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
);
960 /* And create the provider
961 * It will remain unregistered until FsRTL receives a registration request and forwards
964 if (NT_SUCCESS(Status
))
966 ASSERT(Info
!= NULL
);
967 AddUnregisteredProvider((PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
), ProviderOrder
);
972 ExFreePoolWithTag(Info
, TAG_MUP
);
977 MupGetProviderInformation(VOID
)
982 PWSTR Providers
, Coma
;
983 PKEY_VALUE_FULL_INFORMATION Info
;
984 ULONG ResultLength
, ProviderCount
;
985 OBJECT_ATTRIBUTES ObjectAttributes
;
986 UNICODE_STRING NetworkProvider
, ProviderOrder
;
988 /* Open the registry to get the order of the providers */
989 RtlInitUnicodeString(&NetworkProvider
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
990 InitializeObjectAttributes(&ObjectAttributes
,
992 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
995 Status
= ZwOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &ObjectAttributes
);
996 if (!NT_SUCCESS(Status
))
1001 RtlInitUnicodeString(&ProviderOrder
, L
"ProviderOrder");
1002 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, NULL
, 0, &ResultLength
);
1003 if (Status
== STATUS_BUFFER_TOO_SMALL
)
1005 Info
= ExAllocatePoolWithTag(PagedPool
, ResultLength
+ sizeof(UNICODE_NULL
), TAG_MUP
);
1012 Status
= ZwQueryValueKey(KeyHandle
, &ProviderOrder
, KeyValueFullInformation
, Info
, ResultLength
, &ResultLength
);
1021 if (NT_SUCCESS(Status
))
1023 ASSERT(Info
!= NULL
);
1025 Providers
= (PWSTR
)((ULONG_PTR
)Info
+ Info
->DataOffset
);
1029 /* For all the providers we got (coma-separated list), just create a provider node with the right order
1030 * The order is just the order of the list
1031 * First has highest priority (0) and then, get lower and lower priority
1032 * The highest number is the lowest priority
1036 Coma
= wcschr(Providers
, L
',');
1039 *Coma
= UNICODE_NULL
;
1046 InitializeProvider(Providers
, ProviderCount
);
1049 Providers
= Coma
+ 1;
1055 ExFreePoolWithTag(Info
, TAG_MUP
);
1060 MupCheckForUnregisteredProvider(PUNICODE_STRING RedirectorDeviceName
)
1063 PMUP_UNC UncProvider
;
1065 /* Browse the list of all the providers nodes we have */
1066 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1067 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1069 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1071 /* If one matches the device and is not registered, that's ours! */
1072 if (!UncProvider
->Registered
&& RtlEqualUnicodeString(RedirectorDeviceName
, &UncProvider
->DeviceName
, TRUE
))
1074 UncProvider
->NodeStatus
= NODE_STATUS_HEALTHY
;
1079 if (Entry
== &MupProviderList
)
1083 ExReleaseResourceLite(&MupGlobalLock
);
1089 RegisterUncProvider(PDEVICE_OBJECT DeviceObject
,
1098 PIO_STACK_LOCATION Stack
;
1099 IO_STATUS_BLOCK IoStatusBlock
;
1100 PMUP_UNC UncProvider
, ListEntry
;
1101 OBJECT_ATTRIBUTES ObjectAttributes
;
1102 UNICODE_STRING RedirectorDeviceName
;
1103 OBJECT_HANDLE_INFORMATION HandleInfo
;
1104 PMUP_PROVIDER_REGISTRATION_INFO RegInfo
;
1106 DPRINT1("RegisterUncProvider(%p, %p)\n", DeviceObject
, Irp
);
1109 /* Check whether providers order was already initialized */
1110 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1111 if (MupOrderInitialized
)
1113 ExReleaseResourceLite(&MupGlobalLock
);
1117 /* They weren't, so do it */
1118 MupOrderInitialized
= TRUE
;
1119 ExReleaseResourceLite(&MupGlobalLock
);
1120 MupGetProviderInformation();
1123 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1125 /* This can only happen with a volume open */
1126 if (MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
) != NODE_TYPE_VCB
)
1128 Irp
->IoStatus
.Status
= STATUS_INVALID_HANDLE
;
1129 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1131 return STATUS_INVALID_HANDLE
;
1134 /* Get the registration information */
1135 RegInfo
= (PMUP_PROVIDER_REGISTRATION_INFO
)Irp
->AssociatedIrp
.SystemBuffer
;
1138 RedirectorDeviceName
.Length
= RegInfo
->RedirectorDeviceNameLength
;
1139 RedirectorDeviceName
.MaximumLength
= RedirectorDeviceName
.Length
;
1140 RedirectorDeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
);
1142 /* Have we got already a node for it? (Like from previous init) */
1143 UncProvider
= MupCheckForUnregisteredProvider(&RedirectorDeviceName
);
1144 if (UncProvider
== NULL
)
1146 /* If we don't, allocate a new one */
1148 UncProvider
= MupAllocateUncProvider(RegInfo
->RedirectorDeviceNameLength
);
1149 if (UncProvider
== NULL
)
1151 Status
= STATUS_INVALID_USER_BUFFER
;
1156 UncProvider
->DeviceName
.Length
= RedirectorDeviceName
.Length
;
1157 UncProvider
->DeviceName
.MaximumLength
= RedirectorDeviceName
.MaximumLength
;
1158 UncProvider
->DeviceName
.Buffer
= (PWSTR
)((ULONG_PTR
)UncProvider
+ sizeof(MUP_UNC
));
1160 /* As it wasn't in registry for order, give the lowest priority possible */
1161 UncProvider
->ProviderOrder
= MAXLONG
;
1162 RtlMoveMemory(UncProvider
->DeviceName
.Buffer
, (PWSTR
)((ULONG_PTR
)RegInfo
+ RegInfo
->RedirectorDeviceNameOffset
), RegInfo
->RedirectorDeviceNameLength
);
1165 /* Continue registration */
1166 UncProvider
->MailslotsSupported
= RegInfo
->MailslotsSupported
;
1167 ++UncProvider
->NodeReferences
;
1169 /* Open a handle to the device */
1170 InitializeObjectAttributes(&ObjectAttributes
,
1171 &UncProvider
->DeviceName
,
1172 OBJ_CASE_INSENSITIVE
,
1175 Status
= NtOpenFile(&UncProvider
->DeviceHandle
,
1179 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1180 FILE_DIRECTORY_FILE
);
1181 if (NT_SUCCESS(Status
))
1183 Status
= IoStatusBlock
.Status
;
1186 /* And return the provider (as CCB) */
1187 if (NT_SUCCESS(Status
))
1189 Stack
->FileObject
->FsContext2
= UncProvider
;
1190 Status
= ObReferenceObjectByHandle(UncProvider
->DeviceHandle
, 0, NULL
, KernelMode
, (PVOID
*)&UncProvider
->FileObject
, &HandleInfo
);
1191 if (!NT_SUCCESS(Status
))
1193 NtClose(UncProvider
->DeviceHandle
);
1197 if (!NT_SUCCESS(Status
))
1199 MupDereferenceUncProvider(UncProvider
);
1203 UncProvider
->DeviceObject
= IoGetRelatedDeviceObject(UncProvider
->FileObject
);
1205 /* Now, insert the provider in our global list
1206 * They are sorted by order
1208 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1212 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1214 ListEntry
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1216 if (UncProvider
->ProviderOrder
< ListEntry
->ProviderOrder
)
1222 InsertTailList(Entry
, &UncProvider
->ProviderListEntry
);
1224 UncProvider
->Registered
= TRUE
;
1225 ExReleaseResourceLite(&MupGlobalLock
);
1226 Status
= STATUS_SUCCESS
;
1228 DPRINT1("UNC provider %wZ registered\n", &UncProvider
->DeviceName
);
1233 if (_abnormal_termination())
1235 Status
= STATUS_INVALID_USER_BUFFER
;
1238 MupDereferenceVcb((PMUP_VCB
)Fcb
);
1240 Irp
->IoStatus
.Status
= Status
;
1241 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1249 DfsFsdFileSystemControl(PDEVICE_OBJECT DeviceObject
,
1252 return STATUS_NOT_IMPLEMENTED
;
1257 MupFsControl(PDEVICE_OBJECT DeviceObject
,
1261 PIO_STACK_LOCATION Stack
;
1263 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1267 /* MUP only understands a single FSCTL code: registering UNC provider */
1268 if (Stack
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_MUP_REGISTER_PROVIDER
)
1270 /* It obviously has to come from a driver/kernelmode thread */
1271 if (Irp
->RequestorMode
== UserMode
)
1273 Status
= STATUS_ACCESS_DENIED
;
1275 Irp
->IoStatus
.Status
= Status
;
1276 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1281 Status
= RegisterUncProvider(DeviceObject
, Irp
);
1285 /* If that's an unknown FSCTL code, maybe it's for DFS, pass it */
1288 Status
= STATUS_INVALID_PARAMETER
;
1290 Irp
->IoStatus
.Status
= Status
;
1291 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1296 Status
= DfsFsdFileSystemControl(DeviceObject
, Irp
);
1299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1301 Status
= _SEH2_GetExceptionCode();
1309 MupSetFileObject(PFILE_OBJECT FileObject
,
1313 FileObject
->FsContext
= Fcb
;
1314 FileObject
->FsContext2
= Ccb
;
1318 MupRerouteOpen(PFILE_OBJECT FileObject
,
1319 PMUP_UNC UncProvider
)
1324 DPRINT1("Rerouting %wZ with %wZ\n", &FileObject
->FileName
, &UncProvider
->DeviceName
);
1326 /* Get the full path name (device name first, and requested file name appended) */
1327 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1328 if (TotalLength
> MAXUSHORT
)
1330 return STATUS_NAME_TOO_LONG
;
1333 /* Allocate a buffer big enough */
1334 FullPath
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1335 if (FullPath
== NULL
)
1337 return STATUS_INSUFFICIENT_RESOURCES
;
1340 /* Create the full path */
1341 RtlMoveMemory(FullPath
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1342 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
+ UncProvider
->DeviceName
.Length
), FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
1344 /* And redo the path in the file oject */
1345 ExFreePoolWithTag(FileObject
->FileName
.Buffer
, 0);
1346 FileObject
->FileName
.Buffer
= FullPath
;
1347 FileObject
->FileName
.MaximumLength
= TotalLength
;
1348 FileObject
->FileName
.Length
= FileObject
->FileName
.MaximumLength
;
1350 /* Ob, please reparse to open the correct file at the right place, thanks! :-) */
1351 return STATUS_REPARSE
;
1355 BroadcastOpen(PIRP Irp
)
1361 PMUP_UNC UncProvider
;
1362 UNICODE_STRING FullPath
;
1363 PFILE_OBJECT FileObject
;
1364 PIO_STACK_LOCATION Stack
;
1365 NTSTATUS Status
, LastFailed
;
1366 ULONG TotalLength
, LastOrder
;
1367 IO_STATUS_BLOCK IoStatusBlock
;
1368 OBJECT_ATTRIBUTES ObjectAttributes
;
1369 OBJECT_HANDLE_INFORMATION HandleInfo
;
1370 BOOLEAN Locked
, Referenced
, CcbInitialized
;
1372 Fcb
= MupCreateFcb();
1375 return STATUS_INSUFFICIENT_RESOURCES
;
1378 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1379 FileObject
= Stack
->FileObject
;
1382 CcbInitialized
= FALSE
;
1383 LastFailed
= STATUS_NO_SUCH_FILE
;
1384 LastOrder
= (ULONG
)-1;
1388 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1391 /* Associate our FCB with the FO */
1392 MupSetFileObject(FileObject
, Fcb
, NULL
);
1393 Fcb
->FileObject
= FileObject
;
1395 /* Now, broadcast the open to any UNC provider that supports mailslots */
1396 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
1398 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
1399 ++UncProvider
->NodeReferences
;
1402 ExReleaseResourceLite(&MupGlobalLock
);
1405 TotalLength
= UncProvider
->DeviceName
.Length
+ FileObject
->FileName
.Length
;
1406 if (UncProvider
->MailslotsSupported
&& TotalLength
<= MAXUSHORT
)
1408 /* Provide the correct name for the mailslot (ie, happened the device name of the provider) */
1409 FullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
, TotalLength
, TAG_MUP
);
1410 if (FullPath
.Buffer
== NULL
)
1412 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
1415 FullPath
.Length
= TotalLength
;
1416 FullPath
.MaximumLength
= TotalLength
;
1417 RtlMoveMemory(FullPath
.Buffer
, UncProvider
->DeviceName
.Buffer
, UncProvider
->DeviceName
.Length
);
1418 RtlMoveMemory((PWSTR
)((ULONG_PTR
)FullPath
.Buffer
+ UncProvider
->DeviceName
.Length
),
1419 FileObject
->FileName
.Buffer
,
1420 FileObject
->FileName
.Length
);
1422 /* And just forward the creation request */
1423 InitializeObjectAttributes(&ObjectAttributes
,
1425 OBJ_KERNEL_HANDLE
| OBJ_CASE_INSENSITIVE
,
1428 Status
= IoCreateFile(&Handle
,
1429 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_SIMPLE_RIGHTS_MASK
,
1433 Stack
->Parameters
.Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
,
1434 Stack
->Parameters
.Create
.ShareAccess
& FILE_SHARE_VALID_FLAGS
,
1436 Stack
->Parameters
.Create
.Options
& FILE_VALID_SET_FLAGS
,
1441 IO_NO_PARAMETER_CHECKING
);
1443 ExFreePoolWithTag(FullPath
.Buffer
, TAG_MUP
);
1445 /* If opening succeed */
1446 if (NT_SUCCESS(Status
))
1448 Status
= IoStatusBlock
.Status
;
1451 Ccb
= MupCreateCcb();
1454 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1457 /* And associated a FO to it */
1458 if (NT_SUCCESS(Status
))
1460 Status
= ObReferenceObjectByHandle(Handle
, 0, 0, 0, (PVOID
*)&Ccb
->FileObject
, &HandleInfo
);
1465 /* If we failed, remember the last failed status of the higher priority provider */
1466 if (!NT_SUCCESS(Status
))
1468 if (UncProvider
->ProviderOrder
<= LastOrder
)
1470 LastOrder
= UncProvider
->ProviderOrder
;
1471 LastFailed
= Status
;
1474 /* Otherwise, properly attach our CCB to the mailslot */
1477 Ccb
->DeviceObject
= IoGetRelatedDeviceObject(Ccb
->FileObject
);
1480 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1482 ++Fcb
->NodeReferences
;
1483 ExReleaseResourceLite(&MupGlobalLock
);
1485 CcbInitialized
= TRUE
;
1487 InsertTailList(&Fcb
->CcbList
, &Ccb
->CcbListEntry
);
1491 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1493 MupDereferenceUncProvider(UncProvider
);
1497 ExReleaseResourceLite(&MupGlobalLock
);
1500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1502 Status
= _SEH2_GetExceptionCode();
1506 /* If we at least opened one mailslot, return success */
1507 Status
= (CcbInitialized
? STATUS_SUCCESS
: LastFailed
);
1511 MupDereferenceUncProvider(UncProvider
);
1516 ExReleaseResourceLite(&MupGlobalLock
);
1519 /* In case of failure, don't leak CCB */
1520 if (!NT_SUCCESS(Status
) && Ccb
!= NULL
)
1529 MupBuildIoControlRequest(PFILE_OBJECT FileObject
,
1531 ULONG MajorFunction
,
1534 ULONG InputBufferSize
,
1536 ULONG OutputBufferSize
,
1537 PIO_COMPLETION_ROUTINE CompletionRoutine
)
1540 PIO_STACK_LOCATION Stack
;
1541 PDEVICE_OBJECT DeviceObject
;
1543 if (InputBuffer
== NULL
)
1548 /* Get the device object */
1549 DeviceObject
= IoGetRelatedDeviceObject(FileObject
);
1550 /* Allocate the IRP (with one more location for us */
1551 Irp
= IoAllocateIrp(DeviceObject
->StackSize
+ 1, FALSE
);
1557 /* Skip our location */
1558 IoSetNextIrpStackLocation(Irp
);
1560 Irp
->Tail
.Overlay
.OriginalFileObject
= FileObject
;
1561 Irp
->Tail
.Overlay
.Thread
= PsGetCurrentThread();
1562 IoSetCompletionRoutine(Irp
, CompletionRoutine
, Context
, TRUE
, TRUE
, TRUE
);
1564 /* Setup the stack */
1565 Stack
= IoGetNextIrpStackLocation(Irp
);
1566 Stack
->MajorFunction
= MajorFunction
;
1567 Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
= OutputBufferSize
;
1568 Stack
->Parameters
.DeviceIoControl
.InputBufferLength
= InputBufferSize
;
1569 Stack
->Parameters
.DeviceIoControl
.IoControlCode
= IoctlCode
;
1570 Stack
->MinorFunction
= 0;
1571 Stack
->FileObject
= FileObject
;
1572 Stack
->DeviceObject
= DeviceObject
;
1574 switch (IO_METHOD_FROM_CTL_CODE(IoctlCode
))
1576 case METHOD_BUFFERED
:
1577 /* If it's buffered, just pass the buffers we got */
1578 Irp
->MdlAddress
= NULL
;
1579 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1580 Irp
->UserBuffer
= OutputBuffer
;
1581 Irp
->Flags
= IRP_BUFFERED_IO
;
1583 if (OutputBuffer
!= NULL
)
1585 Irp
->Flags
|= IRP_INPUT_OPERATION
;
1589 case METHOD_IN_DIRECT
:
1590 case METHOD_OUT_DIRECT
:
1591 /* Otherwise, allocate an MDL */
1592 if (IoAllocateMdl(InputBuffer
, InputBufferSize
, FALSE
, FALSE
, Irp
) == NULL
)
1598 Irp
->AssociatedIrp
.SystemBuffer
= InputBuffer
;
1599 Irp
->Flags
= IRP_BUFFERED_IO
;
1600 MmProbeAndLockPages(Irp
->MdlAddress
, KernelMode
, IoReadAccess
);
1603 case METHOD_NEITHER
:
1604 /* Or pass the buffers */
1605 Irp
->UserBuffer
= OutputBuffer
;
1606 Irp
->MdlAddress
= NULL
;
1607 Irp
->AssociatedIrp
.SystemBuffer
= NULL
;
1608 Stack
->Parameters
.DeviceIoControl
.Type3InputBuffer
= InputBuffer
;
1616 MupFreeMasterQueryContext(PMUP_MQC MasterQueryContext
)
1618 ExDeleteResourceLite(&MasterQueryContext
->QueryPathListLock
);
1619 ExFreePoolWithTag(MasterQueryContext
, TAG_MUP
);
1623 MupDereferenceMasterQueryContext(PMUP_MQC MasterQueryContext
)
1627 BOOLEAN KeepExtraRef
;
1629 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1630 --MasterQueryContext
->NodeReferences
;
1631 References
= MasterQueryContext
->NodeReferences
;
1632 ExReleaseResourceLite(&MupGlobalLock
);
1634 if (References
!= 0)
1636 DPRINT("Still having refs (%ld)\n", References
);
1637 return STATUS_PENDING
;
1640 /* We HAVE an IRP to complete. It cannot be NULL
1641 * Please, help preserving kittens, don't provide NULL IRPs.
1643 if (MasterQueryContext
->Irp
== NULL
)
1645 KeBugCheck(FILE_SYSTEM
);
1648 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
1649 RemoveEntryList(&MasterQueryContext
->MQCListEntry
);
1650 ExReleaseResourceLite(&MupGlobalLock
);
1652 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1653 KeepExtraRef
= MasterQueryContext
->Prefix
->KeepExtraRef
;
1654 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1656 /* We found a provider? */
1657 if (MasterQueryContext
->LatestProvider
!= NULL
)
1659 /* With a successful status? */
1660 if (MasterQueryContext
->LatestStatus
== STATUS_SUCCESS
)
1662 /* Then, it's time to reroute, someone accepted to handle the file creation request! */
1665 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1668 ExReleaseResourceLite(&MupPrefixTableLock
);
1669 /* Reroute & complete :-) */
1670 Status
= MupRerouteOpen(MasterQueryContext
->FileObject
, MasterQueryContext
->LatestProvider
);
1675 MupDereferenceUncProvider(MasterQueryContext
->LatestProvider
);
1679 MupDereferenceKnownPrefix(MasterQueryContext
->Prefix
);
1680 ExReleaseResourceLite(&MupPrefixTableLock
);
1682 /* Return the highest failed status we had */
1683 Status
= MasterQueryContext
->LatestStatus
;
1686 /* In finally, complete the IRP for real! */
1687 MasterQueryContext
->Irp
->IoStatus
.Status
= Status
;
1688 IofCompleteRequest(MasterQueryContext
->Irp
, IO_DISK_INCREMENT
);
1690 MasterQueryContext
->Irp
= NULL
;
1691 MupFreeMasterQueryContext(MasterQueryContext
);
1698 QueryPathCompletionRoutine(PDEVICE_OBJECT DeviceObject
,
1703 ULONG LatestPos
, Pos
;
1704 PWSTR AcceptedPrefix
;
1705 PMUP_MQC MasterQueryContext
;
1706 NTSTATUS Status
, TableStatus
;
1707 PQUERY_PATH_CONTEXT QueryContext
;
1708 PQUERY_PATH_RESPONSE QueryResponse
;
1710 /* Get all the data from our query to the provider */
1711 QueryContext
= (PQUERY_PATH_CONTEXT
)Context
;
1712 QueryResponse
= (PQUERY_PATH_RESPONSE
)QueryContext
->QueryPathRequest
;
1713 MasterQueryContext
= QueryContext
->MasterQueryContext
;
1714 Status
= Irp
->IoStatus
.Status
;
1716 DPRINT("Reply from %wZ: %u (Status: %lx)\n", &QueryContext
->UncProvider
->DeviceName
, QueryResponse
->LengthAccepted
, Status
);
1718 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
1719 RemoveEntryList(&QueryContext
->QueryPathListEntry
);
1721 /* If the driver returned a success, and an acceptance length */
1722 if (NT_SUCCESS(Status
) && QueryResponse
->LengthAccepted
> 0)
1724 Prefix
= MasterQueryContext
->Prefix
;
1726 /* Check if we already found a provider from a previous iteration */
1727 if (MasterQueryContext
->LatestProvider
!= NULL
)
1729 /* If the current provider has a lower priority (ie, a greater order), then, bailout and keep previous one */
1730 if (QueryContext
->UncProvider
->ProviderOrder
>= MasterQueryContext
->LatestProvider
->ProviderOrder
)
1732 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1736 /* Otherwise, if the prefix was in the prefix table, just drop it:
1737 * we have a provider which superseeds the accepted prefix, so leave
1738 * room for the new prefix/provider
1740 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1741 if (Prefix
->InTable
)
1743 RtlRemoveUnicodePrefix(&MupPrefixTable
, &Prefix
->PrefixTableEntry
);
1744 RemoveEntryList(&Prefix
->PrefixListEntry
);
1745 Prefix
->InTable
= FALSE
;
1747 ExReleaseResourceLite(&MupPrefixTableLock
);
1749 Prefix
->KeepExtraRef
= FALSE
;
1751 /* Release data associated with the current prefix, if any
1752 * We'll renew them with the new accepted prefix
1754 if (Prefix
->AcceptedPrefix
.Length
!= 0 && Prefix
->AcceptedPrefix
.Buffer
!= NULL
)
1756 ExFreePoolWithTag(Prefix
->AcceptedPrefix
.Buffer
, TAG_MUP
);
1757 Prefix
->AcceptedPrefix
.MaximumLength
= 0;
1758 Prefix
->AcceptedPrefix
.Length
= 0;
1759 Prefix
->AcceptedPrefix
.Buffer
= NULL
;
1760 Prefix
->ExternalAlloc
= FALSE
;
1763 /* If there was also a provider, drop it, the new one
1766 if (Prefix
->UncProvider
!= NULL
)
1768 MupDereferenceUncProvider(Prefix
->UncProvider
);
1769 Prefix
->UncProvider
= NULL
;
1773 /* Now, set our information about the provider that accepted the prefix */
1774 MasterQueryContext
->LatestProvider
= QueryContext
->UncProvider
;
1775 MasterQueryContext
->LatestStatus
= Status
;
1777 if (MasterQueryContext
->FileObject
->FsContext2
!= DFS_MAGIC_CCB
)
1779 /* Allocate a buffer for the prefix */
1780 AcceptedPrefix
= ExAllocatePoolWithTag(PagedPool
, QueryResponse
->LengthAccepted
, TAG_MUP
);
1781 if (AcceptedPrefix
== NULL
)
1783 Prefix
->InTable
= FALSE
;
1787 /* Set it up to the accepted length */
1788 RtlMoveMemory(AcceptedPrefix
, MasterQueryContext
->FileObject
->FileName
.Buffer
, QueryResponse
->LengthAccepted
);
1789 Prefix
->UncProvider
= MasterQueryContext
->LatestProvider
;
1790 Prefix
->AcceptedPrefix
.Buffer
= AcceptedPrefix
;
1791 Prefix
->AcceptedPrefix
.Length
= QueryResponse
->LengthAccepted
;
1792 Prefix
->AcceptedPrefix
.MaximumLength
= QueryResponse
->LengthAccepted
;
1793 Prefix
->ExternalAlloc
= TRUE
;
1795 /* Insert the accepted prefix in the table of known prefixes */
1796 DPRINT1("%wZ accepted %wZ\n", &Prefix
->UncProvider
->DeviceName
, &Prefix
->AcceptedPrefix
);
1797 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1798 if (RtlInsertUnicodePrefix(&MupPrefixTable
, &Prefix
->AcceptedPrefix
, &Prefix
->PrefixTableEntry
))
1800 InsertHeadList(&MupPrefixList
, &Prefix
->PrefixListEntry
);
1801 Prefix
->InTable
= TRUE
;
1802 Prefix
->KeepExtraRef
= TRUE
;
1806 Prefix
->InTable
= FALSE
;
1808 ExReleaseResourceLite(&MupPrefixTableLock
);
1814 MupDereferenceUncProvider(QueryContext
->UncProvider
);
1816 /* We failed and didn't find any provider over the latest iterations */
1817 if (MasterQueryContext
->LatestProvider
== NULL
)
1819 /* If we had a success though (broken provider?) set our failed status */
1820 if (NT_SUCCESS(MasterQueryContext
->LatestStatus
))
1822 MasterQueryContext
->LatestStatus
= Status
;
1826 TableStatus
= MupOrderedErrorList
[0];
1829 /* Otherwise, time to compare statuteses, between the latest failed
1830 * and the current failure.
1831 * We have an order table of failed status: the deeper you go in the
1832 * table, the more the error is critical.
1833 * Our goal is to return the most critical status that was returned by
1834 * any of the providers
1837 /* Look for latest status position */
1838 while (TableStatus
!= 0 && TableStatus
!= MasterQueryContext
->LatestStatus
)
1841 TableStatus
= MupOrderedErrorList
[LatestPos
];
1844 /* If at pos 0, the new status is likely more critical */
1847 MasterQueryContext
->LatestStatus
= Status
;
1851 /* Otherwise, find position of the new status in the table */
1855 if (Status
== MupOrderedErrorList
[Pos
])
1862 while (Pos
< LatestPos
);
1864 /* If it has a higher position (more critical), return it */
1865 if (Pos
>= LatestPos
)
1867 MasterQueryContext
->LatestStatus
= Status
;
1875 ExFreePoolWithTag(QueryResponse
, TAG_MUP
);
1876 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
1879 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
1880 MupDereferenceMasterQueryContext(MasterQueryContext
);
1882 return STATUS_MORE_PROCESSING_REQUIRED
;
1886 DfsFsdCreate(PDEVICE_OBJECT DeviceObject
,
1890 return STATUS_NOT_IMPLEMENTED
;
1894 CreateRedirectedFile(PIRP Irp
,
1895 PFILE_OBJECT FileObject
,
1896 PIO_SECURITY_CONTEXT SecurityContext
)
1905 PMUP_UNC UncProvider
;
1906 PIO_STACK_LOCATION Stack
;
1907 LARGE_INTEGER CurrentTime
;
1908 PMUP_MQC MasterQueryContext
;
1909 PQUERY_PATH_CONTEXT QueryContext
;
1910 PQUERY_PATH_REQUEST QueryPathRequest
;
1911 PUNICODE_PREFIX_TABLE_ENTRY TableEntry
;
1912 BOOLEAN Locked
, Referenced
, BreakOnFirst
;
1914 /* We cannot open a file without a name */
1915 if (FileObject
->FileName
.Length
== 0)
1917 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1918 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1920 return STATUS_INVALID_DEVICE_REQUEST
;
1923 DPRINT1("Request for opening: %wZ\n", &FileObject
->FileName
);
1926 BreakOnFirst
= TRUE
;
1927 Status
= STATUS_BAD_NETWORK_PATH
;
1929 ExAcquireResourceExclusiveLite(&MupPrefixTableLock
, TRUE
);
1930 /* First, try to see if that's a prefix we already know */
1931 TableEntry
= RtlFindUnicodePrefix(&MupPrefixTable
, &FileObject
->FileName
, 1);
1932 if (TableEntry
!= NULL
)
1934 Prefix
= CONTAINING_RECORD(TableEntry
, MUP_PFX
, PrefixTableEntry
);
1936 DPRINT("Matching prefix found: %wZ\n", &Prefix
->AcceptedPrefix
);
1938 /* If so, check whether the prefix is still valid */
1939 KeQuerySystemTime(&CurrentTime
);
1940 if (Prefix
->ValidityTimeout
.QuadPart
< CurrentTime
.QuadPart
)
1942 /* It is: so, update its validity period and reroute file opening */
1943 MupCalculateTimeout(&Prefix
->ValidityTimeout
);
1944 Status
= MupRerouteOpen(FileObject
, Prefix
->UncProvider
);
1945 ExReleaseResourceLite(&MupPrefixTableLock
);
1947 if (Status
== STATUS_REPARSE
)
1949 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1952 Irp
->IoStatus
.Status
= Status
;
1953 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
1958 /* When here, we found a matching prefix, but expired, remove it from the table
1959 * We'll redo a full search
1961 if (Prefix
->InTable
)
1963 MupRemoveKnownPrefixEntry(Prefix
);
1966 ExReleaseResourceLite(&MupPrefixTableLock
);
1968 Stack
= IoGetCurrentIrpStackLocation(Irp
);
1969 /* First of all, start looking for a mailslot */
1970 if (FileObject
->FileName
.Buffer
[0] == L
'\\' && Stack
->MajorFunction
!= IRP_MJ_CREATE
)
1972 Name
= &FileObject
->FileName
.Buffer
[1];
1973 Len
= FileObject
->FileName
.Length
;
1975 /* Skip the remote destination name */
1978 Len
-= sizeof(WCHAR
);
1986 } while (Cur
!= L
'\\');
1987 Len
-= sizeof(WCHAR
);
1989 /* If we still have room for "Mailslot" to fit */
1990 if (Len
>= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)))
1992 /* Get the len in terms of chars count */
1993 Len
/= sizeof(WCHAR
);
1994 if (Len
> ((sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
)))
1996 Len
= (sizeof(L
"Mailslot") - sizeof(UNICODE_NULL
)) / sizeof(WCHAR
);
1999 /* It's indeed a mailslot opening! */
2000 if (_wcsnicmp(Name
, L
"Mailslot", Len
) == 0)
2002 /* Broadcast open */
2003 Status
= BroadcastOpen(Irp
);
2004 if (Status
== STATUS_REPARSE
)
2006 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
2009 Irp
->IoStatus
.Status
= Status
;
2010 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2017 /* Ok, at that point, that's a regular MUP opening (if no DFS) */
2018 if (!MupEnableDfs
|| FileObject
->FsContext2
== DFS_MAGIC_CCB
)
2020 /* We won't complete immediately */
2021 IoMarkIrpPending(Irp
);
2023 /* Allocate a new prefix for our search */
2024 Prefix
= MupAllocatePrefixEntry(0);
2027 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2028 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2030 return STATUS_PENDING
;
2033 /* Allocate a context for our search */
2034 MasterQueryContext
= MupAllocateMasterQueryContext();
2035 if (MasterQueryContext
== NULL
)
2037 MupFreeNode(Prefix
);
2039 Irp
->IoStatus
.Status
= STATUS_INSUFFICIENT_RESOURCES
;
2040 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2042 return STATUS_PENDING
;
2045 MasterQueryContext
->Irp
= Irp
;
2046 MasterQueryContext
->FileObject
= FileObject
;
2047 MasterQueryContext
->LatestProvider
= NULL
;
2048 MasterQueryContext
->Prefix
= Prefix
;
2049 MasterQueryContext
->LatestStatus
= STATUS_BAD_NETWORK_PATH
;
2050 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2051 InsertTailList(&MupMasterQueryList
, &MasterQueryContext
->MQCListEntry
);
2052 ++Prefix
->NodeReferences
;
2053 ExReleaseResourceLite(&MupGlobalLock
);
2057 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2060 /* Now, we will browse all the providers we know, to ask for their accepted prefix regarding the path */
2061 for (Entry
= MupProviderList
.Flink
; Entry
!= &MupProviderList
; Entry
= Entry
->Flink
)
2063 UncProvider
= CONTAINING_RECORD(Entry
, MUP_UNC
, ProviderListEntry
);
2065 ++UncProvider
->NodeReferences
;
2068 ExReleaseResourceLite(&MupGlobalLock
);
2071 /* We will obviously only query registered providers */
2072 if (UncProvider
->Registered
)
2074 /* We will issue an IOCTL_REDIR_QUERY_PATH, so allocate input buffer */
2075 QueryPathRequest
= ExAllocatePoolWithTag(PagedPool
, FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
), TAG_MUP
);
2076 if (QueryPathRequest
== NULL
)
2078 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2081 /* Allocate a context for IRP completion routine
2082 * In case a prefix matches the path, the reroute will happen
2083 * in the completion routine, when we have return from the provider
2085 QueryContext
= ExAllocatePoolWithTag(PagedPool
, sizeof(QUERY_PATH_CONTEXT
), TAG_MUP
);
2086 if (QueryContext
== NULL
)
2088 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2089 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2092 InitializeListHead(&QueryContext
->QueryPathListEntry
);
2093 QueryContext
->MasterQueryContext
= MasterQueryContext
;
2094 QueryContext
->QueryPathRequest
= QueryPathRequest
;
2095 QueryPathRequest
->PathNameLength
= FileObject
->FileName
.Length
;
2096 QueryPathRequest
->SecurityContext
= SecurityContext
;
2097 RtlMoveMemory(QueryPathRequest
->FilePathName
, FileObject
->FileName
.Buffer
, FileObject
->FileName
.Length
);
2099 /* Build our IRP for the query */
2100 QueryIrp
= MupBuildIoControlRequest(UncProvider
->FileObject
,
2102 IRP_MJ_DEVICE_CONTROL
,
2103 IOCTL_REDIR_QUERY_PATH
,
2105 FileObject
->FileName
.Length
+ sizeof(QUERY_PATH_REQUEST
),
2107 sizeof(QUERY_PATH_RESPONSE
),
2108 QueryPathCompletionRoutine
);
2109 if (QueryIrp
== NULL
)
2111 ExFreePoolWithTag(QueryContext
, TAG_MUP
);
2112 ExFreePoolWithTag(QueryPathRequest
, TAG_MUP
);
2113 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
2116 QueryIrp
->RequestorMode
= KernelMode
;
2117 QueryContext
->UncProvider
= UncProvider
;
2118 QueryContext
->Irp
= QueryIrp
;
2120 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2121 ++UncProvider
->NodeReferences
;
2122 ++MasterQueryContext
->NodeReferences
;
2123 ExReleaseResourceLite(&MupGlobalLock
);
2125 ExAcquireResourceExclusiveLite(&MasterQueryContext
->QueryPathListLock
, TRUE
);
2126 InsertTailList(&MasterQueryContext
->QueryPathList
, &QueryContext
->QueryPathListEntry
);
2127 ExReleaseResourceLite(&MasterQueryContext
->QueryPathListLock
);
2129 /* Query the provider !*/
2130 DPRINT1("Requeting UNC provider: %wZ\n", &UncProvider
->DeviceName
);
2131 DPRINT("Calling: %wZ\n", &UncProvider
->DeviceObject
->DriverObject
->DriverName
);
2132 Status
= IoCallDriver(UncProvider
->DeviceObject
, QueryIrp
);
2135 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2138 /* We're done with that provider */
2139 MupDereferenceUncProvider(UncProvider
);
2142 /* If query went fine on the first request, just break and leave */
2143 if (BreakOnFirst
&& Status
== STATUS_SUCCESS
)
2148 BreakOnFirst
= FALSE
;
2153 if (_abnormal_termination())
2155 MasterQueryContext
->LatestStatus
= STATUS_INSUFFICIENT_RESOURCES
;
2160 MupDereferenceUncProvider(UncProvider
);
2165 ExReleaseResourceLite(&MupGlobalLock
);
2168 MupDereferenceMasterQueryContext(MasterQueryContext
);
2170 Status
= STATUS_PENDING
;
2177 Status
= STATUS_NOT_IMPLEMENTED
;
2184 OpenMupFileSystem(PMUP_VCB Vcb
,
2185 PFILE_OBJECT FileObject
,
2186 ACCESS_MASK DesiredAccess
,
2191 DPRINT1("Opening MUP\n");
2193 ExAcquireResourceExclusiveLite(&MupVcbLock
, TRUE
);
2196 /* Update share access, increase reference count, and associated VCB to the FO, that's it! */
2197 Status
= IoCheckShareAccess(DesiredAccess
, ShareAccess
, FileObject
, &Vcb
->ShareAccess
, TRUE
);
2198 if (NT_SUCCESS(Status
))
2200 ++Vcb
->NodeReferences
;
2201 MupSetFileObject(FileObject
, (PMUP_FCB
)Vcb
, NULL
);
2202 Status
= STATUS_SUCCESS
;
2207 ExReleaseResourceLite(&MupVcbLock
);
2216 MupCreate(PDEVICE_OBJECT DeviceObject
,
2220 PIO_STACK_LOCATION Stack
;
2221 PFILE_OBJECT FileObject
, RelatedFileObject
;
2223 FsRtlEnterFileSystem();
2227 /* If DFS is enabled, check if that's for DFS and is so relay */
2228 if (MupEnableDfs
&& (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
))
2230 Status
= DfsFsdCreate(DeviceObject
, Irp
);
2234 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2235 FileObject
= Stack
->FileObject
;
2236 RelatedFileObject
= FileObject
->RelatedFileObject
;
2238 /* If we have a file name or if the associated FCB of the related FO isn't the VCB, then, it's a regular opening */
2239 if (FileObject
->FileName
.Length
!= 0 || (RelatedFileObject
!= NULL
&& ((PMUP_FCB
)(RelatedFileObject
->FsContext
))->NodeType
!= NODE_TYPE_VCB
))
2241 Status
= CreateRedirectedFile(Irp
, FileObject
, Stack
->Parameters
.Create
.SecurityContext
);
2243 /* Otherwise, it's just a volume open */
2246 Status
= OpenMupFileSystem(DeviceObject
->DeviceExtension
,
2248 Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
2249 Stack
->Parameters
.Create
.ShareAccess
);
2251 Irp
->IoStatus
.Information
= FILE_OPENED
;
2252 Irp
->IoStatus
.Status
= Status
;
2253 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2259 Status
= _SEH2_GetExceptionCode();
2261 Irp
->IoStatus
.Status
= Status
;
2262 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2266 FsRtlExitFileSystem();
2272 MupCloseUncProvider(PMUP_UNC UncProvider
)
2274 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2276 /* If the node was still valid, reregister the UNC provider */
2277 if (UncProvider
->NodeStatus
== NODE_STATUS_HEALTHY
)
2279 UncProvider
->NodeStatus
= NODE_STATUS_CLEANUP
;
2280 UncProvider
->Registered
= FALSE
;
2281 ExReleaseResourceLite(&MupGlobalLock
);
2283 if (UncProvider
->FileObject
!= NULL
)
2285 ZwClose(UncProvider
->DeviceHandle
);
2286 ObDereferenceObject(UncProvider
->FileObject
);
2291 ExReleaseResourceLite(&MupGlobalLock
);
2296 DfsFsdCleanup(PDEVICE_OBJECT DeviceObject
,
2300 return STATUS_NOT_IMPLEMENTED
;
2305 MupCleanup(PDEVICE_OBJECT DeviceObject
,
2312 PIO_STACK_LOCATION Stack
;
2314 /* If DFS is enabled, check if that's for DFS and is so relay */
2317 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2319 return DfsFsdCleanup(DeviceObject
, Irp
);
2323 FsRtlEnterFileSystem();
2327 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2328 Type
= MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2332 /* If we got a VCB, clean it up */
2333 MupCleanupVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
);
2335 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2336 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2338 MupDereferenceVcb((PMUP_VCB
)Fcb
);
2340 /* If Ccb is not null, then, it's a UNC provider node */
2343 /* Close it, and dereference */
2344 MupCloseUncProvider((PMUP_UNC
)Ccb
);
2345 MupDereferenceUncProvider((PMUP_UNC
)Ccb
);
2346 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2348 ExReleaseResourceLite(&MupGlobalLock
);
2351 Status
= STATUS_SUCCESS
;
2355 /* If the node wasn't already cleaned, do it */
2356 if (Fcb
->NodeStatus
== NODE_STATUS_HEALTHY
)
2358 MupCleanupFcb(DeviceObject
, Irp
, Fcb
);
2359 Status
= STATUS_SUCCESS
;
2363 Status
= STATUS_INVALID_HANDLE
;
2366 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2367 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2369 MupDereferenceFcb(Fcb
);
2373 Status
= STATUS_INVALID_HANDLE
;
2375 Irp
->IoStatus
.Status
= Status
;
2376 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2381 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2383 Status
= _SEH2_GetExceptionCode();
2387 FsRtlExitFileSystem();
2393 MupCloseVcb(PDEVICE_OBJECT DeviceObject
,
2396 PFILE_OBJECT FileObject
)
2398 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2400 /* Remove FCB, UNC from FO */
2401 MupSetFileObject(FileObject
, NULL
, NULL
);
2402 MupDereferenceVcb(Vcb
);
2404 ExReleaseResourceLite(&MupGlobalLock
);
2406 return STATUS_SUCCESS
;
2410 MupCloseFcb(PDEVICE_OBJECT DeviceObject
,
2413 PFILE_OBJECT FileObject
)
2415 ExAcquireResourceExclusiveLite(&MupGlobalLock
, TRUE
);
2417 /* Remove FCB, CCB from FO */
2418 MupSetFileObject(FileObject
, NULL
, NULL
);
2419 MupDereferenceFcb(Fcb
);
2421 ExReleaseResourceLite(&MupGlobalLock
);
2423 return STATUS_SUCCESS
;
2427 DfsFsdClose(PDEVICE_OBJECT DeviceObject
,
2431 return STATUS_NOT_IMPLEMENTED
;
2436 MupClose(PDEVICE_OBJECT DeviceObject
,
2442 PIO_STACK_LOCATION Stack
;
2444 /* If DFS is enabled, check if that's for DFS and is so relay */
2447 if (DeviceObject
->DeviceType
== FILE_DEVICE_DFS
|| DeviceObject
->DeviceType
== FILE_DEVICE_DFS_FILE_SYSTEM
)
2449 return DfsFsdClose(DeviceObject
, Irp
);
2453 FsRtlEnterFileSystem();
2457 /* Get our internal structures from FO */
2458 Stack
= IoGetCurrentIrpStackLocation(Irp
);
2459 MupDecodeFileObject(Stack
->FileObject
, &Fcb
, &Ccb
);
2462 Status
= STATUS_INVALID_HANDLE
;
2464 Irp
->IoStatus
.Status
= Status
;
2465 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2470 /* If we got the VCB, that's a volume close */
2471 if (Fcb
->NodeType
== NODE_TYPE_VCB
)
2473 Status
= MupCloseVcb(DeviceObject
, Irp
, (PMUP_VCB
)Fcb
, Stack
->FileObject
);
2475 /* Otherwise close the FCB */
2476 else if (Fcb
->NodeType
== NODE_TYPE_FCB
)
2478 MupDereferenceFcb(Fcb
);
2479 Status
= MupCloseFcb(DeviceObject
, Irp
, Fcb
, Stack
->FileObject
);
2483 Status
= STATUS_INVALID_HANDLE
;
2485 Irp
->IoStatus
.Status
= Status
;
2486 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2491 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
2492 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2494 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2496 Status
= _SEH2_GetExceptionCode();
2500 FsRtlExitFileSystem();
2506 DfsUnload(PDRIVER_OBJECT DriverObject
)
2513 MupUnload(PDRIVER_OBJECT DriverObject
)
2515 IoDeleteDevice(mupDeviceObject
);
2519 DfsUnload(DriverObject
);
2522 MupUninitializeData();
2527 DfsDriverEntry(PDRIVER_OBJECT DriverObject
,
2528 PUNICODE_STRING RegistryPath
)
2530 /* We don't support DFS yet, so
2531 * fail to make sure it remains disabled
2534 return STATUS_NOT_IMPLEMENTED
;
2538 * FUNCTION: Called by the system to initialize the driver
2540 * DriverObject = object describing this driver
2541 * RegistryPath = path to our configuration entries
2542 * RETURNS: Success or failure
2547 DriverEntry(PDRIVER_OBJECT DriverObject
,
2548 PUNICODE_STRING RegistryPath
)
2551 UNICODE_STRING MupString
;
2552 PDEVICE_OBJECT DeviceObject
;
2554 /* Only initialize global state of the driver
2555 * Other inits will happen when required
2557 MupInitializeData();
2559 /* Check if DFS is disabled */
2560 MupEnableDfs
= MuppIsDfsEnabled();
2561 /* If it's not disabled but when cannot init, disable it */
2562 if (MupEnableDfs
&& !NT_SUCCESS(DfsDriverEntry(DriverObject
, RegistryPath
)))
2564 MupEnableDfs
= FALSE
;
2567 /* Create the MUP device */
2568 RtlInitUnicodeString(&MupString
, L
"\\Device\\Mup");
2569 Status
= IoCreateDevice(DriverObject
, sizeof(MUP_VCB
), &MupString
, FILE_DEVICE_MULTI_UNC_PROVIDER
, 0, FALSE
, &DeviceObject
);
2570 if (!NT_SUCCESS(Status
))
2574 DfsUnload(DriverObject
);
2577 MupUninitializeData();
2583 DriverObject
->DriverUnload
= MupUnload
;
2584 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = MupCreate
;
2585 DriverObject
->MajorFunction
[IRP_MJ_CREATE_NAMED_PIPE
] = MupCreate
;
2586 DriverObject
->MajorFunction
[IRP_MJ_CREATE_MAILSLOT
] = MupCreate
;
2587 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = MupForwardIoRequest
;
2588 DriverObject
->MajorFunction
[IRP_MJ_FILE_SYSTEM_CONTROL
] = MupFsControl
;
2589 DriverObject
->MajorFunction
[IRP_MJ_CLEANUP
] = MupCleanup
;
2590 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = MupClose
;
2592 /* And finish init */
2593 mupDeviceObject
= DeviceObject
;
2594 MupInitializeVcb(DeviceObject
->DeviceExtension
);
2596 return STATUS_SUCCESS
;