3 * Copyright (C) 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/filesystems/mup/mup.c
23 * PURPOSE: Multi UNC Provider
24 * PROGRAMMER: Eric Kohl
25 * Pierre Schweitzer (pierre@reactos.org)
28 /* INCLUDES *****************************************************************/
38 PDRIVER_OBJECT DriverObject
,
39 PUNICODE_STRING RegistryPath
44 PDRIVER_OBJECT DriverObject
,
45 PUNICODE_STRING RegistryPath
58 #if defined(ALLOC_PRAGMA)
59 #pragma alloc_text(INIT, DriverEntry)
60 #pragma alloc_text(INIT, DfsDriverEntry)
61 #pragma alloc_text(INIT, MupInitializeData)
62 #pragma alloc_text(INIT, MupInitializeVcb)
65 ERESOURCE MupGlobalLock
;
66 ERESOURCE MupPrefixTableLock
;
67 ERESOURCE MupCcbListLock
;
69 LIST_ENTRY MupProviderList
;
70 LIST_ENTRY MupPrefixList
;
71 LIST_ENTRY MupMasterQueryList
;
72 UNICODE_PREFIX_TABLE MupPrefixTable
;
73 LARGE_INTEGER MupKnownPrefixTimeout
;
74 ULONG MupProviderCount
;
75 BOOLEAN MupOrderInitialized
;
77 PDEVICE_OBJECT mupDeviceObject
;
78 NTSTATUS MupOrderedErrorList
[] = { STATUS_UNSUCCESSFUL
,
79 STATUS_INVALID_PARAMETER
,
80 STATUS_REDIRECTOR_NOT_STARTED
,
81 STATUS_BAD_NETWORK_NAME
,
82 STATUS_BAD_NETWORK_PATH
, 0 };
84 /* FUNCTIONS ****************************************************************/
88 MupInitializeData(VOID
)
90 ExInitializeResourceLite(&MupGlobalLock
);
91 ExInitializeResourceLite(&MupPrefixTableLock
);
92 ExInitializeResourceLite(&MupCcbListLock
);
93 ExInitializeResourceLite(&MupVcbLock
);
95 InitializeListHead(&MupProviderList
);
96 InitializeListHead(&MupPrefixList
);
97 InitializeListHead(&MupMasterQueryList
);
98 RtlInitializeUnicodePrefix(&MupPrefixTable
);
99 MupKnownPrefixTimeout
.QuadPart
= 9000000000LL;
100 MupOrderInitialized
= FALSE
;
104 MupUninitializeData()
106 ExDeleteResourceLite(&MupGlobalLock
);
107 ExDeleteResourceLite(&MupPrefixTableLock
);
108 ExDeleteResourceLite(&MupCcbListLock
);
109 ExDeleteResourceLite(&MupVcbLock
);
114 MupInitializeVcb(PMUP_VCB Vcb
)
116 RtlZeroMemory(Vcb
, sizeof(MUP_VCB
));
117 Vcb
->NodeType
= NODE_TYPE_VCB
;
118 Vcb
->NodeStatus
= NODE_STATUS_HEALTHY
;
119 Vcb
->NodeReferences
= 1;
120 Vcb
->NodeSize
= sizeof(MUP_VCB
);
124 MuppIsDfsEnabled(VOID
)
129 UNICODE_STRING KeyName
;
130 OBJECT_ATTRIBUTES ObjectAttributes
;
133 KEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
137 /* You recognize FsRtlpIsDfsEnabled()! Congratz :-) */
138 KeyName
.Buffer
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup";
139 KeyName
.Length
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup") - sizeof(UNICODE_NULL
);
140 KeyName
.MaximumLength
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
142 /* Simply query registry to know whether we have to disable DFS.
143 * Unless explicitely stated in registry, we will try to enable DFS.
145 InitializeObjectAttributes(&ObjectAttributes
,
147 OBJ_CASE_INSENSITIVE
,
151 Status
= ZwOpenKey(&Key
, KEY_READ
, &ObjectAttributes
);
152 if (!NT_SUCCESS(Status
))
157 KeyName
.Buffer
= L
"DisableDfs";
158 KeyName
.Length
= sizeof(L
"DisableDfs") - sizeof(UNICODE_NULL
);
159 KeyName
.MaximumLength
= sizeof(L
"DisableDfs");
161 Status
= ZwQueryValueKey(Key
, &KeyName
, KeyValuePartialInformation
, &KeyQueryOutput
, sizeof(KeyQueryOutput
), &Length
);
163 if (!NT_SUCCESS(Status
) || KeyQueryOutput
.KeyInfo
.Type
!= REG_DWORD
)
168 return ((ULONG
)KeyQueryOutput
.KeyInfo
.Data
!= 1);
172 MupCalculateTimeout(PLARGE_INTEGER EntryTime
)
174 LARGE_INTEGER CurrentTime
;
176 /* Just get now + our allowed timeout */
177 KeQuerySystemTime(&CurrentTime
);
178 EntryTime
->QuadPart
= CurrentTime
.QuadPart
+ MupKnownPrefixTimeout
.QuadPart
;
186 Ccb
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_CCB
), TAG_MUP
);
192 Ccb
->NodeStatus
= NODE_STATUS_HEALTHY
;
193 Ccb
->NodeReferences
= 1;
194 Ccb
->NodeType
= NODE_TYPE_CCB
;
195 Ccb
->NodeSize
= sizeof(MUP_CCB
);
205 Fcb
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_FCB
), TAG_MUP
);
211 Fcb
->NodeStatus
= NODE_STATUS_HEALTHY
;
212 Fcb
->NodeReferences
= 1;
213 Fcb
->NodeType
= NODE_TYPE_FCB
;
214 Fcb
->NodeSize
= sizeof(MUP_FCB
);
215 InitializeListHead(&Fcb
->CcbList
);
221 MupAllocateMasterIoContext(VOID
)
223 PMUP_MIC MasterIoContext
;
225 MasterIoContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MUP_MIC
), TAG_MUP
);
226 if (MasterIoContext
== NULL
)
231 MasterIoContext
->NodeStatus
= NODE_STATUS_HEALTHY
;
232 MasterIoContext
->NodeReferences
= 1;
233 MasterIoContext
->NodeType
= NODE_TYPE_MIC
;
234 MasterIoContext
->NodeSize
= sizeof(MUP_MIC
);
236 return MasterIoContext
;
240 MupAllocateUncProvider(ULONG RedirectorDeviceNameLength
)
242 PMUP_UNC UncProvider
;
244 UncProvider
= ExAllocatePoolWithTag(PagedPool
, sizeof(MUP_UNC
) + RedirectorDeviceNameLength
, TAG_MUP
);
245 if (UncProvider
== NULL
)
250 UncProvider
->NodeReferences
= 0;
251 UncProvider
->NodeType
= NODE_TYPE_UNC
;
252 UncProvider
->NodeStatus
= NODE_STATUS_HEALTHY
;
253 UncProvider
->NodeSize
= sizeof(MUP_UNC
) + RedirectorDeviceNameLength
;
254 UncProvider
->Registered
= FALSE
;
260 MupAllocatePrefixEntry(ULONG PrefixLength
)
265 PrefixSize
= sizeof(MUP_PFX
) + PrefixLength
;
266 Prefix
= ExAllocatePoolWithTag(PagedPool
, PrefixSize
, TAG_MUP
);
272 RtlZeroMemory(Prefix
, PrefixSize
);
273 Prefix
->NodeType
= NODE_TYPE_PFX
;
274 Prefix
->NodeStatus
= NODE_STATUS_HEALTHY
;
275 Prefix
->NodeReferences
= 1;
276 Prefix
->NodeSize
= PrefixSize
;
278 /* If we got a prefix, initialize the string */
279 if (PrefixLength
!= 0)
281 Prefix
->AcceptedPrefix
.Buffer
= (PVOID
)((ULONG_PTR
)Prefix
+ sizeof(MUP_PFX
));
282 Prefix
->AcceptedPrefix
.Length
= PrefixLength
;
283 Prefix
->AcceptedPrefix
.MaximumLength
= PrefixLength
;
285 /* Otherwise, mark the fact that the allocation will be external */
288 Prefix
->ExternalAlloc
= TRUE
;
291 Prefix
->KeepExtraRef
= FALSE
;
292 /* Already init timeout to have one */
293 MupCalculateTimeout(&Prefix
->ValidityTimeout
);
299 MupAllocateMasterQueryContext(VOID
)
301 PMUP_MQC MasterQueryContext
;
303 MasterQueryContext
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MUP_MQC
), TAG_MUP
);
304 if (MasterQueryContext
== NULL
)
309 MasterQueryContext
->NodeStatus
= NODE_STATUS_HEALTHY
;
310 MasterQueryContext
->NodeReferences
= 1;
311 MasterQueryContext
->NodeType
= NODE_TYPE_MQC
;
312 MasterQueryContext
->NodeSize
= sizeof(MUP_MQC
);
313 InitializeListHead(&MasterQueryContext
->QueryPathList
);
314 InitializeListHead(&MasterQueryContext
->MQCListEntry
);
315 ExInitializeResourceLite(&MasterQueryContext
->QueryPathListLock
);
317 return MasterQueryContext
;
321 MupDecodeFileObject(PFILE_OBJECT FileObject
, PMUP_FCB
* pFcb
, PMUP_CCB
* pCcb
)
326 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
327 *pFcb
= FileObject
->FsContext
;
328 *pCcb
= FileObject
->FsContext2
;
333 ExReleaseResourceLite(&MupGlobalLock
);
337 Type
= Fcb
->NodeType
;
338 if ((Type
!= NODE_TYPE_VCB
&& Type
!= NODE_TYPE_FCB
) || (Fcb
->NodeStatus
!= NODE_STATUS_HEALTHY
&& Fcb
->NodeStatus
!= NODE_STATUS_CLEANUP
))
341 ExReleaseResourceLite(&MupGlobalLock
);
345 ++Fcb
->NodeReferences
;
346 ExReleaseResourceLite(&MupGlobalLock
);
352 MupFreeNode(PVOID Node
)
354 ExFreePoolWithTag(Node
, TAG_MUP
);
358 MupDereferenceFcb(PMUP_FCB Fcb
)
360 /* Just dereference and delete if no references left */
361 if (InterlockedDecrement(&Fcb
->NodeReferences
) == 0)
368 MupDereferenceCcb(PMUP_CCB Ccb
)
370 /* Just dereference and delete (and clean) if no references left */
371 if (InterlockedDecrement(&Ccb
->NodeReferences
) == 0)
373 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
374 RemoveEntryList(&Ccb
->CcbListEntry
);
375 ExReleaseResourceLite(&MupCcbListLock
);
376 ObDereferenceObject(Ccb
->FileObject
);
377 MupDereferenceFcb(Ccb
->Fcb
);
383 MupDereferenceVcb(PMUP_VCB Vcb
)
385 /* We cannot reach the point where no references are left */
386 if (InterlockedDecrement(&Vcb
->NodeReferences
) == 0)
388 KeBugCheckEx(FILE_SYSTEM
, 3, 0, 0, 0);
393 MupDereferenceMasterIoContext(PMUP_MIC MasterIoContext
,
398 PIO_STACK_LOCATION Stack
;
400 Status
= STATUS_SUCCESS
;
402 if (NewStatus
!= NULL
)
404 /* Save last status, depending on whether it failed or not */
405 if (!NT_SUCCESS(*NewStatus
))
407 MasterIoContext
->LastFailed
= *NewStatus
;
411 MasterIoContext
->LastSuccess
= STATUS_SUCCESS
;
415 if (InterlockedDecrement(&MasterIoContext
->NodeReferences
) != 0)
417 return STATUS_PENDING
;
420 Irp
= MasterIoContext
->Irp
;
421 Stack
= IoGetCurrentIrpStackLocation(Irp
);
422 if (Stack
->MajorFunction
== IRP_MJ_WRITE
)
424 Irp
->IoStatus
.Information
= Stack
->Parameters
.Write
.Length
;
428 Irp
->IoStatus
.Information
= 0;
431 /* In case we never had any success (init is a failure), get the last failed status */
432 if (!NT_SUCCESS(MasterIoContext
->LastSuccess
))
434 Status
= MasterIoContext
->LastFailed
;
437 Irp
->IoStatus
.Status
= Status
;
438 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
439 MupDereferenceFcb(MasterIoContext
->Fcb
);
440 MupFreeNode(MasterIoContext
);
446 MupDereferenceUncProvider(PMUP_UNC UncProvider
)
448 InterlockedExchangeAdd(&UncProvider
->NodeReferences
, -1);
452 MupDereferenceKnownPrefix(PMUP_PFX Prefix
)
454 /* Just dereference and delete (and clean) if no references left */
455 if (InterlockedDecrement(&Prefix
->NodeReferences
) == 0)
459 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
460 RemoveEntryList(&Prefix
->PrefixListEntry
);
463 if (Prefix
->ExternalAlloc
&& Prefix
->AcceptedPrefix
.Buffer
!= NULL
)
465 ExFreePoolWithTag(Prefix
->AcceptedPrefix
.Buffer
, TAG_MUP
);
468 if (Prefix
->UncProvider
)
470 MupDereferenceUncProvider(Prefix
->UncProvider
);
478 MupRemoveKnownPrefixEntry(PMUP_PFX Prefix
)
480 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
481 RemoveEntryList(&Prefix
->PrefixListEntry
);
482 Prefix
->InTable
= FALSE
;
483 MupDereferenceKnownPrefix(Prefix
);
487 MupInvalidatePrefixTable(VOID
)
492 /* Browse the prefix table */
493 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
494 for (Entry
= MupPrefixList
.Flink
;
495 Entry
!= &MupPrefixList
;
496 Entry
= Entry
->Flink
)
498 Prefix
= CONTAINING_RECORD(Entry
, MUP_PFX
, PrefixListEntry
);
500 /* And remove any entry in it */
503 MupRemoveKnownPrefixEntry(Prefix
);
506 ExReleaseResourceLite(&MupPrefixTableLock
);
510 MupCleanupVcb(PDEVICE_OBJECT DeviceObject
,
514 ExAcquireResourceExclusiveLite(&MupVcbLock
, TRUE
);
516 /* Check we're not doing anything wrong first */
517 if (Vcb
->NodeStatus
!= NODE_STATUS_HEALTHY
|| Vcb
->NodeType
!= NODE_TYPE_VCB
)
519 ExRaiseStatus(STATUS_INVALID_HANDLE
);
522 /* Remove share access */
523 IoRemoveShareAccess(IoGetCurrentIrpStackLocation(Irp
)->FileObject
, &Vcb
->ShareAccess
);
525 ExReleaseResourceLite(&MupVcbLock
);
529 MupCleanupFcb(PDEVICE_OBJECT DeviceObject
,
536 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
537 /* Check we're not doing anything wrong first */
538 if (Fcb
->NodeStatus
!= NODE_STATUS_HEALTHY
|| Fcb
->NodeType
!= NODE_TYPE_FCB
)
540 ExRaiseStatus(STATUS_INVALID_HANDLE
);
542 Fcb
->NodeStatus
= NODE_STATUS_CLEANUP
;
543 ExReleaseResourceLite(&MupGlobalLock
);
545 /* Dereference any CCB associated with the FCB */
546 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
547 for (Entry
= Fcb
->CcbList
.Flink
;
548 Entry
!= &Fcb
->CcbList
;
549 Entry
= Entry
->Flink
)
551 Ccb
= CONTAINING_RECORD(Entry
, MUP_CCB
, CcbListEntry
);
552 ExReleaseResourceLite(&MupCcbListLock
);
553 MupDereferenceCcb(Ccb
);
554 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
556 ExReleaseResourceLite(&MupCcbListLock
);
560 CommonForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
562 PFORWARDED_IO_CONTEXT FwdCtxt
)
566 Status
= Irp
->IoStatus
.Status
;
568 /* Just free everything we had allocated */
569 if (Irp
->MdlAddress
!= NULL
)
571 MmUnlockPages(Irp
->MdlAddress
);
572 IoFreeMdl(Irp
->MdlAddress
);
575 if (Irp
->Flags
& IRP_DEALLOCATE_BUFFER
)
577 ExFreePoolWithTag(Irp
->AssociatedIrp
.SystemBuffer
, TAG_MUP
);
582 /* Dereference the master context
583 * The upper IRP will be completed once all the lower IRPs are done
584 * (and thus, references count reaches 0)
586 MupDereferenceCcb(FwdCtxt
->Ccb
);
587 MupDereferenceMasterIoContext(FwdCtxt
->MasterIoContext
, &Status
);
588 ExFreePoolWithTag(FwdCtxt
, TAG_MUP
);
590 return STATUS_MORE_PROCESSING_REQUIRED
;
595 DeferredForwardedIoCompletionRoutine(PVOID Context
)
597 PFORWARDED_IO_CONTEXT FwdCtxt
= (PFORWARDED_IO_CONTEXT
)Context
;
599 CommonForwardedIoCompletionRoutine(FwdCtxt
->DeviceObject
, FwdCtxt
->Irp
, Context
);
604 ForwardedIoCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
608 PFORWARDED_IO_CONTEXT FwdCtxt
;
610 /* If we're at DISPATCH_LEVEL, we cannot complete, defer completion */
611 if (KeGetCurrentIrql() < DISPATCH_LEVEL
)
613 CommonForwardedIoCompletionRoutine(DeviceObject
, Irp
, Context
);
617 FwdCtxt
= (PFORWARDED_IO_CONTEXT
)Context
;
619 ExInitializeWorkItem(&FwdCtxt
->WorkQueueItem
, DeferredForwardedIoCompletionRoutine
, Context
);
620 ExQueueWorkItem(&FwdCtxt
->WorkQueueItem
, CriticalWorkQueue
);
623 return STATUS_MORE_PROCESSING_REQUIRED
;
627 BuildAndSubmitIrp(PIRP Irp
,
629 PMUP_MIC MasterIoContext
)
634 PIO_STACK_LOCATION Stack
;
635 PDEVICE_OBJECT DeviceObject
;
636 PFORWARDED_IO_CONTEXT FwdCtxt
;
638 Status
= STATUS_SUCCESS
;
642 /* Allocate a context for the completion routine */
643 FwdCtxt
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(FORWARDED_IO_CONTEXT
), TAG_MUP
);
646 Status
= STATUS_INSUFFICIENT_RESOURCES
;
651 FwdCtxt
->DeviceObject
= NULL
;
654 /* Allocate the IRP */
655 DeviceObject
= IoGetRelatedDeviceObject(Ccb
->FileObject
);
656 LowerIrp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
657 if (LowerIrp
== NULL
)
659 Status
= STATUS_INSUFFICIENT_RESOURCES
;
664 LowerIrp
->Tail
.Overlay
.OriginalFileObject
= Ccb
->FileObject
;
665 LowerIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
666 LowerIrp
->RequestorMode
= KernelMode
;
668 /* Copy the stack of the request we received to the IRP we'll pass below */
669 Stack
= IoGetNextIrpStackLocation(LowerIrp
);
670 RtlMoveMemory(Stack
, IoGetCurrentIrpStackLocation(Irp
), sizeof(IO_STACK_LOCATION
));
671 Stack
->FileObject
= Ccb
->FileObject
;
672 /* Setup flags according to the FO */
673 if (Ccb
->FileObject
->Flags
& FO_WRITE_THROUGH
)
675 Stack
->Flags
= SL_WRITE_THROUGH
;
680 /* Does the device requires we do buffered IOs? */
681 if (DeviceObject
->Flags
& DO_BUFFERED_IO
)
683 LowerIrp
->AssociatedIrp
.SystemBuffer
= NULL
;
685 if (Stack
->Parameters
.Write
.Length
== 0)
687 LowerIrp
->Flags
= IRP_BUFFERED_IO
;
689 /* If we have data to pass */
692 /* If it's coming from usermode, probe first */
693 if (Irp
->RequestorMode
== UserMode
)
695 ProbeForRead(Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
, sizeof(UCHAR
));
698 /* Allocate the buffer */
699 LowerIrp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithQuotaTag(PagedPoolCacheAligned
,
700 Stack
->Parameters
.Write
.Length
,
702 if (LowerIrp
->AssociatedIrp
.SystemBuffer
== NULL
)
704 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
707 /* And copy input (remember, we've to free!) */
708 RtlMoveMemory(LowerIrp
->AssociatedIrp
.SystemBuffer
, Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
);
709 LowerIrp
->Flags
= IRP_BUFFERED_IO
| IRP_DEALLOCATE_BUFFER
;
714 if (!(DeviceObject
->Flags
& DO_DIRECT_IO
))
716 LowerIrp
->UserBuffer
= Irp
->UserBuffer
;
720 /* For direct IOs, allocate an MDL and pass it */
721 if (Stack
->Parameters
.Write
.Length
!= 0)
723 Mdl
= IoAllocateMdl(Irp
->UserBuffer
, Stack
->Parameters
.Write
.Length
, FALSE
, TRUE
, LowerIrp
);
726 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
729 MmProbeAndLockPages(Mdl
, Irp
->RequestorMode
, IoReadAccess
);
734 /* Fix flags in the IRP */
735 if (Ccb
->FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
)
737 LowerIrp
->Flags
|= IRP_WRITE_OPERATION
| IRP_NOCACHE
;
741 LowerIrp
->Flags
|= IRP_WRITE_OPERATION
;
745 FwdCtxt
->MasterIoContext
= MasterIoContext
;
747 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
748 ++MasterIoContext
->NodeReferences
;
749 ExReleaseResourceLite(&MupGlobalLock
);
751 /* Set out completion routine */
752 IoSetCompletionRoutine(LowerIrp
, ForwardedIoCompletionRoutine
, FwdCtxt
, TRUE
, TRUE
, TRUE
);
753 /* And call the device with our brand new IRP */
754 Status
= IoCallDriver(Ccb
->DeviceObject
, LowerIrp
);
756 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
758 Status
= _SEH2_GetExceptionCode();
763 if (!NT_SUCCESS(Status
))
767 ExFreePoolWithTag(FwdCtxt
, TAG_MUP
);
770 if (LowerIrp
!= NULL
)
772 if (LowerIrp
->AssociatedIrp
.SystemBuffer
== NULL
)
774 ExFreePoolWithTag(LowerIrp
->AssociatedIrp
.SystemBuffer
, TAG_MUP
);
791 DfsVolumePassThrough(PDEVICE_OBJECT DeviceObject
,
794 return STATUS_NOT_IMPLEMENTED
;
799 MupForwardIoRequest(PDEVICE_OBJECT DeviceObject
,
807 BOOLEAN CcbLockAcquired
;
808 PMUP_MIC MasterIoContext
;
809 PIO_STACK_LOCATION Stack
;
811 /* If DFS is enabled, check if that's for DFS and is so relay */
812 if (MupEnableDfs
&& DeviceObject
->DeviceType
== FILE_DEVICE_DFS
)
814 return DfsVolumePassThrough(DeviceObject
, Irp
);
817 Stack
= IoGetCurrentIrpStackLocation(Irp
);
819 FsRtlEnterFileSystem();
821 /* Write request is only possible for a mailslot, we need a FCB */
822 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
823 if (Fcb
== NULL
|| Fcb
->NodeType
!= NODE_TYPE_FCB
)
825 FsRtlExitFileSystem();
826 Status
= STATUS_INVALID_DEVICE_REQUEST
;
830 /* Allocate a context */
831 MasterIoContext
= MupAllocateMasterIoContext();
832 if (MasterIoContext
== NULL
)
834 FsRtlExitFileSystem();
835 Status
= STATUS_INSUFFICIENT_RESOURCES
;
839 /* Mark the IRP pending and init the context */
840 IoMarkIrpPending(Irp
);
841 MasterIoContext
->Irp
= Irp
;
842 /* Init with a failure to catch if we ever succeed */
843 MasterIoContext
->LastSuccess
= STATUS_UNSUCCESSFUL
;
844 /* Init with the worth failure possible */
845 MasterIoContext
->LastFailed
= STATUS_BAD_NETWORK_PATH
;
846 MasterIoContext
->Fcb
= Fcb
;
850 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
851 CcbLockAcquired
= TRUE
;
853 /* For all the CCB (ie, the mailslots) we have */
854 for (Entry
= Fcb
->CcbList
.Flink
;
855 Entry
!= &Fcb
->CcbList
;
856 Entry
= Entry
->Flink
)
858 FcbListCcb
= CONTAINING_RECORD(Entry
, MUP_CCB
, CcbListEntry
);
859 ExReleaseResourceLite(&MupCcbListLock
);
860 CcbLockAcquired
= FALSE
;
862 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
863 ++FcbListCcb
->NodeReferences
;
864 ExReleaseResourceLite(&MupGlobalLock
);
866 /* Forward the write request */
867 BuildAndSubmitIrp(Irp
, FcbListCcb
, MasterIoContext
);
868 ExAcquireResourceExclusiveLite(&MupCcbListLock
, TRUE
);
869 CcbLockAcquired
= TRUE
;
872 ExReleaseResourceLite(&MupCcbListLock
);
873 CcbLockAcquired
= FALSE
;
875 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
879 ExReleaseResourceLite(&MupCcbListLock
);
885 MupDereferenceMasterIoContext(MasterIoContext
, NULL
);
886 FsRtlExitFileSystem();
888 return STATUS_PENDING
;
892 Irp
->IoStatus
.Status
= Status
;
893 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
898 AddUnregisteredProvider(PCWSTR DeviceName
,
901 PMUP_UNC UncProvider
;
902 ULONG StrLen
, NameLen
;
904 /* Just allocate the node */
905 NameLen
= wcslen(DeviceName
);
906 StrLen
= NameLen
* sizeof(WCHAR
);
907 UncProvider
= MupAllocateUncProvider(StrLen
);
908 if (UncProvider
== NULL
)
914 UncProvider
->DeviceName
.MaximumLength
= StrLen
;
915 UncProvider
->DeviceName
.Length
= StrLen
;
916 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
917 UncProvider
->ProviderOrder
= ProviderOrder
;
918 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, DeviceName
, StrLen
);
920 /* And add it to the global list
921 * We're using tail here so that when called from registry init,
922 * the providers with highest priority will be in the head of
925 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
926 InsertTailList(&MupProviderList
, &UncProvider
->ProviderListEntry
);
927 ExReleaseResourceLite(&MupGlobalLock
);
933 InitializeProvider(PCWSTR ProviderName
,
938 UNICODE_STRING Key
, Value
;
939 PKEY_VALUE_FULL_INFORMATION Info
;
940 OBJECT_ATTRIBUTES ObjectAttributes
;
941 ULONG NameLen
, StrLen
, ResultLength
;
943 /* Get the information about the provider from registry */
944 NameLen
= wcslen(ProviderName
);
945 StrLen
= NameLen
* sizeof(WCHAR
) + sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") + sizeof(L
"\\NetworkProvider");
946 Key
.Buffer
= ExAllocatePoolWithTag(PagedPool
, StrLen
, TAG_MUP
);
947 if (Key
.Buffer
== NULL
)
952 RtlMoveMemory(Key
.Buffer
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\", sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"));
953 Key
.MaximumLength
= StrLen
;
954 Key
.Length
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\") - sizeof(UNICODE_NULL
);
955 RtlAppendUnicodeToString(&Key
, ProviderName
);
956 RtlAppendUnicodeToString(&Key
, L
"\\NetworkProvider");
958 InitializeObjectAttributes(&ObjectAttributes
,
960 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
963 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
964 ExFreePoolWithTag(Key
.Buffer
, TAG_MUP
);
965 if (!NT_SUCCESS(Status
))
970 RtlInitUnicodeString(&Value
, L
"DeviceName");
971 Status
= ZwQueryValueKey(KeyHandle
, &Value
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
972 if (Status
== STATUS_BUFFER_TOO_SMALL
)
974 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
981 Status
= ZwQueryValueKey(KeyHandle
, &Value
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
990 /* And create the provider
991 * It will remain unregistered until FsRTL receives a registration request and forwards
994 if (NT_SUCCESS(Status
))
996 ASSERT(Info
!= NULL
);
997 AddUnregisteredProvider((PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
), ProviderOrder
);
1002 ExFreePoolWithTag(Info
, TAG_MUP
);
1007 MupGetProviderInformation(VOID
)
1012 PWSTR Providers
, Coma
;
1013 PKEY_VALUE_FULL_INFORMATION Info
;
1014 ULONG ResultLength
, ProviderCount
;
1015 OBJECT_ATTRIBUTES ObjectAttributes
;
1016 UNICODE_STRING NetworkProvider
, ProviderOrder
;
1018 /* Open the registry to get the order of the providers */
1019 RtlInitUnicodeString(&NetworkProvider
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
1020 InitializeObjectAttributes(&ObjectAttributes
,
1022 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1025 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
1026 if (!NT_SUCCESS(Status
))
1031 RtlInitUnicodeString(&ProviderOrder
, L
"ProviderOrder");
1032 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
1033 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1035 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
1042 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
1051 if (NT_SUCCESS(Status
))
1053 ASSERT(Info
!= NULL
);
1055 Providers
= (PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
);
1059 /* For all the providers we got (coma-separated list), just create a provider node with the right order
1060 * The order is just the order of the list
1061 * First has highest priority (0) and then, get lower and lower priority
1062 * The highest number is the lowest priority
1066 Coma
= wcschr(Providers
, L
',');
1069 *Coma
= UNICODE_NULL
;
1076 InitializeProvider(Providers
, ProviderCount
);
1079 Providers
= Coma
+ 1;
1085 ExFreePoolWithTag(Info
, TAG_MUP
);
1090 MupCheckForUnregisteredProvider(PUNICODE_STRING RedirectorDeviceName
)
1093 PMUP_UNC UncProvider
;
1095 /* Browse the list of all the providers nodes we have */
1096 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1097 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1099 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1101 /* If one matches the device and is not registered, that's ours! */
1102 if (!UncProvider
->Registered
&& RtlEqualUnicodeString(RedirectorDeviceName
, &UncProvider
->DeviceName
, TRUE
))
1104 UncProvider
->NodeStatus
= NODE_STATUS_HEALTHY
;
1109 if (Entry
== &MupProviderList
)
1113 ExReleaseResourceLite(&MupGlobalLock
);
1119 RegisterUncProvider(PDEVICE_OBJECT DeviceObject
,
1128 PIO_STACK_LOCATION Stack
;
1129 IO_STATUS_BLOCK IoStatusBlock
;
1130 PMUP_UNC UncProvider
, ListEntry
;
1131 OBJECT_ATTRIBUTES ObjectAttributes
;
1132 UNICODE_STRING RedirectorDeviceName
;
1133 OBJECT_HANDLE_INFORMATION HandleInfo
;
1134 PMUP_PROVIDER_REGISTRATION_INFO RegInfo
;
1136 DPRINT1("RegisterUncProvider(%p, %p)\n", DeviceObject
, Irp
);
1139 /* Check whether providers order was already initialized */
1140 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1141 if (MupOrderInitialized
)
1143 ExReleaseResourceLite(&MupGlobalLock
);
1147 /* They weren't, so do it */
1148 MupOrderInitialized
= TRUE
;
1149 ExReleaseResourceLite(&MupGlobalLock
);
1150 MupGetProviderInformation();
1153 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1155 /* This can only happen with a volume open */
1156 if (MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
) != NODE_TYPE_VCB
)
1158 Irp
->IoStatus
.Status
= STATUS_INVALID_HANDLE
;
1159 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1161 return STATUS_INVALID_HANDLE
;
1164 /* Get the registration information */
1165 RegInfo
= (PMUP_PROVIDER_REGISTRATION_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
1168 RedirectorDeviceName
.Length
= RegInfo
->RedirectorDeviceNameLength
;
1169 RedirectorDeviceName
.MaximumLength
= RedirectorDeviceName
.Length
;
1170 RedirectorDeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
);
1172 /* Have we got already a node for it? (Like from previous init) */
1173 UncProvider
= MupCheckForUnregisteredProvider(&RedirectorDeviceName
);
1174 if (UncProvider
== NULL
)
1176 /* If we don't, allocate a new one */
1178 UncProvider
= MupAllocateUncProvider(RegInfo
->RedirectorDeviceNameLength
);
1179 if (UncProvider
== NULL
)
1181 Status
= STATUS_INVALID_USER_BUFFER
;
1186 UncProvider
->DeviceName
.Length
= RedirectorDeviceName
.Length
;
1187 UncProvider
->DeviceName
.MaximumLength
= RedirectorDeviceName
.MaximumLength
;
1188 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
1190 /* As it wasn't in registry for order, give the lowest priority possible */
1191 UncProvider
->ProviderOrder
= MAXLONG
;
1192 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
), RegInfo
->RedirectorDeviceNameLength
);
1195 /* Continue registration */
1196 UncProvider
->MailslotsSupported
= RegInfo
->MailslotsSupported
;
1197 ++UncProvider
->NodeReferences
;
1199 /* Open a handle to the device */
1200 InitializeObjectAttributes(&ObjectAttributes
,
1201 &UncProvider
->DeviceName
,
1202 OBJ_CASE_INSENSITIVE
,
1205 Status
= NtOpenFile(&UncProvider
->DeviceHandle
,
1209 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1210 FILE_DIRECTORY_FILE
);
1211 if (NT_SUCCESS(Status
))
1213 Status
= IoStatusBlock
.Status
;
1216 /* And return the provider (as CCB) */
1217 if (NT_SUCCESS(Status
))
1219 Stack
->FileObject
->FsContext2
= UncProvider
;
1220 Status
= ObReferenceObjectByHandle(UncProvider
->DeviceHandle
, 0, NULL
, KernelMode
, (PVOID
*)&UncProvider
->FileObject
, &HandleInfo
);
1221 if (!NT_SUCCESS(Status
))
1223 NtClose(UncProvider
->DeviceHandle
);
1227 if (!NT_SUCCESS(Status
))
1229 MupDereferenceUncProvider(UncProvider
);
1233 UncProvider
->DeviceObject
= IoGetRelatedDeviceObject(UncProvider
->FileObject
);
1235 /* Now, insert the provider in our global list
1236 * They are sorted by order
1238 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1242 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1244 ListEntry
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1246 if (UncProvider
->ProviderOrder
< ListEntry
->ProviderOrder
)
1252 InsertTailList(Entry
, &UncProvider
->ProviderListEntry
);
1254 UncProvider
->Registered
= TRUE
;
1255 ExReleaseResourceLite(&MupGlobalLock
);
1256 Status
= STATUS_SUCCESS
;
1258 DPRINT1("UNC provider %wZ registered\n", &UncProvider
->DeviceName
);
1263 if (_abnormal_termination())
1265 Status
= STATUS_INVALID_USER_BUFFER
;
1268 MupDereferenceVcb((PMUP_VCB
)Fcb
);
1270 Irp
->IoStatus
.Status
= Status
;
1271 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1279 DfsFsdFileSystemControl(PDEVICE_OBJECT DeviceObject
,
1282 return STATUS_NOT_IMPLEMENTED
;
1287 MupFsControl(PDEVICE_OBJECT DeviceObject
,
1291 PIO_STACK_LOCATION Stack
;
1293 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1297 /* MUP only understands a single FSCTL code: registering UNC provider */
1298 if (Stack
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_MUP_REGISTER_PROVIDER
)
1300 /* It obviously has to come from a driver/kernelmode thread */
1301 if (Irp
->RequestorMode
== UserMode
)
1303 Status
= STATUS_ACCESS_DENIED
;
1305 Irp
->IoStatus
.Status
= Status
;
1306 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1311 Status
= RegisterUncProvider(DeviceObject
, Irp
);
1315 /* If that's an unknown FSCTL code, maybe it's for DFS, pass it */
1318 Status
= STATUS_INVALID_PARAMETER
;
1320 Irp
->IoStatus
.Status
= Status
;
1321 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1326 Status
= DfsFsdFileSystemControl(DeviceObject
, Irp
);
1329 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1331 Status
= _SEH2_GetExceptionCode();
1339 MupSetFileObject(PFILE_OBJECT FileObject
,
1343 FileObject
->FsContext
= Fcb
;
1344 FileObject
->FsContext2
= Ccb
;
1348 MupRerouteOpen(PFILE_OBJECT FileObject
,
1349 PMUP_UNC UncProvider
)
1354 DPRINT1("Rerouting %wZ with %wZ\n", &FileObject
->FileName
, &UncProvider
->DeviceName
);
1356 /* Get the full path name (device name first, and requested file name appended) */
1357 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1358 if (TotalLength
> MAXUSHORT
)
1360 return STATUS_NAME_TOO_LONG
;
1363 /* Allocate a buffer big enough */
1364 FullPath
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1365 if (FullPath
== NULL
)
1367 return STATUS_INSUFFICIENT_RESOURCES
;
1370 /* Create the full path */
1371 RtlMoveMemory(FullPath
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1372 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
+ UncProvider
->DeviceName
.Length
), FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
1374 /* And redo the path in the file oject */
1375 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
1376 FileObject
->FileName
.Buffer
= FullPath
;
1377 FileObject
->FileName
.MaximumLength
= TotalLength
;
1378 FileObject
->FileName
.Length
= FileObject
->FileName
.MaximumLength
;
1380 /* Ob, please reparse to open the correct file at the right place, thanks! :-) */
1381 return STATUS_REPARSE
;
1385 BroadcastOpen(PIRP Irp
)
1390 PMUP_CCB Ccb
= NULL
;
1391 PMUP_UNC UncProvider
;
1392 UNICODE_STRING FullPath
;
1393 PFILE_OBJECT FileObject
;
1394 PIO_STACK_LOCATION Stack
;
1395 NTSTATUS Status
, LastFailed
;
1396 ULONG TotalLength
, LastOrder
;
1397 IO_STATUS_BLOCK IoStatusBlock
;
1398 OBJECT_ATTRIBUTES ObjectAttributes
;
1399 OBJECT_HANDLE_INFORMATION HandleInfo
;
1400 BOOLEAN Locked
, Referenced
, CcbInitialized
;
1402 Fcb
= MupCreateFcb();
1405 return STATUS_INSUFFICIENT_RESOURCES
;
1408 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1409 FileObject
= Stack
->FileObject
;
1412 CcbInitialized
= FALSE
;
1413 LastFailed
= STATUS_NO_SUCH_FILE
;
1414 LastOrder
= (ULONG
)-1;
1418 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1421 /* Associate our FCB with the FO */
1422 MupSetFileObject(FileObject
, Fcb
, NULL
);
1423 Fcb
->FileObject
= FileObject
;
1425 /* Now, broadcast the open to any UNC provider that supports mailslots */
1426 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1428 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1429 ++UncProvider
->NodeReferences
;
1432 ExReleaseResourceLite(&MupGlobalLock
);
1435 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1436 if (UncProvider
->MailslotsSupported
&& TotalLength
<= MAXUSHORT
)
1438 /* Provide the correct name for the mailslot (ie, happened the device name of the provider) */
1439 FullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1440 if (FullPath
.Buffer
== NULL
)
1442 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
1445 FullPath
.Length
= TotalLength
;
1446 FullPath
.MaximumLength
= TotalLength
;
1447 RtlMoveMemory(FullPath
.Buffer
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1448 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
.Buffer
+ UncProvider
->DeviceName
.Length
),
1449 FileObject
->FileName
.Buffer
,
1450 FileObject
->FileName
.Length
);
1452 /* And just forward the creation request */
1453 InitializeObjectAttributes(&ObjectAttributes
,
1455 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1458 Status
= IoCreateFile(&Handle
,
1459 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_SIMPLE_RIGHTS_MASK
,
1463 Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
,
1464 Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
,
1466 Stack
->Parameters
.Create
.Options
& FILE_VALID_SET_FLAGS
,
1471 IO_NO_PARAMETER_CHECKING
);
1473 ExFreePoolWithTag(FullPath
.Buffer
, TAG_MUP
);
1475 /* If opening succeed */
1476 if (NT_SUCCESS(Status
))
1478 Status
= IoStatusBlock
.Status
;
1481 Ccb
= MupCreateCcb();
1484 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1487 /* And associated a FO to it */
1488 if (NT_SUCCESS(Status
))
1490 Status
= ObReferenceObjectByHandle(Handle
, 0, 0, 0, (PVOID
*)&Ccb
->FileObject
, &HandleInfo
);
1495 /* If we failed, remember the last failed status of the higher priority provider */
1496 if (!NT_SUCCESS(Status
))
1498 if (UncProvider
->ProviderOrder
<= LastOrder
)
1500 LastOrder
= UncProvider
->ProviderOrder
;
1501 LastFailed
= Status
;
1504 /* Otherwise, properly attach our CCB to the mailslot */
1507 Ccb
->DeviceObject
= IoGetRelatedDeviceObject(Ccb
->FileObject
);
1510 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1512 ++Fcb
->NodeReferences
;
1513 ExReleaseResourceLite(&MupGlobalLock
);
1515 CcbInitialized
= TRUE
;
1517 InsertTailList(&Fcb
->CcbList
, &Ccb
->CcbListEntry
);
1521 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1523 MupDereferenceUncProvider(UncProvider
);
1527 ExReleaseResourceLite(&MupGlobalLock
);
1530 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1532 Status
= _SEH2_GetExceptionCode();
1536 /* If we at least opened one mailslot, return success */
1537 Status
= (CcbInitialized
? STATUS_SUCCESS
: LastFailed
);
1541 MupDereferenceUncProvider(UncProvider
);
1546 ExReleaseResourceLite(&MupGlobalLock
);
1549 /* In case of failure, don't leak CCB */
1550 if (!NT_SUCCESS(Status
) && Ccb
!= NULL
)
1559 MupBuildIoControlRequest(PFILE_OBJECT FileObject
,
1561 ULONG MajorFunction
,
1564 ULONG InputBufferSize
,
1566 ULONG OutputBufferSize
,
1567 PIO_COMPLETION_ROUTINE CompletionRoutine
)
1570 PIO_STACK_LOCATION Stack
;
1571 PDEVICE_OBJECT DeviceObject
;
1573 if (InputBuffer
== NULL
)
1578 /* Get the device object */
1579 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1580 /* Allocate the IRP (with one more location for us */
1581 Irp
= IoAllocateIrp(DeviceObject
->StackSize
+ 1, FALSE
);
1587 /* Skip our location */
1588 IoSetNextIrpStackLocation(Irp
);
1590 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1591 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1592 IoSetCompletionRoutine(Irp
, CompletionRoutine
, Context
, TRUE
, TRUE
, TRUE
);
1594 /* Setup the stack */
1595 Stack
= IoGetNextIrpStackLocation(Irp
);
1596 Stack
->MajorFunction
= MajorFunction
;
1597 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
= OutputBufferSize
;
1598 Stack
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferSize
;
1599 Stack
->Parameters
.DeviceIoControl
.IoControlCode
= IoctlCode
;
1600 Stack
->MinorFunction
= 0;
1601 Stack
->FileObject
= FileObject
;
1602 Stack
->DeviceObject
= DeviceObject
;
1604 switch (IO_METHOD_FROM_CTL_CODE(IoctlCode
))
1606 case METHOD_BUFFERED
:
1607 /* If it's buffered, just pass the buffers we got */
1608 Irp
->MdlAddress
= NULL
;
1609 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1610 Irp
->UserBuffer
= OutputBuffer
;
1611 Irp
->Flags
= IRP_BUFFERED_IO
;
1613 if (OutputBuffer
!= NULL
)
1615 Irp
->Flags
|= IRP_INPUT_OPERATION
;
1619 case METHOD_IN_DIRECT
:
1620 case METHOD_OUT_DIRECT
:
1621 /* Otherwise, allocate an MDL */
1622 if (IoAllocateMdl(InputBuffer
, InputBufferSize
, FALSE
, FALSE
, Irp
) == NULL
)
1628 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1629 Irp
->Flags
= IRP_BUFFERED_IO
;
1630 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, IoReadAccess
);
1633 case METHOD_NEITHER
:
1634 /* Or pass the buffers */
1635 Irp
->UserBuffer
= OutputBuffer
;
1636 Irp
->MdlAddress
= NULL
;
1637 Irp
->AssociatedIrp
.SystemBuffer
= NULL
;
1638 Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
1646 MupFreeMasterQueryContext(PMUP_MQC MasterQueryContext
)
1648 ExDeleteResourceLite(&MasterQueryContext
->QueryPathListLock
);
1649 ExFreePoolWithTag(MasterQueryContext
, TAG_MUP
);
1653 MupDereferenceMasterQueryContext(PMUP_MQC MasterQueryContext
)
1657 BOOLEAN KeepExtraRef
;
1659 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1660 --MasterQueryContext
->NodeReferences
;
1661 References
= MasterQueryContext
->NodeReferences
;
1662 ExReleaseResourceLite(&MupGlobalLock
);
1664 if (References
!= 0)
1666 DPRINT("Still having refs (%ld)\n", References
);
1667 return STATUS_PENDING
;
1670 /* We HAVE an IRP to complete. It cannot be NULL
1671 * Please, help preserving kittens, don't provide NULL IRPs.
1673 if (MasterQueryContext
->Irp
== NULL
)
1675 KeBugCheck(FILE_SYSTEM
);
1678 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1679 RemoveEntryList(&MasterQueryContext
->MQCListEntry
);
1680 ExReleaseResourceLite(&MupGlobalLock
);
1682 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1683 KeepExtraRef
= MasterQueryContext
->Prefix
->KeepExtraRef
;
1684 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1686 /* We found a provider? */
1687 if (MasterQueryContext
->LatestProvider
!= NULL
)
1689 /* With a successful status? */
1690 if (MasterQueryContext
->LatestStatus
== STATUS_SUCCESS
)
1692 /* Then, it's time to reroute, someone accepted to handle the file creation request! */
1695 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1698 ExReleaseResourceLite(&MupPrefixTableLock
);
1699 /* Reroute & complete :-) */
1700 Status
= MupRerouteOpen(MasterQueryContext
->FileObject
, MasterQueryContext
->LatestProvider
);
1705 MupDereferenceUncProvider(MasterQueryContext
->LatestProvider
);
1709 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1710 ExReleaseResourceLite(&MupPrefixTableLock
);
1712 /* Return the highest failed status we had */
1713 Status
= MasterQueryContext
->LatestStatus
;
1716 /* In finally, complete the IRP for real! */
1717 MasterQueryContext
->Irp
->IoStatus
.Status
= Status
;
1718 IoCompleteRequest(MasterQueryContext
->Irp
, IO_DISK_INCREMENT
);
1720 MasterQueryContext
->Irp
= NULL
;
1721 MupFreeMasterQueryContext(MasterQueryContext
);
1728 QueryPathCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
1733 ULONG LatestPos
, Pos
;
1734 PWSTR AcceptedPrefix
;
1735 PMUP_MQC MasterQueryContext
;
1736 NTSTATUS Status
, TableStatus
;
1737 PQUERY_PATH_CONTEXT QueryContext
;
1738 PQUERY_PATH_RESPONSE QueryResponse
;
1740 /* Get all the data from our query to the provider */
1741 QueryContext
= (PQUERY_PATH_CONTEXT
)Context
;
1742 QueryResponse
= (PQUERY_PATH_RESPONSE
)QueryContext
->QueryPathRequest
;
1743 MasterQueryContext
= QueryContext
->MasterQueryContext
;
1744 Status
= Irp
->IoStatus
.Status
;
1746 DPRINT("Reply from %wZ: %u (Status: %lx)\n", &QueryContext
->UncProvider
->DeviceName
, QueryResponse
->LengthAccepted
, Status
);
1748 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
1749 RemoveEntryList(&QueryContext
->QueryPathListEntry
);
1751 /* If the driver returned a success, and an acceptance length */
1752 if (NT_SUCCESS(Status
) && QueryResponse
->LengthAccepted
> 0)
1754 Prefix
= MasterQueryContext
->Prefix
;
1756 /* Check if we already found a provider from a previous iteration */
1757 if (MasterQueryContext
->LatestProvider
!= NULL
)
1759 /* If the current provider has a lower priority (ie, a greater order), then, bailout and keep previous one */
1760 if (QueryContext
->UncProvider
->ProviderOrder
>= MasterQueryContext
->LatestProvider
->ProviderOrder
)
1762 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1766 /* Otherwise, if the prefix was in the prefix table, just drop it:
1767 * we have a provider which superseeds the accepted prefix, so leave
1768 * room for the new prefix/provider
1770 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1771 if (Prefix
->InTable
)
1773 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
1774 RemoveEntryList(&Prefix
->PrefixListEntry
);
1775 Prefix
->InTable
= FALSE
;
1777 ExReleaseResourceLite(&MupPrefixTableLock
);
1779 Prefix
->KeepExtraRef
= FALSE
;
1781 /* Release data associated with the current prefix, if any
1782 * We'll renew them with the new accepted prefix
1784 if (Prefix
->AcceptedPrefix
.Length
!= 0 && Prefix
->AcceptedPrefix
.Buffer
!= NULL
)
1786 ExFreePoolWithTag(Prefix
->AcceptedPrefix
.Buffer
, TAG_MUP
);
1787 Prefix
->AcceptedPrefix
.MaximumLength
= 0;
1788 Prefix
->AcceptedPrefix
.Length
= 0;
1789 Prefix
->AcceptedPrefix
.Buffer
= NULL
;
1790 Prefix
->ExternalAlloc
= FALSE
;
1793 /* If there was also a provider, drop it, the new one
1796 if (Prefix
->UncProvider
!= NULL
)
1798 MupDereferenceUncProvider(Prefix
->UncProvider
);
1799 Prefix
->UncProvider
= NULL
;
1803 /* Now, set our information about the provider that accepted the prefix */
1804 MasterQueryContext
->LatestProvider
= QueryContext
->UncProvider
;
1805 MasterQueryContext
->LatestStatus
= Status
;
1807 if (MasterQueryContext
->FileObject
->FsContext2
!= DFS_MAGIC_CCB
)
1809 /* Allocate a buffer for the prefix */
1810 AcceptedPrefix
= ExAllocatePoolWithTag(PagedPool
, QueryResponse
->LengthAccepted
, TAG_MUP
);
1811 if (AcceptedPrefix
== NULL
)
1813 Prefix
->InTable
= FALSE
;
1817 /* Set it up to the accepted length */
1818 RtlMoveMemory(AcceptedPrefix
, MasterQueryContext
->FileObject
->FileName
.Buffer
, QueryResponse
->LengthAccepted
);
1819 Prefix
->UncProvider
= MasterQueryContext
->LatestProvider
;
1820 Prefix
->AcceptedPrefix
.Buffer
= AcceptedPrefix
;
1821 Prefix
->AcceptedPrefix
.Length
= QueryResponse
->LengthAccepted
;
1822 Prefix
->AcceptedPrefix
.MaximumLength
= QueryResponse
->LengthAccepted
;
1823 Prefix
->ExternalAlloc
= TRUE
;
1825 /* Insert the accepted prefix in the table of known prefixes */
1826 DPRINT1("%wZ accepted %wZ\n", &Prefix
->UncProvider
->DeviceName
, &Prefix
->AcceptedPrefix
);
1827 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1828 if (RtlInsertUnicodePrefix(&MupPrefixTable
, &Prefix
->AcceptedPrefix
, &Prefix
->PrefixTableEntry
))
1830 InsertHeadList(&MupPrefixList
, &Prefix
->PrefixListEntry
);
1831 Prefix
->InTable
= TRUE
;
1832 Prefix
->KeepExtraRef
= TRUE
;
1836 Prefix
->InTable
= FALSE
;
1838 ExReleaseResourceLite(&MupPrefixTableLock
);
1844 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1846 /* We failed and didn't find any provider over the latest iterations */
1847 if (MasterQueryContext
->LatestProvider
== NULL
)
1849 /* If we had a success though (broken provider?) set our failed status */
1850 if (NT_SUCCESS(MasterQueryContext
->LatestStatus
))
1852 MasterQueryContext
->LatestStatus
= Status
;
1856 TableStatus
= MupOrderedErrorList
[0];
1859 /* Otherwise, time to compare statuteses, between the latest failed
1860 * and the current failure.
1861 * We have an order table of failed status: the deeper you go in the
1862 * table, the more the error is critical.
1863 * Our goal is to return the most critical status that was returned by
1864 * any of the providers
1867 /* Look for latest status position */
1868 while (TableStatus
!= 0 && TableStatus
!= MasterQueryContext
->LatestStatus
)
1871 TableStatus
= MupOrderedErrorList
[LatestPos
];
1874 /* If at pos 0, the new status is likely more critical */
1877 MasterQueryContext
->LatestStatus
= Status
;
1881 /* Otherwise, find position of the new status in the table */
1885 if (Status
== MupOrderedErrorList
[Pos
])
1892 while (Pos
< LatestPos
);
1894 /* If it has a higher position (more critical), return it */
1895 if (Pos
>= LatestPos
)
1897 MasterQueryContext
->LatestStatus
= Status
;
1905 ExFreePoolWithTag(QueryResponse
, TAG_MUP
);
1906 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
1909 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
1910 MupDereferenceMasterQueryContext(MasterQueryContext
);
1912 return STATUS_MORE_PROCESSING_REQUIRED
;
1916 DfsFsdCreate(PDEVICE_OBJECT DeviceObject
,
1920 return STATUS_NOT_IMPLEMENTED
;
1924 CreateRedirectedFile(PIRP Irp
,
1925 PFILE_OBJECT FileObject
,
1926 PIO_SECURITY_CONTEXT SecurityContext
)
1935 PMUP_UNC UncProvider
;
1936 PIO_STACK_LOCATION Stack
;
1937 LARGE_INTEGER CurrentTime
;
1938 PMUP_MQC MasterQueryContext
;
1939 PQUERY_PATH_CONTEXT QueryContext
;
1940 PQUERY_PATH_REQUEST QueryPathRequest
;
1941 PUNICODE_PREFIX_TABLE_ENTRY TableEntry
;
1942 BOOLEAN Locked
, Referenced
, BreakOnFirst
;
1944 /* We cannot open a file without a name */
1945 if (FileObject
->FileName
.Length
== 0)
1947 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1948 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1950 return STATUS_INVALID_DEVICE_REQUEST
;
1953 DPRINT1("Request for opening: %wZ\n", &FileObject
->FileName
);
1956 BreakOnFirst
= TRUE
;
1957 Status
= STATUS_BAD_NETWORK_PATH
;
1959 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1960 /* First, try to see if that's a prefix we already know */
1961 TableEntry
= RtlFindUnicodePrefix(&MupPrefixTable
, &FileObject
->FileName
, 1);
1962 if (TableEntry
!= NULL
)
1964 Prefix
= CONTAINING_RECORD(TableEntry
, MUP_PFX
, PrefixTableEntry
);
1966 DPRINT("Matching prefix found: %wZ\n", &Prefix
->AcceptedPrefix
);
1968 /* If so, check whether the prefix is still valid */
1969 KeQuerySystemTime(&CurrentTime
);
1970 if (Prefix
->ValidityTimeout
.QuadPart
< CurrentTime
.QuadPart
)
1972 /* It is: so, update its validity period and reroute file opening */
1973 MupCalculateTimeout(&Prefix
->ValidityTimeout
);
1974 Status
= MupRerouteOpen(FileObject
, Prefix
->UncProvider
);
1975 ExReleaseResourceLite(&MupPrefixTableLock
);
1977 if (Status
== STATUS_REPARSE
)
1979 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1982 Irp
->IoStatus
.Status
= Status
;
1983 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1988 /* When here, we found a matching prefix, but expired, remove it from the table
1989 * We'll redo a full search
1991 if (Prefix
->InTable
)
1993 MupRemoveKnownPrefixEntry(Prefix
);
1996 ExReleaseResourceLite(&MupPrefixTableLock
);
1998 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1999 /* First of all, start looking for a mailslot */
2000 if (FileObject
->FileName
.Buffer
[0] == L
'\\' && Stack
->MajorFunction
!= IRP_MJ_CREATE
)
2002 Name
= &FileObject
->FileName
.Buffer
[1];
2003 Len
= FileObject
->FileName
.Length
;
2005 /* Skip the remote destination name */
2008 Len
-= sizeof(WCHAR
);
2016 } while (Cur
!= L
'\\');
2017 Len
-= sizeof(WCHAR
);
2019 /* If we still have room for "Mailslot" to fit */
2020 if (Len
>= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)))
2022 /* Get the len in terms of chars count */
2023 Len
/= sizeof(WCHAR
);
2024 if (Len
> ((sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
)))
2026 Len
= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
);
2029 /* It's indeed a mailslot opening! */
2030 if (_wcsnicmp(Name
, L
"Mailslot", Len
) == 0)
2032 /* Broadcast open */
2033 Status
= BroadcastOpen(Irp
);
2034 if (Status
== STATUS_REPARSE
)
2036 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
2039 Irp
->IoStatus
.Status
= Status
;
2040 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2047 /* Ok, at that point, that's a regular MUP opening (if no DFS) */
2048 if (!MupEnableDfs
|| FileObject
->FsContext2
== DFS_MAGIC_CCB
)
2050 /* We won't complete immediately */
2051 IoMarkIrpPending(Irp
);
2053 /* Allocate a new prefix for our search */
2054 Prefix
= MupAllocatePrefixEntry(0);
2057 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2058 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2060 return STATUS_PENDING
;
2063 /* Allocate a context for our search */
2064 MasterQueryContext
= MupAllocateMasterQueryContext();
2065 if (MasterQueryContext
== NULL
)
2067 MupFreeNode(Prefix
);
2069 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2070 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2072 return STATUS_PENDING
;
2075 MasterQueryContext
->Irp
= Irp
;
2076 MasterQueryContext
->FileObject
= FileObject
;
2077 MasterQueryContext
->LatestProvider
= NULL
;
2078 MasterQueryContext
->Prefix
= Prefix
;
2079 MasterQueryContext
->LatestStatus
= STATUS_BAD_NETWORK_PATH
;
2080 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2081 InsertTailList(&MupMasterQueryList
, &MasterQueryContext
->MQCListEntry
);
2082 ++Prefix
->NodeReferences
;
2083 ExReleaseResourceLite(&MupGlobalLock
);
2087 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2090 /* Now, we will browse all the providers we know, to ask for their accepted prefix regarding the path */
2091 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
2093 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
2095 ++UncProvider
->NodeReferences
;
2098 ExReleaseResourceLite(&MupGlobalLock
);
2101 /* We will obviously only query registered providers */
2102 if (UncProvider
->Registered
)
2104 /* We will issue an IOCTL_REDIR_QUERY_PATH, so allocate input buffer */
2105 QueryPathRequest
= ExAllocatePoolWithTag(PagedPool
, FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
), TAG_MUP
);
2106 if (QueryPathRequest
== NULL
)
2108 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2111 /* Allocate a context for IRP completion routine
2112 * In case a prefix matches the path, the reroute will happen
2113 * in the completion routine, when we have return from the provider
2115 QueryContext
= ExAllocatePoolWithTag(PagedPool
, sizeof(QUERY_PATH_CONTEXT
), TAG_MUP
);
2116 if (QueryContext
== NULL
)
2118 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2119 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2122 InitializeListHead(&QueryContext
->QueryPathListEntry
);
2123 QueryContext
->MasterQueryContext
= MasterQueryContext
;
2124 QueryContext
->QueryPathRequest
= QueryPathRequest
;
2125 QueryPathRequest
->PathNameLength
= FileObject
->FileName
.Length
;
2126 QueryPathRequest
->SecurityContext
= SecurityContext
;
2127 RtlMoveMemory(QueryPathRequest
->FilePathName
, FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
2129 /* Build our IRP for the query */
2130 QueryIrp
= MupBuildIoControlRequest(UncProvider
->FileObject
,
2132 IRP_MJ_DEVICE_CONTROL
,
2133 IOCTL_REDIR_QUERY_PATH
,
2135 FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
),
2137 sizeof(QUERY_PATH_RESPONSE
),
2138 QueryPathCompletionRoutine
);
2139 if (QueryIrp
== NULL
)
2141 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
2142 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2143 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2146 QueryIrp
->RequestorMode
= KernelMode
;
2147 QueryContext
->UncProvider
= UncProvider
;
2148 QueryContext
->Irp
= QueryIrp
;
2150 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2151 ++UncProvider
->NodeReferences
;
2152 ++MasterQueryContext
->NodeReferences
;
2153 ExReleaseResourceLite(&MupGlobalLock
);
2155 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
2156 InsertTailList(&MasterQueryContext
->QueryPathList
, &QueryContext
->QueryPathListEntry
);
2157 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
2159 /* Query the provider !*/
2160 DPRINT1("Requesting UNC provider: %wZ\n", &UncProvider
->DeviceName
);
2161 DPRINT("Calling: %wZ\n", &UncProvider
->DeviceObject
->DriverObject
->DriverName
);
2162 Status
= IoCallDriver(UncProvider
->DeviceObject
, QueryIrp
);
2165 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2168 /* We're done with that provider */
2169 MupDereferenceUncProvider(UncProvider
);
2172 /* If query went fine on the first request, just break and leave */
2173 if (BreakOnFirst
&& Status
== STATUS_SUCCESS
)
2178 BreakOnFirst
= FALSE
;
2183 if (_abnormal_termination())
2185 MasterQueryContext
->LatestStatus
= STATUS_INSUFFICIENT_RESOURCES
;
2190 MupDereferenceUncProvider(UncProvider
);
2195 ExReleaseResourceLite(&MupGlobalLock
);
2198 MupDereferenceMasterQueryContext(MasterQueryContext
);
2200 Status
= STATUS_PENDING
;
2207 Status
= STATUS_NOT_IMPLEMENTED
;
2214 OpenMupFileSystem(PMUP_VCB Vcb
,
2215 PFILE_OBJECT FileObject
,
2216 ACCESS_MASK DesiredAccess
,
2221 DPRINT1("Opening MUP\n");
2223 ExAcquireResourceExclusiveLite(&MupVcbLock
, TRUE
);
2226 /* Update share access, increase reference count, and associated VCB to the FO, that's it! */
2227 Status
= IoCheckShareAccess(DesiredAccess
, ShareAccess
, FileObject
, &Vcb
->ShareAccess
, TRUE
);
2228 if (NT_SUCCESS(Status
))
2230 ++Vcb
->NodeReferences
;
2231 MupSetFileObject(FileObject
, (PMUP_FCB
)Vcb
, NULL
);
2232 Status
= STATUS_SUCCESS
;
2237 ExReleaseResourceLite(&MupVcbLock
);
2246 MupCreate(PDEVICE_OBJECT DeviceObject
,
2250 PIO_STACK_LOCATION Stack
;
2251 PFILE_OBJECT FileObject
, RelatedFileObject
;
2253 FsRtlEnterFileSystem();
2257 /* If DFS is enabled, check if that's for DFS and is so relay */
2258 if (MupEnableDfs
&& (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
))
2260 Status
= DfsFsdCreate(DeviceObject
, Irp
);
2264 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2265 FileObject
= Stack
->FileObject
;
2266 RelatedFileObject
= FileObject
->RelatedFileObject
;
2268 /* 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 */
2269 if (FileObject
->FileName
.Length
!= 0 || (RelatedFileObject
!= NULL
&& ((PMUP_FCB
)(RelatedFileObject
->FsContext
))->NodeType
!= NODE_TYPE_VCB
))
2271 Status
= CreateRedirectedFile(Irp
, FileObject
, Stack
->Parameters
.Create
.SecurityContext
);
2273 /* Otherwise, it's just a volume open */
2276 Status
= OpenMupFileSystem(DeviceObject
->DeviceExtension
,
2278 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
2279 Stack
->Parameters
.Create
.ShareAccess
);
2281 Irp
->IoStatus
.Information
= FILE_OPENED
;
2282 Irp
->IoStatus
.Status
= Status
;
2283 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2287 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2289 Status
= _SEH2_GetExceptionCode();
2291 Irp
->IoStatus
.Status
= Status
;
2292 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2296 FsRtlExitFileSystem();
2302 MupCloseUncProvider(PMUP_UNC UncProvider
)
2304 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2306 /* If the node was still valid, reregister the UNC provider */
2307 if (UncProvider
->NodeStatus
== NODE_STATUS_HEALTHY
)
2309 UncProvider
->NodeStatus
= NODE_STATUS_CLEANUP
;
2310 UncProvider
->Registered
= FALSE
;
2311 ExReleaseResourceLite(&MupGlobalLock
);
2313 if (UncProvider
->FileObject
!= NULL
)
2315 ZwClose(UncProvider
->DeviceHandle
);
2316 ObDereferenceObject(UncProvider
->FileObject
);
2321 ExReleaseResourceLite(&MupGlobalLock
);
2326 DfsFsdCleanup(PDEVICE_OBJECT DeviceObject
,
2330 return STATUS_NOT_IMPLEMENTED
;
2335 MupCleanup(PDEVICE_OBJECT DeviceObject
,
2342 PIO_STACK_LOCATION Stack
;
2344 /* If DFS is enabled, check if that's for DFS and is so relay */
2347 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2349 return DfsFsdCleanup(DeviceObject
, Irp
);
2353 FsRtlEnterFileSystem();
2357 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2358 Type
= MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2362 /* If we got a VCB, clean it up */
2363 MupCleanupVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
);
2365 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2366 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2368 MupDereferenceVcb((PMUP_VCB
)Fcb
);
2370 /* If Ccb is not null, then, it's a UNC provider node */
2373 /* Close it, and dereference */
2374 MupCloseUncProvider((PMUP_UNC
)Ccb
);
2375 MupDereferenceUncProvider((PMUP_UNC
)Ccb
);
2376 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2378 ExReleaseResourceLite(&MupGlobalLock
);
2381 Status
= STATUS_SUCCESS
;
2385 /* If the node wasn't already cleaned, do it */
2386 if (Fcb
->NodeStatus
== NODE_STATUS_HEALTHY
)
2388 MupCleanupFcb(DeviceObject
, Irp
, Fcb
);
2389 Status
= STATUS_SUCCESS
;
2393 Status
= STATUS_INVALID_HANDLE
;
2396 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2397 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2399 MupDereferenceFcb(Fcb
);
2403 Status
= STATUS_INVALID_HANDLE
;
2405 Irp
->IoStatus
.Status
= Status
;
2406 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2411 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2413 Status
= _SEH2_GetExceptionCode();
2417 FsRtlExitFileSystem();
2423 MupCloseVcb(PDEVICE_OBJECT DeviceObject
,
2426 PFILE_OBJECT FileObject
)
2428 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2430 /* Remove FCB, UNC from FO */
2431 MupSetFileObject(FileObject
, NULL
, NULL
);
2432 MupDereferenceVcb(Vcb
);
2434 ExReleaseResourceLite(&MupGlobalLock
);
2436 return STATUS_SUCCESS
;
2440 MupCloseFcb(PDEVICE_OBJECT DeviceObject
,
2443 PFILE_OBJECT FileObject
)
2445 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2447 /* Remove FCB, CCB from FO */
2448 MupSetFileObject(FileObject
, NULL
, NULL
);
2449 MupDereferenceFcb(Fcb
);
2451 ExReleaseResourceLite(&MupGlobalLock
);
2453 return STATUS_SUCCESS
;
2457 DfsFsdClose(PDEVICE_OBJECT DeviceObject
,
2461 return STATUS_NOT_IMPLEMENTED
;
2466 MupClose(PDEVICE_OBJECT DeviceObject
,
2472 PIO_STACK_LOCATION Stack
;
2474 /* If DFS is enabled, check if that's for DFS and is so relay */
2477 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2479 return DfsFsdClose(DeviceObject
, Irp
);
2483 FsRtlEnterFileSystem();
2487 /* Get our internal structures from FO */
2488 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2489 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2492 Status
= STATUS_INVALID_HANDLE
;
2494 Irp
->IoStatus
.Status
= Status
;
2495 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2500 /* If we got the VCB, that's a volume close */
2501 if (Fcb
->NodeType
== NODE_TYPE_VCB
)
2503 Status
= MupCloseVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
, Stack
->FileObject
);
2505 /* Otherwise close the FCB */
2506 else if (Fcb
->NodeType
== NODE_TYPE_FCB
)
2508 MupDereferenceFcb(Fcb
);
2509 Status
= MupCloseFcb(DeviceObject
, Irp
, Fcb
, Stack
->FileObject
);
2513 Status
= STATUS_INVALID_HANDLE
;
2515 Irp
->IoStatus
.Status
= Status
;
2516 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2521 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2522 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2524 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2526 Status
= _SEH2_GetExceptionCode();
2530 FsRtlExitFileSystem();
2536 DfsUnload(PDRIVER_OBJECT DriverObject
)
2543 MupUnload(PDRIVER_OBJECT DriverObject
)
2545 IoDeleteDevice(mupDeviceObject
);
2549 DfsUnload(DriverObject
);
2552 MupUninitializeData();
2557 DfsDriverEntry(PDRIVER_OBJECT DriverObject
,
2558 PUNICODE_STRING RegistryPath
)
2560 /* We don't support DFS yet, so
2561 * fail to make sure it remains disabled
2564 return STATUS_NOT_IMPLEMENTED
;
2568 * FUNCTION: Called by the system to initialize the driver
2570 * DriverObject = object describing this driver
2571 * RegistryPath = path to our configuration entries
2572 * RETURNS: Success or failure
2577 DriverEntry(PDRIVER_OBJECT DriverObject
,
2578 PUNICODE_STRING RegistryPath
)
2581 UNICODE_STRING MupString
;
2582 PDEVICE_OBJECT DeviceObject
;
2584 /* Only initialize global state of the driver
2585 * Other inits will happen when required
2587 MupInitializeData();
2589 /* Check if DFS is disabled */
2590 MupEnableDfs
= MuppIsDfsEnabled();
2591 /* If it's not disabled but when cannot init, disable it */
2592 if (MupEnableDfs
&& !NT_SUCCESS(DfsDriverEntry(DriverObject
, RegistryPath
)))
2594 MupEnableDfs
= FALSE
;
2597 /* Create the MUP device */
2598 RtlInitUnicodeString(&MupString
, L
"\\Device\\Mup");
2599 Status
= IoCreateDevice(DriverObject
, sizeof(MUP_VCB
), &MupString
, FILE_DEVICE_MULTI_UNC_PROVIDER
, 0, FALSE
, &DeviceObject
);
2600 if (!NT_SUCCESS(Status
))
2604 DfsUnload(DriverObject
);
2607 MupUninitializeData();
2613 DriverObject
->DriverUnload
= MupUnload
;
2614 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MupCreate
;
2615 DriverObject
->MajorFunction
[IRP_MJ_CREATE_NAMED_PIPE
] = MupCreate
;
2616 DriverObject
->MajorFunction
[IRP_MJ_CREATE_MAILSLOT
] = MupCreate
;
2617 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = MupForwardIoRequest
;
2618 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] = MupFsControl
;
2619 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MupCleanup
;
2620 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MupClose
;
2622 /* And finish init */
2623 mupDeviceObject
= DeviceObject
;
2624 MupInitializeVcb(DeviceObject
->DeviceExtension
);
2626 return STATUS_SUCCESS
;