2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/unc.c
5 * PURPOSE: Manages UNC support routines for file system drivers.
6 * PROGRAMMERS: Pierre Schweitzer (pierre@reactos.org)
9 /* INCLUDES ******************************************************************/
15 KSEMAPHORE FsRtlpUncSemaphore
;
17 ULONG FsRtlpRedirs
= 0;
23 UNICODE_STRING RedirectorDeviceName
;
24 BOOLEAN MailslotsSupported
;
28 FsRtlpIsDfsEnabled(VOID
)
33 UNICODE_STRING KeyName
;
34 OBJECT_ATTRIBUTES ObjectAttributes
;
37 KEY_VALUE_PARTIAL_INFORMATION KeyInfo
;
41 /* You recognize MuppIsDfsEnabled()! Congratz :-) */
42 KeyName
.Buffer
= L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup";
43 KeyName
.Length
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup") - sizeof(UNICODE_NULL
);
44 KeyName
.MaximumLength
= sizeof(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
46 /* Simply query registry to get whether DFS is disabled.
47 * If DFS isn't disabled from registry side, assume it is enabled
49 * MUP itself might disable it, but that's not our concern
52 InitializeObjectAttributes(&ObjectAttributes
,
57 Status
= ZwOpenKey(&Key
, KEY_READ
, &ObjectAttributes
);
58 if (!NT_SUCCESS(Status
))
63 KeyName
.Buffer
= L
"DisableDfs";
64 KeyName
.Length
= sizeof(L
"DisableDfs") - sizeof(UNICODE_NULL
);
65 KeyName
.MaximumLength
= sizeof(L
"DisableDfs");
67 Status
= ZwQueryValueKey(Key
, &KeyName
, KeyValuePartialInformation
, &KeyQueryOutput
, sizeof(KeyQueryOutput
), &Length
);
69 if (!NT_SUCCESS(Status
) || KeyQueryOutput
.KeyInfo
.Type
!= REG_DWORD
)
74 return ((ULONG
)KeyQueryOutput
.KeyInfo
.Data
!= 1);
78 FsRtlpOpenDev(OUT PHANDLE DeviceHandle
,
82 UNICODE_STRING StrDeviceName
;
83 IO_STATUS_BLOCK IoStatusBlock
;
84 OBJECT_ATTRIBUTES ObjectAttributes
;
88 /* Just open the device and return the obtained handle */
89 RtlInitUnicodeString(&StrDeviceName
, DeviceName
);
90 InitializeObjectAttributes(&ObjectAttributes
,
95 Status
= ZwCreateFile(DeviceHandle
,
100 FILE_ATTRIBUTE_NORMAL
,
101 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
102 FILE_OPEN
, 0, NULL
, 0);
103 if (NT_SUCCESS(Status
))
105 Status
= IoStatusBlock
.Status
;
108 if (!NT_SUCCESS(Status
))
110 *DeviceHandle
= INVALID_HANDLE_VALUE
;
117 FsRtlpSetSymbolicLink(IN PCUNICODE_STRING DeviceName
)
120 UNICODE_STRING UncDevice
;
124 /* Delete the old link, and set the new one if we have a name */
125 RtlInitUnicodeString(&UncDevice
, L
"\\DosDevices\\UNC");
126 IoDeleteSymbolicLink(&UncDevice
);
127 if (DeviceName
!= NULL
)
129 Status
= IoCreateSymbolicLink(&UncDevice
, (PUNICODE_STRING
)DeviceName
);
130 ASSERT(NT_SUCCESS(Status
));
135 FsRtlpRegisterProviderWithMUP(IN HANDLE MupHandle
,
136 IN PCUNICODE_STRING RedirectorDeviceName
,
137 IN BOOLEAN MailslotsSupported
)
141 IO_STATUS_BLOCK IoStatusBlock
;
142 PMUP_PROVIDER_REGISTRATION_INFO RegistrationInfo
;
146 DPRINT1("FsRtlpRegisterProviderWithMUP(%p, %wZ, %u)\n", (PVOID
)MupHandle
, RedirectorDeviceName
, MailslotsSupported
);
148 /* We have to be able to store the name and the registration information */
149 BufferSize
= RedirectorDeviceName
->Length
+ sizeof(MUP_PROVIDER_REGISTRATION_INFO
);
150 RegistrationInfo
= ExAllocatePoolWithTag(NonPagedPool
, BufferSize
, TAG_UNC
);
151 if (RegistrationInfo
== NULL
)
153 return STATUS_INSUFFICIENT_RESOURCES
;
156 /* Set the information about the provider (including its name) */
157 RegistrationInfo
->RedirectorDeviceNameOffset
= sizeof(MUP_PROVIDER_REGISTRATION_INFO
);
158 RegistrationInfo
->RedirectorDeviceNameLength
= RedirectorDeviceName
->Length
;
159 RegistrationInfo
->MailslotsSupported
= MailslotsSupported
;
160 RtlCopyMemory((PWSTR
)((ULONG_PTR
)RegistrationInfo
+ RegistrationInfo
->RedirectorDeviceNameOffset
),
161 RedirectorDeviceName
->Buffer
, RedirectorDeviceName
->Length
);
163 /* Call MUP with the registration FSCTL */
164 Status
= NtFsControlFile(MupHandle
, NULL
, NULL
, NULL
,
165 &IoStatusBlock
, FSCTL_MUP_REGISTER_PROVIDER
,
166 RegistrationInfo
, BufferSize
, NULL
, 0);
167 if (Status
== STATUS_PENDING
)
169 Status
= NtWaitForSingleObject(MupHandle
, TRUE
, NULL
);
172 if (NT_SUCCESS(Status
))
174 Status
= IoStatusBlock
.Status
;
177 /* And we're done! */
178 ASSERT(NT_SUCCESS(Status
));
179 ExFreePoolWithTag(RegistrationInfo
, TAG_UNC
);
184 /* PUBLIC FUNCTIONS **********************************************************/
187 * @name FsRtlDeregisterUncProvider
202 FsRtlDeregisterUncProvider(IN HANDLE Handle
)
206 /* We won't work on invalid input */
207 if (Handle
== INVALID_HANDLE_VALUE
|| Handle
== 0)
212 KeWaitForSingleObject(&FsRtlpUncSemaphore
, Executive
, KernelMode
, FALSE
, NULL
);
214 /* Sanity check: we need to have providers */
215 ASSERT(FsRtlpRedirs
> 0);
217 /* At that point, we had only one provider at a time */
218 if (Handle
== (HANDLE
)FsRtlpDRD
.NullHandle
)
220 /* Free its name if possible (it might have been overtaken in case of
221 * registration of other UNC provider */
222 if (FsRtlpDRD
.RedirectorDeviceName
.Buffer
!= NULL
)
224 ExFreePoolWithTag(FsRtlpDRD
.RedirectorDeviceName
.Buffer
, TAG_UNC
);
225 FsRtlpDRD
.RedirectorDeviceName
.Buffer
= NULL
;
228 /* Close the handle to MUP */
229 if (FsRtlpDRD
.MupHandle
!= INVALID_HANDLE_VALUE
)
231 ZwClose(FsRtlpDRD
.MupHandle
);
232 FsRtlpDRD
.MupHandle
= INVALID_HANDLE_VALUE
;
235 /* Last handle isn't required anymore */
236 FsRtlpDRD
.NullHandle
= INVALID_HANDLE_VALUE
;
239 /* One less provider */
242 /* In case we reach no provider anylonger, reset the symbolic link */
243 if (FsRtlpRedirs
== 0)
245 FsRtlpSetSymbolicLink(NULL
);
248 KeReleaseSemaphore(&FsRtlpUncSemaphore
, IO_NO_INCREMENT
, 1, FALSE
);
251 * NULL device handle and 'normal' MUP device handle are not closed by
252 * FsRtl. It's up to the user to close them afterwards.
253 * If the handle is leaked, MUP will never be notified about the
259 * @name FsRtlRegisterUncProvider
267 * @param RedirectorDeviceName
270 * @param MailslotsSupported
280 FsRtlRegisterUncProvider(OUT PHANDLE Handle
,
281 IN PCUNICODE_STRING RedirectorDeviceName
,
282 IN BOOLEAN MailslotsSupported
)
286 UNICODE_STRING MupString
;
290 DPRINT1("FsRtlRegisterUncProvider(%p, %wZ, %u)\n", Handle
, RedirectorDeviceName
, MailslotsSupported
);
292 KeWaitForSingleObject(&FsRtlpUncSemaphore
, Executive
, KernelMode
, FALSE
, NULL
);
294 /* In case no provider was registered yet, check for DFS present.
295 * If DFS is present, we need to go with MUP, whatever the case
297 if (FsRtlpRedirs
== 0)
299 if (FsRtlpIsDfsEnabled())
301 DPRINT1("DFS is not disabled. Going through MUP\n");
303 /* We've to go with MUP, make sure our internal structure doesn't
304 * contain any leftover data and raise redirs to one, to make sure
307 RtlZeroMemory(&FsRtlpDRD
, sizeof(FsRtlpDRD
));
312 /* In case no UNC provider was already registered,
313 * We'll proceed without MUP and directly redirect
314 * UNC to the provider.
316 if (FsRtlpRedirs
== 0)
318 /* As we don't provide MUP, just give a handle to NULL device */
319 Status
= FsRtlpOpenDev(&DeviceHandle
, L
"\\Device\\Null");
320 if (!NT_SUCCESS(Status
))
325 /* Allocate a buffer big enough to keep a local copy of UNC provider device */
326 FsRtlpDRD
.RedirectorDeviceName
.Buffer
= ExAllocatePoolWithTag(NonPagedPool
, RedirectorDeviceName
->MaximumLength
, TAG_UNC
);
327 if (FsRtlpDRD
.RedirectorDeviceName
.Buffer
== NULL
)
329 Status
= STATUS_INSUFFICIENT_RESOURCES
;
333 FsRtlpDRD
.RedirectorDeviceName
.Length
= RedirectorDeviceName
->Length
;
334 FsRtlpDRD
.RedirectorDeviceName
.MaximumLength
= RedirectorDeviceName
->MaximumLength
;
335 RtlCopyMemory(FsRtlpDRD
.RedirectorDeviceName
.Buffer
, RedirectorDeviceName
->Buffer
, RedirectorDeviceName
->MaximumLength
);
337 /* We don't have MUP, and copy provider information */
338 FsRtlpDRD
.MupHandle
= INVALID_HANDLE_VALUE
;
339 FsRtlpDRD
.MailslotsSupported
= MailslotsSupported
;
340 FsRtlpDRD
.NullHandle
= DeviceHandle
;
342 /* Set DOS device UNC to use provider device */
343 FsRtlpSetSymbolicLink(RedirectorDeviceName
);
347 /* We (will) have several providers, MUP is required */
348 Status
= FsRtlpOpenDev(&DeviceHandle
, L
"\\Device\\Mup");
349 if (!NT_SUCCESS(Status
))
351 /* Opening MUP may have failed because the driver was not loaded, so load it and retry */
352 RtlInitUnicodeString(&MupString
, L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Mup");
353 ZwLoadDriver(&MupString
);
354 Status
= FsRtlpOpenDev(&DeviceHandle
, L
"\\Device\\Mup");
355 if (!NT_SUCCESS(Status
))
361 /* In case we had a single provider till now, we have to forward the old provider to MUP
362 * And then, register the new one to MUP as well
364 if (FsRtlpDRD
.RedirectorDeviceName
.Buffer
!= NULL
)
366 /* We will only continue if we can register previous provider in MUP */
367 Status
= FsRtlpRegisterProviderWithMUP(DeviceHandle
, &FsRtlpDRD
.RedirectorDeviceName
, FsRtlpDRD
.MailslotsSupported
);
368 if (!NT_SUCCESS(Status
))
373 /* Save our Mup handle for later usage */
374 FsRtlpDRD
.MupHandle
= DeviceHandle
;
376 /* Release information about previous provider */
377 ExFreePoolWithTag(FsRtlpDRD
.RedirectorDeviceName
.Buffer
, TAG_UNC
);
378 FsRtlpDRD
.RedirectorDeviceName
.Buffer
= NULL
;
380 /* Re-open MUP to have a handle to give back to the user */
381 Status
= FsRtlpOpenDev(&DeviceHandle
, L
"\\Device\\Mup");
382 if (!NT_SUCCESS(Status
))
388 /* Redirect UNC DOS device to MUP */
389 RtlInitUnicodeString(&MupString
, L
"\\Device\\Mup");
390 FsRtlpSetSymbolicLink(&MupString
);
392 /* Register new provider */
393 Status
= FsRtlpRegisterProviderWithMUP(DeviceHandle
, RedirectorDeviceName
, MailslotsSupported
);
398 /* In case of success, increment number of providers and return handle
399 * to the device pointed by UNC DOS device
401 if (NT_SUCCESS(Status
))
404 *Handle
= DeviceHandle
;
408 /* Cleanup in case of failure */
409 if (DeviceHandle
!= INVALID_HANDLE_VALUE
&& DeviceHandle
!= 0)
411 ZwClose(DeviceHandle
);
414 *Handle
= INVALID_HANDLE_VALUE
;
417 KeReleaseSemaphore(&FsRtlpUncSemaphore
, IO_NO_INCREMENT
, 1, FALSE
);