[THEMES]
[reactos.git] / reactos / drivers / filters / mountmgr / device.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2011-2012 ReactOS Team
4 *
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.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/mountmgr/device.c
22 * PURPOSE: Mount Manager - Device Control
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #include "mntmgr.h"
29
30 #define MAX_DEVICES 0x3E8 /* Matches 1000 devices */
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /*
36 * @implemented
37 */
38 NTSTATUS
39 MountMgrChangeNotify(IN PDEVICE_EXTENSION DeviceExtension,
40 IN PIRP Irp)
41 {
42 KIRQL OldIrql;
43 NTSTATUS Status;
44 PIO_STACK_LOCATION Stack;
45 PMOUNTMGR_CHANGE_NOTIFY_INFO ChangeNotify;
46
47 /* Get the I/O buffer */
48 Stack = IoGetCurrentIrpStackLocation(Irp);
49 ChangeNotify = (PMOUNTMGR_CHANGE_NOTIFY_INFO)Irp->AssociatedIrp.SystemBuffer;
50
51 /* Validate it */
52 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO) ||
53 Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO))
54 {
55 return STATUS_INVALID_PARAMETER;
56 }
57
58 /* If epic number doesn't match, just return now one */
59 if (DeviceExtension->EpicNumber != ChangeNotify->EpicNumber)
60 {
61 ChangeNotify->EpicNumber = DeviceExtension->EpicNumber;
62 Irp->IoStatus.Information = 0;
63 return STATUS_SUCCESS;
64 }
65
66 /* If IRP is to be canceled, forget about that */
67 IoAcquireCancelSpinLock(&OldIrql);
68 if (Irp->Cancel)
69 {
70 Status = STATUS_CANCELLED;
71 }
72 /* Otherwise queue the IRP to be notified with the next epic number change */
73 else
74 {
75 InsertTailList(&(DeviceExtension->IrpListHead), &(Irp->Tail.Overlay.ListEntry));
76 IoMarkIrpPending(Irp);
77 IoSetCancelRoutine(Irp, MountMgrCancel);
78 Status = STATUS_PENDING;
79 }
80 IoReleaseCancelSpinLock(OldIrql);
81
82 return Status;
83 }
84
85 /*
86 * @implemented
87 */
88 NTSTATUS
89 MountmgrWriteNoAutoMount(IN PDEVICE_EXTENSION DeviceExtension)
90 {
91 ULONG Value = DeviceExtension->NoAutoMount;
92
93 return RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
94 DeviceExtension->RegistryPath.Buffer,
95 L"NoAutoMount",
96 REG_DWORD,
97 &Value,
98 sizeof(Value));
99
100 }
101
102 /*
103 * @implemented
104 */
105 NTSTATUS
106 MountMgrSetAutoMount(IN PDEVICE_EXTENSION DeviceExtension,
107 IN PIRP Irp)
108 {
109 PIO_STACK_LOCATION Stack;
110 PMOUNTMGR_SET_AUTO_MOUNT SetState;
111
112 Stack = IoGetCurrentIrpStackLocation(Irp);
113
114 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_SET_AUTO_MOUNT))
115 {
116 Irp->IoStatus.Information = 0;
117 return STATUS_INVALID_PARAMETER;
118 }
119
120 /* Only change if there's a real difference */
121 SetState = (PMOUNTMGR_SET_AUTO_MOUNT)Irp->AssociatedIrp.SystemBuffer;
122 if (SetState->NewState == !DeviceExtension->NoAutoMount)
123 {
124 Irp->IoStatus.Information = 0;
125 return STATUS_SUCCESS;
126 }
127
128 /* Set new state; ! on purpose */
129 DeviceExtension->NoAutoMount = !SetState->NewState;
130 Irp->IoStatus.Information = 0;
131 return MountmgrWriteNoAutoMount(DeviceExtension);
132 }
133
134 /*
135 * @implemented
136 */
137 NTSTATUS
138 MountMgrQueryAutoMount(IN PDEVICE_EXTENSION DeviceExtension,
139 IN PIRP Irp)
140 {
141 PIO_STACK_LOCATION Stack;
142 PMOUNTMGR_QUERY_AUTO_MOUNT QueryState;
143
144 Stack = IoGetCurrentIrpStackLocation(Irp);
145
146 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_QUERY_AUTO_MOUNT))
147 {
148 Irp->IoStatus.Information = 0;
149 return STATUS_INVALID_PARAMETER;
150 }
151
152 QueryState = (PMOUNTMGR_QUERY_AUTO_MOUNT)Irp->AssociatedIrp.SystemBuffer;
153 QueryState->CurrentState = !DeviceExtension->NoAutoMount;
154 Irp->IoStatus.Information = sizeof(MOUNTMGR_QUERY_AUTO_MOUNT);
155
156 return STATUS_SUCCESS;
157 }
158
159 /*
160 * @implemented
161 */
162 NTSTATUS
163 NTAPI
164 ScrubRegistryRoutine(IN PWSTR ValueName,
165 IN ULONG ValueType,
166 IN PVOID ValueData,
167 IN ULONG ValueLength,
168 IN PVOID Context,
169 IN PVOID EntryContext)
170 {
171 NTSTATUS Status;
172 PLIST_ENTRY NextEntry;
173 PDEVICE_INFORMATION DeviceInfo;
174 PBOOLEAN Continue = EntryContext;
175 PDEVICE_EXTENSION DeviceExtension = Context;
176
177 if (ValueType != REG_BINARY)
178 {
179 return STATUS_SUCCESS;
180 }
181
182 /* Delete values for devices that don't have the matching unique ID */
183 if (!IsListEmpty(&(DeviceExtension->DeviceListHead)))
184 {
185 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
186 NextEntry != &(DeviceExtension->DeviceListHead);
187 NextEntry = NextEntry->Flink)
188 {
189 DeviceInfo = CONTAINING_RECORD(NextEntry,
190 DEVICE_INFORMATION,
191 DeviceListEntry);
192
193 if (!DeviceInfo->UniqueId || DeviceInfo->UniqueId->UniqueIdLength != ValueLength)
194 {
195 continue;
196 }
197
198 if (RtlCompareMemory(DeviceInfo->UniqueId->UniqueId, ValueData, ValueLength) == ValueLength)
199 {
200 return STATUS_SUCCESS;
201 }
202 }
203 }
204
205 /* Wrong unique ID, scrub it */
206 Status = RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE,
207 DatabasePath,
208 ValueName);
209 if (!NT_SUCCESS(Status))
210 {
211 *Continue = TRUE;
212 return STATUS_UNSUCCESSFUL;
213 }
214
215 *Continue = FALSE;
216 return Status;
217 }
218
219 /*
220 * @implemented
221 */
222 NTSTATUS
223 MountMgrScrubRegistry(IN PDEVICE_EXTENSION DeviceExtension)
224 {
225 NTSTATUS Status;
226 BOOLEAN Continue;
227 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
228
229 do
230 {
231 RtlZeroMemory(QueryTable, sizeof(QueryTable));
232 QueryTable[0].QueryRoutine = ScrubRegistryRoutine;
233 QueryTable[0].EntryContext = &Continue;
234 Continue = FALSE;
235
236 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
237 DatabasePath,
238 QueryTable,
239 DeviceExtension,
240 NULL);
241 }
242 while (Continue);
243
244 return Status;
245 }
246
247 /*
248 * @implemented
249 */
250 NTSTATUS
251 MountMgrCreatePoint(IN PDEVICE_EXTENSION DeviceExtension,
252 IN PIRP Irp)
253 {
254 ULONG MaxLength;
255 PIO_STACK_LOCATION Stack;
256 PMOUNTMGR_CREATE_POINT_INPUT Point;
257 UNICODE_STRING DeviceName, SymbolicName;
258
259 Stack = IoGetCurrentIrpStackLocation(Irp);
260
261 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_CREATE_POINT_INPUT))
262 {
263 return STATUS_INVALID_PARAMETER;
264 }
265
266 Point = (PMOUNTMGR_CREATE_POINT_INPUT)Irp->AssociatedIrp.SystemBuffer;
267
268 MaxLength = MAX((Point->DeviceNameOffset + Point->DeviceNameLength),
269 (Point->SymbolicLinkNameLength + Point->SymbolicLinkNameOffset));
270 if (MaxLength >= Stack->Parameters.DeviceIoControl.InputBufferLength)
271 {
272 return STATUS_INVALID_PARAMETER;
273 }
274
275 /* Get all the strings and call the worker */
276 SymbolicName.Length = Point->SymbolicLinkNameLength;
277 SymbolicName.MaximumLength = Point->SymbolicLinkNameLength;
278 DeviceName.Length = Point->DeviceNameLength;
279 DeviceName.MaximumLength = Point->DeviceNameLength;
280 SymbolicName.Buffer = (PVOID)((ULONG_PTR)Point + Point->SymbolicLinkNameOffset);
281 DeviceName.Buffer = (PVOID)((ULONG_PTR)Point + Point->DeviceNameOffset);
282
283 return MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &DeviceName);
284 }
285
286 /*
287 * @implemented
288 */
289 NTSTATUS
290 MountMgrCheckUnprocessedVolumes(IN PDEVICE_EXTENSION DeviceExtension,
291 IN PIRP Irp)
292 {
293 PLIST_ENTRY NextEntry;
294 PDEVICE_INFORMATION DeviceInformation;
295 NTSTATUS ArrivalStatus, Status = STATUS_SUCCESS;
296
297 UNREFERENCED_PARAMETER(Irp);
298
299 /* No offline volumes, nothing more to do */
300 if (IsListEmpty(&(DeviceExtension->OfflineDeviceListHead)))
301 {
302 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
303 return STATUS_SUCCESS;
304 }
305
306 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
307
308 /* Reactivate all the offline volumes */
309 while (!IsListEmpty(&(DeviceExtension->OfflineDeviceListHead)))
310 {
311 NextEntry = RemoveHeadList(&(DeviceExtension->OfflineDeviceListHead));
312 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
313
314 ArrivalStatus = MountMgrMountedDeviceArrival(DeviceExtension,
315 &(DeviceInformation->SymbolicName),
316 DeviceInformation->Volume);
317 /* Then, remove them dead information */
318 MountMgrFreeDeadDeviceInfo(DeviceInformation);
319
320 if (NT_SUCCESS(Status))
321 {
322 Status = ArrivalStatus;
323 }
324 }
325
326 return Status;
327 }
328
329 /*
330 * @implemented
331 */
332 BOOLEAN
333 IsFtVolume(IN PUNICODE_STRING SymbolicName)
334 {
335 PIRP Irp;
336 KEVENT Event;
337 NTSTATUS Status;
338 PFILE_OBJECT FileObject;
339 IO_STATUS_BLOCK IoStatusBlock;
340 PARTITION_INFORMATION PartitionInfo;
341 PDEVICE_OBJECT DeviceObject, FileDeviceObject;
342
343 /* Get device object */
344 Status = IoGetDeviceObjectPointer(SymbolicName,
345 FILE_READ_ATTRIBUTES,
346 &FileObject,
347 &DeviceObject);
348 if (!NT_SUCCESS(Status))
349 {
350 return FALSE;
351 }
352
353 /* Get attached device */
354 FileDeviceObject = FileObject->DeviceObject;
355 DeviceObject = IoGetAttachedDeviceReference(FileDeviceObject);
356
357 /* FT volume can't be removable */
358 if (FileDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
359 {
360 ObDereferenceObject(DeviceObject);
361 ObDereferenceObject(FileObject);
362 return FALSE;
363 }
364
365 ObDereferenceObject(FileObject);
366
367 /* Get partition information */
368 KeInitializeEvent(&Event, NotificationEvent, FALSE);
369 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
370 DeviceObject,
371 NULL,
372 0,
373 &PartitionInfo,
374 sizeof(PartitionInfo),
375 FALSE,
376 &Event,
377 &IoStatusBlock);
378 if (!Irp)
379 {
380 ObDereferenceObject(DeviceObject);
381 return FALSE;
382 }
383
384 Status = IoCallDriver(DeviceObject, Irp);
385 if (Status == STATUS_PENDING)
386 {
387 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
388 Status = IoStatusBlock.Status;
389 }
390
391 ObDereferenceObject(DeviceObject);
392 if (!NT_SUCCESS(Status))
393 {
394 return FALSE;
395 }
396
397 /* Check if this is a FT volume */
398 return IsRecognizedPartition(PartitionInfo.PartitionType);
399 }
400
401 /*
402 * @implemented
403 */
404 VOID
405 ProcessSuggestedDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)
406 {
407 WCHAR NameBuffer[DRIVE_LETTER_LENGTH / sizeof(WCHAR)];
408 PLIST_ENTRY NextEntry;
409 UNICODE_STRING SymbolicName;
410 PDEVICE_INFORMATION DeviceInformation;
411
412 /* No devices? Nothing to do! */
413 if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
414 {
415 return;
416 }
417
418 /* For all the devices */
419 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
420 NextEntry != &(DeviceExtension->DeviceListHead);
421 NextEntry = NextEntry->Flink)
422 {
423 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
424
425 /* If no drive letter */
426 if (DeviceInformation->SuggestedDriveLetter == (UCHAR)-1)
427 {
428 /* Ensure it has no entry yet */
429 if (!HasDriveLetter(DeviceInformation) &&
430 !HasNoDriveLetterEntry(DeviceInformation->UniqueId))
431 {
432 /* And create one */
433 CreateNoDriveLetterEntry(DeviceInformation->UniqueId);
434 }
435
436 DeviceInformation->SuggestedDriveLetter = 0;
437 }
438 /* Suggested letter & no entry */
439 else if (DeviceInformation->SuggestedDriveLetter &&
440 !HasNoDriveLetterEntry(DeviceInformation->UniqueId))
441 {
442 /* Just create a mount point */
443 SymbolicName.Buffer = NameBuffer;
444 RtlCopyMemory(NameBuffer, DosDevices.Buffer, DosDevices.Length);
445 NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter;
446 NameBuffer[COLON_POSITION] = L':';
447 SymbolicName.Length =
448 SymbolicName.MaximumLength = DRIVE_LETTER_LENGTH;
449
450 MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &(DeviceInformation->DeviceName));
451 }
452 }
453 }
454
455 /*
456 * @implemented
457 */
458 NTSTATUS
459 MountMgrNextDriveLetterWorker(IN PDEVICE_EXTENSION DeviceExtension,
460 IN PUNICODE_STRING DeviceName,
461 OUT PMOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInfo)
462 {
463 NTSTATUS Status;
464 UCHAR DriveLetter;
465 PLIST_ENTRY NextEntry;
466 PMOUNTDEV_UNIQUE_ID UniqueId;
467 BOOLEAN Removable, GptDriveLetter;
468 PDEVICE_INFORMATION DeviceInformation;
469 WCHAR NameBuffer[DRIVE_LETTER_LENGTH];
470 PSYMLINK_INFORMATION SymlinkInformation;
471 UNICODE_STRING TargetDeviceName, SymbolicName;
472
473 /* First, process suggested letters */
474 if (!DeviceExtension->ProcessedSuggestions)
475 {
476 ProcessSuggestedDriveLetters(DeviceExtension);
477 DeviceExtension->ProcessedSuggestions = TRUE;
478 }
479
480 /* Then, get information about the device */
481 Status = QueryDeviceInformation(DeviceName, &TargetDeviceName, NULL, &Removable, &GptDriveLetter, NULL, NULL, NULL);
482 if (!NT_SUCCESS(Status))
483 {
484 return Status;
485 }
486
487 /* Ensure we have such device */
488 NextEntry = DeviceExtension->DeviceListHead.Flink;
489 while (NextEntry != &(DeviceExtension->DeviceListHead))
490 {
491 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
492
493 if (RtlCompareUnicodeString(&(DeviceInformation->DeviceName), &TargetDeviceName, TRUE) == 0)
494 {
495 break;
496 }
497
498 NextEntry = NextEntry->Flink;
499 }
500
501 if (NextEntry == &(DeviceExtension->DeviceListHead))
502 {
503 FreePool(TargetDeviceName.Buffer);
504 return STATUS_OBJECT_NAME_NOT_FOUND;
505 }
506
507 /* Now, mark we have assigned a letter (assumption) */
508 DeviceInformation->LetterAssigned =
509 DriveLetterInfo->DriveLetterWasAssigned = TRUE;
510
511 /* Browse all the symlink to see if there's already a drive letter */
512 NextEntry = DeviceInformation->SymbolicLinksListHead.Flink;
513 while (NextEntry != &(DeviceInformation->SymbolicLinksListHead))
514 {
515 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
516
517 /* This is a driver letter & online one, forget about new drive eltter */
518 if (IsDriveLetter(&(SymlinkInformation->Name)) && SymlinkInformation->Online)
519 {
520 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
521 DriveLetterInfo->CurrentDriveLetter = (CHAR)SymlinkInformation->Name.Buffer[LETTER_POSITION];
522 break;
523 }
524
525 NextEntry = NextEntry->Flink;
526 }
527
528 /* If we didn't find a drive letter online
529 * ensure there's no GPT drive letter nor no drive entry
530 */
531 if (NextEntry == &(DeviceInformation->SymbolicLinksListHead))
532 {
533 if (GptDriveLetter || HasNoDriveLetterEntry(DeviceInformation->UniqueId))
534 {
535 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
536 DriveLetterInfo->CurrentDriveLetter = 0;
537
538 goto Release;
539 }
540 }
541
542 /* No, ensure that the device is not automonted nor removable */
543 if (!DeviceExtension->NoAutoMount && !Removable)
544 {
545 if (DriveLetterInfo->DriveLetterWasAssigned)
546 {
547 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
548 DriveLetterInfo->CurrentDriveLetter = 0;
549
550 goto Release;
551 }
552 }
553
554 if (!DriveLetterInfo->DriveLetterWasAssigned)
555 {
556 goto Release;
557 }
558
559 /* Now everything is fine, start processing */
560
561 if (RtlPrefixUnicodeString(&DeviceFloppy, &TargetDeviceName, TRUE))
562 {
563 /* If the device is a floppy, start with letter A */
564 DriveLetter = 'A';
565 }
566 else if (RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE))
567 {
568 /* If the device is a CD-ROM, start with letter D */
569 DriveLetter = 'D';
570 }
571 else
572 {
573 /* Finally, if it's a disk, use C */
574 DriveLetter = 'C';
575 }
576
577 /* We cannot set NO drive letter */
578 ASSERT(DeviceInformation->SuggestedDriveLetter != (UCHAR)-1);
579
580 /* If we don't have suggested letter but it's a FT volume, fail */
581 if (!DeviceInformation->SuggestedDriveLetter && IsFtVolume(&(DeviceInformation->DeviceName)))
582 {
583 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
584 DriveLetterInfo->CurrentDriveLetter = 0;
585
586 goto Release;
587 }
588
589 /* Prepare buffer */
590 RtlCopyMemory(NameBuffer, DosDevices.Buffer, DosDevices.Length);
591 NameBuffer[COLON_POSITION] = L':';
592 SymbolicName.Buffer = NameBuffer;
593 SymbolicName.Length =
594 SymbolicName.MaximumLength = DRIVE_LETTER_LENGTH;
595
596 /* It's all prepared, create mount point */
597 if (DeviceInformation->SuggestedDriveLetter)
598 {
599 DriveLetterInfo->CurrentDriveLetter = DeviceInformation->SuggestedDriveLetter;
600 NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter;
601
602 Status = MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &TargetDeviceName);
603 if (NT_SUCCESS(Status))
604 {
605 goto Release;
606 }
607 }
608
609 /* It failed with this letter... Try another one! */
610 for (DriveLetterInfo->CurrentDriveLetter = DriveLetter;
611 DriveLetterInfo->CurrentDriveLetter <= L'Z';
612 DriveLetterInfo->CurrentDriveLetter++)
613 {
614 NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter;
615
616 Status = MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &TargetDeviceName);
617 if (NT_SUCCESS(Status))
618 {
619 break;
620 }
621 }
622
623 /* We failed setting a letter */
624 if (DriveLetterInfo->CurrentDriveLetter > L'Z')
625 {
626 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
627 DriveLetterInfo->CurrentDriveLetter = 0;
628
629 /* Try at least to add a no drive letter entry */
630 Status = QueryDeviceInformation(&TargetDeviceName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL);
631 if (NT_SUCCESS(Status))
632 {
633 CreateNoDriveLetterEntry(UniqueId);
634 FreePool(UniqueId);
635 }
636 }
637
638 Release:
639 FreePool(TargetDeviceName.Buffer);
640
641 return STATUS_SUCCESS;
642 }
643
644
645 /*
646 * @implemented
647 */
648 NTSTATUS
649 MountMgrNextDriveLetter(IN PDEVICE_EXTENSION DeviceExtension,
650 IN PIRP Irp)
651 {
652 NTSTATUS Status;
653 PIO_STACK_LOCATION Stack;
654 UNICODE_STRING DeviceName;
655 PMOUNTMGR_DRIVE_LETTER_TARGET DriveLetterTarget;
656 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
657
658 Stack = IoGetNextIrpStackLocation(Irp);
659
660 /* Validate input */
661 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) ||
662 Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION))
663 {
664 return STATUS_INVALID_PARAMETER;
665 }
666
667 DriveLetterTarget = (PMOUNTMGR_DRIVE_LETTER_TARGET)Irp->AssociatedIrp.SystemBuffer;
668 if (DriveLetterTarget->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
669 {
670 return STATUS_INVALID_PARAMETER;
671 }
672
673 /* Call the worker */
674 DeviceName.Buffer = DriveLetterTarget->DeviceName;
675 DeviceName.Length =
676 DeviceName.MaximumLength = DriveLetterTarget->DeviceNameLength;
677
678 Status = MountMgrNextDriveLetterWorker(DeviceExtension, &DeviceName,
679 &DriveLetterInformation);
680 if (NT_SUCCESS(Status))
681 {
682 *(PMOUNTMGR_DRIVE_LETTER_INFORMATION)Irp->AssociatedIrp.SystemBuffer =
683 DriveLetterInformation;
684 Irp->IoStatus.Information = sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION);
685 }
686
687 return Status;
688 }
689
690 /*
691 * @implemented
692 */
693 NTSTATUS
694 NTAPI
695 MountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName,
696 IN ULONG ValueType,
697 IN PVOID ValueData,
698 IN ULONG ValueLength,
699 IN PVOID Context,
700 IN PVOID EntryContext)
701 {
702 UNICODE_STRING ValueString;
703 PUNICODE_STRING SystemVolumeName;
704
705 UNREFERENCED_PARAMETER(ValueName);
706 UNREFERENCED_PARAMETER(ValueLength);
707 UNREFERENCED_PARAMETER(EntryContext);
708
709 if (ValueType != REG_SZ)
710 {
711 return STATUS_SUCCESS;
712 }
713
714 RtlInitUnicodeString(&ValueString, ValueData);
715 SystemVolumeName = Context;
716
717 /* Return a string containing system volume name */
718 SystemVolumeName->Length = ValueString.Length;
719 SystemVolumeName->MaximumLength = ValueString.Length + sizeof(WCHAR);
720 SystemVolumeName->Buffer = AllocatePool(SystemVolumeName->MaximumLength);
721 if (SystemVolumeName->Buffer)
722 {
723 RtlCopyMemory(SystemVolumeName->Buffer, ValueData, ValueString.Length);
724 SystemVolumeName->Buffer[ValueString.Length / sizeof(WCHAR)] = UNICODE_NULL;
725 }
726
727 return STATUS_SUCCESS;
728
729 }
730
731 /*
732 * @implemented
733 */
734 NTSTATUS
735 MountMgrQuerySystemVolumeName(OUT PUNICODE_STRING SystemVolumeName)
736 {
737 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
738
739 RtlZeroMemory(QueryTable, sizeof(QueryTable));
740 QueryTable[0].QueryRoutine = MountMgrQuerySystemVolumeNameQueryRoutine;
741 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
742 QueryTable[0].Name = L"SystemPartition";
743
744 SystemVolumeName->Buffer = NULL;
745
746 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
747 L"\\Registry\\Machine\\System\\Setup",
748 QueryTable,
749 SystemVolumeName,
750 NULL);
751
752 if (SystemVolumeName->Buffer)
753 {
754 return STATUS_SUCCESS;
755 }
756
757 return STATUS_UNSUCCESSFUL;
758 }
759
760 /*
761 * @implemented
762 */
763 VOID
764 MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)
765 {
766 NTSTATUS Status;
767 PLIST_ENTRY NextEntry;
768 UNICODE_STRING SystemVolumeName;
769 PDEVICE_INFORMATION DeviceInformation;
770 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
771
772 /* First, get system volume name */
773 Status = MountMgrQuerySystemVolumeName(&SystemVolumeName);
774
775 /* If there are no device, it's all done */
776 if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
777 {
778 if (NT_SUCCESS(Status))
779 {
780 FreePool(SystemVolumeName.Buffer);
781 }
782
783 return;
784 }
785
786 /* Now, for all the devices... */
787 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
788 NextEntry != &(DeviceExtension->DeviceListHead);
789 NextEntry = NextEntry->Flink)
790 {
791 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
792
793 /* If the device doesn't have a letter assigned, do it! */
794 if (!DeviceInformation->LetterAssigned)
795 {
796 MountMgrNextDriveLetterWorker(DeviceExtension,
797 &(DeviceInformation->DeviceName),
798 &DriveLetterInformation);
799 }
800
801 /* If it was the system volume */
802 if (NT_SUCCESS(Status) && RtlEqualUnicodeString(&SystemVolumeName, &(DeviceInformation->DeviceName), TRUE))
803 {
804 /* Keep track of it */
805 DeviceExtension->DriveLetterData = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength +
806 sizeof(MOUNTDEV_UNIQUE_ID));
807 if (DeviceExtension->DriveLetterData)
808 {
809 RtlCopyMemory(DeviceExtension->DriveLetterData,
810 DeviceInformation->UniqueId,
811 DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
812 }
813
814 /* If it was not automount, ensure it gets mounted */
815 if (!DeviceExtension->NoAutoMount)
816 {
817 DeviceExtension->NoAutoMount = TRUE;
818
819 MountMgrNextDriveLetterWorker(DeviceExtension,
820 &(DeviceInformation->DeviceName),
821 &DriveLetterInformation);
822
823 DeviceExtension->NoAutoMount = FALSE;
824 }
825 }
826 }
827
828 if (NT_SUCCESS(Status))
829 {
830 FreePool(SystemVolumeName.Buffer);
831 }
832 }
833
834 NTSTATUS
835 MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,
836 IN PIRP Irp)
837 {
838 NTSTATUS Status;
839 ULONG DevicesFound;
840 PIO_STACK_LOCATION Stack;
841 PLIST_ENTRY SymlinksEntry;
842 UNICODE_STRING SymbolicName;
843 PMOUNTMGR_TARGET_NAME Target;
844 PWSTR DeviceString, OldBuffer;
845 USHORT DeviceLength, OldLength;
846 PDEVICE_INFORMATION DeviceInformation;
847 PSYMLINK_INFORMATION SymlinkInformation;
848 PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
849
850 Stack = IoGetNextIrpStackLocation(Irp);
851
852 /* Validate input size */
853 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
854 {
855 return STATUS_INVALID_PARAMETER;
856 }
857
858 /* Ensure we have received UNICODE_STRING */
859 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
860 if (Target->DeviceNameLength & 1)
861 {
862 return STATUS_INVALID_PARAMETER;
863 }
864
865 /* Validate the entry structure size */
866 if (Target->DeviceNameLength + sizeof(UNICODE_NULL) > Stack->Parameters.DeviceIoControl.InputBufferLength)
867 {
868 return STATUS_INVALID_PARAMETER;
869 }
870
871 /* Ensure we can at least return needed size */
872 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
873 {
874 return STATUS_INVALID_PARAMETER;
875 }
876
877 /* Construct string for query */
878 SymbolicName.Length = Target->DeviceNameLength;
879 SymbolicName.MaximumLength = Target->DeviceNameLength + sizeof(UNICODE_NULL);
880 SymbolicName.Buffer = Target->DeviceName;
881
882 /* Find device with our info */
883 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
884 if (!NT_SUCCESS(Status))
885 {
886 return Status;
887 }
888
889 DeviceLength = 0;
890 DeviceString = NULL;
891 DevicesFound = 0;
892
893 /* Try to find associated device info */
894 while (TRUE)
895 {
896 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
897 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
898 SymlinksEntry = SymlinksEntry->Flink)
899 {
900 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
901
902 /* Try to find with drive letter */
903 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online)
904 {
905 break;
906 }
907 }
908
909 /* We didn't find, break */
910 if (SymlinksEntry == &(DeviceInformation->SymbolicLinksListHead))
911 {
912 break;
913 }
914
915 /* It doesn't have associated device, go to fallback method */
916 if (IsListEmpty(&DeviceInformation->AssociatedDevicesHead))
917 {
918 goto TryWithVolumeName;
919 }
920
921 /* Create a string with the information about the device */
922 AssociatedDevice = CONTAINING_RECORD(&(DeviceInformation->SymbolicLinksListHead), ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
923 OldLength = DeviceLength;
924 OldBuffer = DeviceString;
925 DeviceLength += AssociatedDevice->String.Length;
926 DeviceString = AllocatePool(DeviceLength);
927 if (!DeviceString)
928 {
929 if (OldBuffer)
930 {
931 FreePool(OldBuffer);
932 }
933
934 return STATUS_INSUFFICIENT_RESOURCES;
935 }
936
937 /* Store our info and previous if any */
938 RtlCopyMemory(DeviceString, AssociatedDevice->String.Buffer, AssociatedDevice->String.Length);
939 if (OldBuffer)
940 {
941 RtlCopyMemory(&DeviceString[AssociatedDevice->String.Length / sizeof(WCHAR)], OldBuffer, OldLength);
942 FreePool(OldBuffer);
943 }
944
945 /* Count and continue looking */
946 ++DevicesFound;
947 DeviceInformation = AssociatedDevice->DeviceInformation;
948
949 /* If too many devices, try another way */
950 if (DevicesFound > MAX_DEVICES) /* 1000 */
951 {
952 goto TryWithVolumeName;
953 }
954 }
955
956 /* Reallocate our string, so that we can prepend disk letter */
957 OldBuffer = DeviceString;
958 OldLength = DeviceLength;
959 DeviceLength += 2 * sizeof(WCHAR);
960 DeviceString = AllocatePool(DeviceLength);
961 if (!DeviceString)
962 {
963 if (OldBuffer)
964 {
965 FreePool(OldBuffer);
966 }
967
968 return STATUS_INSUFFICIENT_RESOURCES;
969 }
970
971 /* Get the letter */
972 DeviceString[0] = SymlinkInformation->Name.Buffer[12];
973 DeviceString[1] = L':';
974
975 /* And copy the rest */
976 if (OldBuffer)
977 {
978 RtlCopyMemory(&DeviceString[2], OldBuffer, OldLength);
979 FreePool(OldBuffer);
980 }
981
982 TryWithVolumeName:
983 /* If we didn't find anything, try differently */
984 if (DeviceLength < 2 * sizeof(WCHAR) || DeviceString[1] != L':')
985 {
986 if (DeviceString)
987 {
988 FreePool(DeviceString);
989 DeviceLength = 0;
990 }
991
992 /* Try to find a volume name matching */
993 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
994 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
995 SymlinksEntry = SymlinksEntry->Flink)
996 {
997 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
998
999 if (MOUNTMGR_IS_VOLUME_NAME(&SymlinkInformation->Name))
1000 {
1001 break;
1002 }
1003 }
1004
1005 /* If found copy */
1006 if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead))
1007 {
1008 DeviceLength = SymlinkInformation->Name.Length;
1009 DeviceString = AllocatePool(DeviceLength);
1010 if (!DeviceString)
1011 {
1012 return STATUS_INSUFFICIENT_RESOURCES;
1013 }
1014
1015 RtlCopyMemory(DeviceString, SymlinkInformation->Name.Buffer, DeviceLength);
1016 /* Ensure we are in the right namespace; [1] can be ? */
1017 DeviceString[1] = L'\\';
1018 }
1019 }
1020
1021 /* If we found something */
1022 if (DeviceString)
1023 {
1024 /* At least, we will return our length */
1025 ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSzLength = DeviceLength;
1026 /* MOUNTMGR_VOLUME_PATHS is a string + a ULONG */
1027 Irp->IoStatus.Information = DeviceLength + sizeof(ULONG);
1028
1029 /* If we have enough room for copying the string */
1030 if (sizeof(ULONG) + DeviceLength <= Stack->Parameters.DeviceIoControl.OutputBufferLength)
1031 {
1032 /* Copy it */
1033 if (DeviceLength)
1034 {
1035 RtlCopyMemory(((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz, DeviceString, DeviceLength);
1036 }
1037
1038 /* And double zero at its end - this is needed in case of multiple paths which are separated by a single 0 */
1039 FreePool(DeviceString);
1040 ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz[DeviceLength / sizeof(WCHAR)] = 0;
1041 ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz[DeviceLength / sizeof(WCHAR) + 1] = 0;
1042
1043 return STATUS_SUCCESS;
1044 }
1045 else
1046 {
1047 /* Just return appropriate size and leave */
1048 FreePool(DeviceString);
1049 Irp->IoStatus.Information = sizeof(ULONG);
1050 return STATUS_BUFFER_OVERFLOW;
1051 }
1052 }
1053
1054 /* Fail */
1055 return STATUS_NOT_FOUND;
1056 }
1057
1058 NTSTATUS
1059 MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
1060 IN PIRP Irp)
1061 {
1062 UNREFERENCED_PARAMETER(DeviceExtension);
1063 UNREFERENCED_PARAMETER(Irp);
1064 return STATUS_NOT_IMPLEMENTED;
1065 }
1066
1067 /*
1068 * @implemented
1069 */
1070 NTSTATUS
1071 MountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension,
1072 IN PIRP Irp)
1073 {
1074 NTSTATUS Status;
1075 PIO_STACK_LOCATION Stack;
1076 UNICODE_STRING SymbolicName;
1077 PMOUNTMGR_TARGET_NAME Target;
1078 PDEVICE_INFORMATION DeviceInformation;
1079
1080 Stack = IoGetNextIrpStackLocation(Irp);
1081
1082 /* Validate input */
1083 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
1084 {
1085 return STATUS_INVALID_PARAMETER;
1086 }
1087
1088 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
1089 if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
1090 {
1091 return STATUS_INVALID_PARAMETER;
1092 }
1093
1094 SymbolicName.Length =
1095 SymbolicName.MaximumLength = Target->DeviceNameLength;
1096 SymbolicName.Buffer = Target->DeviceName;
1097
1098 /* Find the associated device */
1099 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
1100 if (!NT_SUCCESS(Status))
1101 {
1102 return Status;
1103 }
1104
1105 /* Mark we want to keep links */
1106 DeviceInformation->KeepLinks = TRUE;
1107
1108 return STATUS_SUCCESS;
1109 }
1110
1111 /*
1112 * @implemented
1113 */
1114 NTSTATUS
1115 MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension,
1116 IN PIRP Irp)
1117 {
1118 NTSTATUS Status;
1119 BOOLEAN OldState;
1120 PIO_STACK_LOCATION Stack;
1121 UNICODE_STRING SymbolicName;
1122 PMOUNTMGR_TARGET_NAME Target;
1123
1124 Stack = IoGetNextIrpStackLocation(Irp);
1125
1126 /* Validate input */
1127 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
1128 {
1129 return STATUS_INVALID_PARAMETER;
1130 }
1131
1132 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
1133 if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
1134 {
1135 return STATUS_INVALID_PARAMETER;
1136 }
1137
1138 SymbolicName.Length =
1139 SymbolicName.MaximumLength = Target->DeviceNameLength;
1140 SymbolicName.Buffer = Target->DeviceName;
1141
1142 /* Disable hard errors */
1143 OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1144 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
1145
1146 /* Call real worker */
1147 Status = MountMgrMountedDeviceArrival(DeviceExtension, &SymbolicName, TRUE);
1148
1149 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
1150
1151 return Status;
1152 }
1153
1154 /*
1155 * @implemented
1156 */
1157 NTSTATUS
1158 MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension,
1159 IN PIRP Irp)
1160 {
1161 NTSTATUS Status;
1162 PIO_STACK_LOCATION Stack;
1163 PMOUNTDEV_UNIQUE_ID UniqueId;
1164 PMOUNTMGR_MOUNT_POINT MountPoint;
1165 UNICODE_STRING SymbolicName, DeviceName;
1166
1167 Stack = IoGetNextIrpStackLocation(Irp);
1168
1169 /* Validate input... */
1170 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
1171 {
1172 return STATUS_INVALID_PARAMETER;
1173 }
1174
1175 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1176 if (!MountPoint->SymbolicLinkNameLength)
1177 {
1178 MountPoint->SymbolicLinkNameOffset = 0;
1179 }
1180
1181 if (!MountPoint->UniqueIdLength)
1182 {
1183 MountPoint->UniqueIdOffset = 0;
1184 }
1185
1186 if (!MountPoint->DeviceNameLength)
1187 {
1188 MountPoint->DeviceNameOffset = 0;
1189 }
1190
1191 /* Addresses can't be odd */
1192 if ((MountPoint->SymbolicLinkNameOffset & 1) ||
1193 (MountPoint->SymbolicLinkNameLength & 1))
1194 {
1195 return STATUS_INVALID_PARAMETER;
1196 }
1197
1198 if ((MountPoint->UniqueIdOffset & 1) ||
1199 (MountPoint->UniqueIdLength & 1))
1200 {
1201 return STATUS_INVALID_PARAMETER;
1202 }
1203
1204 if ((MountPoint->DeviceNameOffset & 1) ||
1205 (MountPoint->DeviceNameLength & 1))
1206 {
1207 return STATUS_INVALID_PARAMETER;
1208 }
1209
1210 /* We can't go beyond */
1211 if (((ULONG)MountPoint->SymbolicLinkNameLength + MountPoint->UniqueIdLength +
1212 MountPoint->DeviceNameLength) < Stack->Parameters.DeviceIoControl.InputBufferLength)
1213 {
1214 return STATUS_INVALID_PARAMETER;
1215 }
1216
1217 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_MOUNT_POINTS))
1218 {
1219 return STATUS_INVALID_PARAMETER;
1220 }
1221
1222 /* If caller provided a Symlink, use it */
1223 if (MountPoint->SymbolicLinkNameLength != 0)
1224 {
1225 if (MountPoint->SymbolicLinkNameLength > MAXSHORT)
1226 {
1227 return STATUS_INVALID_PARAMETER;
1228 }
1229
1230 SymbolicName.Length = MountPoint->SymbolicLinkNameLength;
1231 SymbolicName.MaximumLength = MountPoint->SymbolicLinkNameLength + sizeof(WCHAR);
1232 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1233 if (!SymbolicName.Buffer)
1234 {
1235 return STATUS_INSUFFICIENT_RESOURCES;
1236 }
1237
1238 RtlCopyMemory(SymbolicName.Buffer,
1239 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->SymbolicLinkNameOffset),
1240 SymbolicName.Length);
1241 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1242
1243 /* Query links using it */
1244 Status = QueryPointsFromSymbolicLinkName(DeviceExtension, &SymbolicName, Irp);
1245 FreePool(SymbolicName.Buffer);
1246 }
1247 /* If user provided an unique ID */
1248 else if (MountPoint->UniqueIdLength != 0)
1249 {
1250 UniqueId = AllocatePool(MountPoint->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1251 if (!UniqueId)
1252 {
1253 return STATUS_INSUFFICIENT_RESOURCES;
1254 }
1255
1256 UniqueId->UniqueIdLength = MountPoint->UniqueIdLength;
1257 RtlCopyMemory(UniqueId->UniqueId,
1258 (PVOID)((ULONG_PTR)MountPoint + MountPoint->UniqueIdOffset),
1259 MountPoint->UniqueIdLength);
1260
1261 /* Query links using it */
1262 Status = QueryPointsFromMemory(DeviceExtension, Irp, UniqueId, NULL);
1263 FreePool(UniqueId);
1264 }
1265 /* If caller provided a device name */
1266 else if (MountPoint->DeviceNameLength != 0)
1267 {
1268 if (MountPoint->DeviceNameLength > MAXSHORT)
1269 {
1270 return STATUS_INVALID_PARAMETER;
1271 }
1272
1273 DeviceName.Length = MountPoint->DeviceNameLength;
1274 DeviceName.MaximumLength = MountPoint->DeviceNameLength + sizeof(WCHAR);
1275 DeviceName.Buffer = AllocatePool(DeviceName.MaximumLength);
1276 if (!DeviceName.Buffer)
1277 {
1278 return STATUS_INSUFFICIENT_RESOURCES;
1279 }
1280
1281 RtlCopyMemory(DeviceName.Buffer,
1282 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->DeviceNameOffset),
1283 DeviceName.Length);
1284 DeviceName.Buffer[DeviceName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1285
1286 /* Query links using it */
1287 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, &DeviceName);
1288 FreePool(DeviceName.Buffer);
1289 }
1290 else
1291 {
1292 /* Otherwise, query all links */
1293 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, NULL);
1294 }
1295
1296 return Status;
1297 }
1298
1299 /*
1300 * @implemented
1301 */
1302 NTSTATUS
1303 MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension,
1304 IN PIRP Irp)
1305 {
1306 ULONG Link;
1307 NTSTATUS Status;
1308 BOOLEAN CreateNoDrive;
1309 PIO_STACK_LOCATION Stack;
1310 PMOUNTDEV_UNIQUE_ID UniqueId;
1311 PMOUNTMGR_MOUNT_POINT MountPoint;
1312 PMOUNTMGR_MOUNT_POINTS MountPoints;
1313 UNICODE_STRING SymbolicName, DeviceName;
1314
1315 Stack = IoGetNextIrpStackLocation(Irp);
1316
1317 /* Validate input */
1318 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
1319 {
1320 return STATUS_INVALID_PARAMETER;
1321 }
1322
1323 /* Query points */
1324 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1325 CreateNoDrive = (MountPoint->SymbolicLinkNameOffset && MountPoint->SymbolicLinkNameLength);
1326
1327 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1328 if (!NT_SUCCESS(Status))
1329 {
1330 return Status;
1331 }
1332
1333 /* For all the points matching the request */
1334 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
1335 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++)
1336 {
1337 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength;
1338 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR);
1339 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1340 if (!SymbolicName.Buffer)
1341 {
1342 return STATUS_INSUFFICIENT_RESOURCES;
1343 }
1344
1345 RtlCopyMemory(SymbolicName.Buffer,
1346 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset),
1347 SymbolicName.Length);
1348 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1349
1350 /* Create a no drive entry for the drive letters */
1351 if (CreateNoDrive && IsDriveLetter(&SymbolicName))
1352 {
1353 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1354 if (UniqueId)
1355 {
1356 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength;
1357 RtlCopyMemory(UniqueId->UniqueId,
1358 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1359 MountPoints->MountPoints[Link].UniqueIdLength);
1360
1361 CreateNoDriveLetterEntry(UniqueId);
1362 FreePool(UniqueId);
1363 }
1364 }
1365
1366 /* If there are no link any more, and no need to create a no drive entry */
1367 if (Link == 0 && !CreateNoDrive)
1368 {
1369 /* Then, delete everything */
1370 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength);
1371 if (UniqueId)
1372 {
1373 RtlCopyMemory(UniqueId,
1374 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1375 MountPoints->MountPoints[Link].UniqueIdLength);
1376
1377 DeleteNoDriveLetterEntry(UniqueId);
1378 FreePool(UniqueId);
1379 }
1380 }
1381
1382 /* Delete all the information about the mount point */
1383 GlobalDeleteSymbolicLink(&SymbolicName);
1384 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, FALSE);
1385 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer);
1386 FreePool(SymbolicName.Buffer);
1387
1388 /* Notify the change */
1389 DeviceName.Length = DeviceName.MaximumLength =
1390 MountPoints->MountPoints[Link].DeviceNameLength;
1391 DeviceName.Buffer = (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].DeviceNameOffset);
1392 MountMgrNotifyNameChange(DeviceExtension, &DeviceName, TRUE);
1393 }
1394
1395 MountMgrNotify(DeviceExtension);
1396
1397 return Status;
1398 }
1399
1400 /*
1401 * @implemented
1402 */
1403 NTSTATUS
1404 MountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension,
1405 IN PIRP Irp)
1406 {
1407 ULONG Link;
1408 NTSTATUS Status;
1409 UNICODE_STRING SymbolicName;
1410 PMOUNTDEV_UNIQUE_ID UniqueId;
1411 PMOUNTMGR_MOUNT_POINTS MountPoints;
1412
1413 /* Query points */
1414 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1415 if (!NT_SUCCESS(Status))
1416 {
1417 return Status;
1418 }
1419
1420 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
1421 if (MountPoints->NumberOfMountPoints == 0)
1422 {
1423 return Status;
1424 }
1425
1426 /* For all the mount points */
1427 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++)
1428 {
1429 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength;
1430 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR);
1431 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1432 if (!SymbolicName.Buffer)
1433 {
1434 return STATUS_INSUFFICIENT_RESOURCES;
1435 }
1436
1437 RtlCopyMemory(SymbolicName.Buffer,
1438 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset),
1439 SymbolicName.Length);
1440 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1441
1442 /* If the only mount point is a drive letter, then create a no letter drive entry */
1443 if (MountPoints->NumberOfMountPoints == 1 && IsDriveLetter(&SymbolicName))
1444 {
1445 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1446 if (UniqueId)
1447 {
1448 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength;
1449 RtlCopyMemory(UniqueId->UniqueId,
1450 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1451 MountPoints->MountPoints[Link].UniqueIdLength);
1452
1453 CreateNoDriveLetterEntry(UniqueId);
1454 FreePool(UniqueId);
1455 }
1456 }
1457
1458 /* Simply delete mount point from DB */
1459 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, TRUE);
1460 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer);
1461 FreePool(SymbolicName.Buffer);
1462 }
1463
1464 return Status;
1465 }
1466
1467 /*
1468 * @implemented
1469 */
1470 NTSTATUS
1471 MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension,
1472 IN PIRP Irp,
1473 IN NTSTATUS LockStatus,
1474 OUT PUNICODE_STRING SourceDeviceName,
1475 OUT PUNICODE_STRING SourceSymbolicName,
1476 OUT PUNICODE_STRING TargetVolumeName)
1477 {
1478 HANDLE Handle;
1479 NTSTATUS Status;
1480 PFILE_OBJECT FileObject;
1481 PIO_STACK_LOCATION Stack;
1482 ULONG Length, SavedLength;
1483 BOOLEAN FOReferenced = FALSE;
1484 IO_STATUS_BLOCK IoStatusBlock;
1485 OBJECT_ATTRIBUTES ObjectAttributes;
1486 PDEVICE_INFORMATION DeviceInformation;
1487 OBJECT_NAME_INFORMATION ObjectNameInfo;
1488 FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
1489 PFILE_NAME_INFORMATION FileNameInfo = NULL;
1490 PMOUNTMGR_VOLUME_MOUNT_POINT VolumeMountPoint;
1491 POBJECT_NAME_INFORMATION ObjectNameInfoPtr = NULL;
1492 UNICODE_STRING SourceVolumeName, TargetDeviceName;
1493
1494 Stack = IoGetNextIrpStackLocation(Irp);
1495
1496 /* Validate input */
1497 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_VOLUME_MOUNT_POINT))
1498 {
1499 return STATUS_INVALID_PARAMETER;
1500 }
1501
1502 VolumeMountPoint = (PMOUNTMGR_VOLUME_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1503
1504 if (((ULONG)VolumeMountPoint->SourceVolumeNameLength + VolumeMountPoint->TargetVolumeNameLength) <
1505 Stack->Parameters.DeviceIoControl.InputBufferLength)
1506 {
1507 return STATUS_INVALID_PARAMETER;
1508 }
1509
1510 /* Get source volume name */
1511 SourceVolumeName.Length =
1512 SourceVolumeName.MaximumLength = VolumeMountPoint->SourceVolumeNameLength;
1513 SourceVolumeName.Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->SourceVolumeNameOffset);
1514
1515 InitializeObjectAttributes(&ObjectAttributes,
1516 &SourceVolumeName,
1517 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
1518 NULL,
1519 NULL);
1520
1521 /* Open it */
1522 Status = ZwOpenFile(&Handle,
1523 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
1524 &ObjectAttributes,
1525 &IoStatusBlock,
1526 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1527 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
1528 if (!NT_SUCCESS(Status))
1529 {
1530 return Status;
1531 }
1532
1533 TargetDeviceName.Buffer = NULL;
1534
1535 /* Query its attributes */
1536 Status = ZwQueryVolumeInformationFile(Handle,
1537 &IoStatusBlock,
1538 &FsDeviceInfo,
1539 sizeof(FsDeviceInfo),
1540 FileFsDeviceInformation);
1541 if (!NT_SUCCESS(Status))
1542 {
1543 goto Cleanup;
1544 }
1545
1546 if (FsDeviceInfo.DeviceType != FILE_DEVICE_DISK && FsDeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK)
1547 {
1548 goto Cleanup;
1549 }
1550
1551 if (FsDeviceInfo.Characteristics != (FILE_REMOTE_DEVICE | FILE_REMOVABLE_MEDIA))
1552 {
1553 goto Cleanup;
1554 }
1555
1556 /* Reference it */
1557 Status = ObReferenceObjectByHandle(Handle, 0, IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL);
1558 if (!NT_SUCCESS(Status))
1559 {
1560 goto Cleanup;
1561 }
1562 FOReferenced = TRUE;
1563
1564 /* Get file name */
1565 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION));
1566 if (!FileNameInfo)
1567 {
1568 Status = STATUS_INSUFFICIENT_RESOURCES;
1569 goto Cleanup;
1570 }
1571
1572 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo,
1573 sizeof(FILE_NAME_INFORMATION),
1574 FileNameInformation);
1575 if (Status == STATUS_BUFFER_OVERFLOW)
1576 {
1577 /* Now we have real length, use it */
1578 Length = FileNameInfo->FileNameLength;
1579 FreePool(FileNameInfo);
1580
1581 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + Length);
1582 if (!FileNameInfo)
1583 {
1584 Status = STATUS_INSUFFICIENT_RESOURCES;
1585 goto Cleanup;
1586 }
1587
1588 /* Really query file name */
1589 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo,
1590 sizeof(FILE_NAME_INFORMATION) + Length,
1591 FileNameInformation);
1592 }
1593
1594 if (!NT_SUCCESS(Status))
1595 {
1596 goto Cleanup;
1597 }
1598
1599 /* Get symbolic name */
1600 ObjectNameInfoPtr = &ObjectNameInfo;
1601 SavedLength = sizeof(OBJECT_NAME_INFORMATION);
1602 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, sizeof(OBJECT_NAME_INFORMATION), &Length);
1603 if (Status == STATUS_INFO_LENGTH_MISMATCH)
1604 {
1605 /* Once again, with proper size, it works better */
1606 ObjectNameInfoPtr = AllocatePool(Length);
1607 if (!ObjectNameInfoPtr)
1608 {
1609 Status = STATUS_INSUFFICIENT_RESOURCES;
1610 goto Cleanup;
1611 }
1612
1613 SavedLength = Length;
1614 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, SavedLength, &Length);
1615 }
1616
1617 if (!NT_SUCCESS(Status))
1618 {
1619 goto Cleanup;
1620 }
1621
1622 /* Now, query the device name */
1623 Status = QueryDeviceInformation(&ObjectNameInfoPtr->Name, SourceDeviceName,
1624 NULL, NULL, NULL, NULL, NULL, NULL);
1625 if (!NT_SUCCESS(Status))
1626 {
1627 goto Cleanup;
1628 }
1629
1630 /* For target volume name, use input */
1631 TargetVolumeName->Length =
1632 TargetVolumeName->MaximumLength = VolumeMountPoint->TargetVolumeNameLength;
1633 TargetVolumeName->Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->TargetVolumeNameOffset);
1634
1635 /* Query its device name */
1636 Status = QueryDeviceInformation(TargetVolumeName, &TargetDeviceName,
1637 NULL, NULL, NULL, NULL, NULL, NULL);
1638 if (!NT_SUCCESS(Status))
1639 {
1640 goto Cleanup;
1641 }
1642
1643 /* Return symbolic name */
1644 SourceSymbolicName->Length =
1645 SourceSymbolicName->MaximumLength = (USHORT)FileNameInfo->FileNameLength;
1646 SourceSymbolicName->Buffer = (PWSTR)FileNameInfo;
1647 /* memmove allows memory overlap */
1648 RtlMoveMemory(SourceSymbolicName->Buffer, FileNameInfo->FileName, SourceSymbolicName->Length);
1649 FileNameInfo = NULL;
1650
1651 /* Notify the change */
1652 MountMgrNotify(DeviceExtension);
1653 MountMgrNotifyNameChange(DeviceExtension, &TargetDeviceName, TRUE);
1654
1655 /* If we are locked, sync databases if possible */
1656 if (NT_SUCCESS(LockStatus))
1657 {
1658 Status = FindDeviceInfo(DeviceExtension, SourceDeviceName, FALSE, &DeviceInformation);
1659 if (NT_SUCCESS(Status))
1660 {
1661 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
1662 }
1663 else
1664 {
1665 Status = STATUS_PENDING;
1666 }
1667 }
1668
1669 Cleanup:
1670 if (TargetDeviceName.Buffer)
1671 {
1672 FreePool(TargetDeviceName.Buffer);
1673 }
1674
1675 if (ObjectNameInfoPtr && ObjectNameInfoPtr != &ObjectNameInfo)
1676 {
1677 FreePool(ObjectNameInfoPtr);
1678 }
1679
1680 if (FileNameInfo)
1681 {
1682 FreePool(FileNameInfo);
1683 }
1684
1685 if (FOReferenced)
1686 {
1687 ObDereferenceObject(FileObject);
1688 }
1689
1690 return Status;
1691 }
1692
1693 NTSTATUS
1694 MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension,
1695 IN PIRP Irp,
1696 IN NTSTATUS LockStatus)
1697 {
1698 UNREFERENCED_PARAMETER(DeviceExtension);
1699 UNREFERENCED_PARAMETER(Irp);
1700 UNREFERENCED_PARAMETER(LockStatus);
1701 return STATUS_NOT_IMPLEMENTED;
1702 }
1703
1704 NTSTATUS
1705 MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension,
1706 IN PIRP Irp,
1707 IN NTSTATUS LockStatus)
1708 {
1709 UNREFERENCED_PARAMETER(DeviceExtension);
1710 UNREFERENCED_PARAMETER(Irp);
1711 UNREFERENCED_PARAMETER(LockStatus);
1712 return STATUS_NOT_IMPLEMENTED;
1713 }
1714
1715 /*
1716 * @implemented
1717 */
1718 NTSTATUS
1719 NTAPI
1720 MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1721 IN PIRP Irp)
1722 {
1723 PIO_STACK_LOCATION Stack;
1724 NTSTATUS Status, LockStatus;
1725 PDEVICE_EXTENSION DeviceExtension;
1726
1727 Stack = IoGetNextIrpStackLocation(Irp);
1728 DeviceExtension = DeviceObject->DeviceExtension;
1729
1730 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1731
1732 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
1733 {
1734 case IOCTL_MOUNTMGR_CREATE_POINT:
1735 Status = MountMgrCreatePoint(DeviceExtension, Irp);
1736 break;
1737
1738 case IOCTL_MOUNTMGR_DELETE_POINTS:
1739 Status = MountMgrDeletePoints(DeviceExtension, Irp);
1740 break;
1741
1742 case IOCTL_MOUNTMGR_QUERY_POINTS:
1743 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1744 break;
1745
1746 case IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY:
1747 Status = MountMgrDeletePointsDbOnly(DeviceExtension, Irp);
1748 break;
1749
1750 case IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER:
1751 Status = MountMgrNextDriveLetter(DeviceExtension, Irp);
1752 break;
1753
1754 case IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS:
1755 DeviceExtension->AutomaticDriveLetter = TRUE;
1756 Status = STATUS_SUCCESS;
1757
1758 MountMgrAssignDriveLetters(DeviceExtension);
1759 ReconcileAllDatabasesWithMaster(DeviceExtension);
1760 WaitForOnlinesToComplete(DeviceExtension);
1761 break;
1762
1763 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED:
1764 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1765
1766 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension);
1767 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1768 Status = MountMgrVolumeMountPointCreated(DeviceExtension, Irp, LockStatus);
1769 if (NT_SUCCESS(LockStatus))
1770 {
1771 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
1772 }
1773
1774 break;
1775
1776 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED:
1777 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1778
1779 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension);
1780 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1781 Status = MountMgrVolumeMountPointDeleted(DeviceExtension, Irp, LockStatus);
1782 if (NT_SUCCESS(LockStatus))
1783 {
1784 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
1785 }
1786
1787 break;
1788
1789 case IOCTL_MOUNTMGR_CHANGE_NOTIFY:
1790 Status = MountMgrChangeNotify(DeviceExtension, Irp);
1791 break;
1792
1793 case IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE:
1794 Status = MountMgrKeepLinksWhenOffline(DeviceExtension, Irp);
1795 break;
1796
1797 case IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES:
1798 Status = MountMgrCheckUnprocessedVolumes(DeviceExtension, Irp);
1799 goto Complete;
1800
1801 case IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION:
1802 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1803 Status = MountMgrVolumeArrivalNotification(DeviceExtension, Irp);
1804 goto Complete;
1805
1806 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH:
1807 Status = MountMgrQueryDosVolumePath(DeviceExtension, Irp);
1808 break;
1809
1810 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS:
1811 Status = MountMgrQueryDosVolumePaths(DeviceExtension, Irp);
1812 break;
1813
1814 case IOCTL_MOUNTMGR_SCRUB_REGISTRY:
1815 Status = MountMgrScrubRegistry(DeviceExtension);
1816 break;
1817
1818 case IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT:
1819 Status = MountMgrQueryAutoMount(DeviceExtension, Irp);
1820 break;
1821
1822 case IOCTL_MOUNTMGR_SET_AUTO_MOUNT:
1823 Status = MountMgrSetAutoMount(DeviceExtension, Irp);
1824 break;
1825
1826 default:
1827 Status = STATUS_INVALID_DEVICE_REQUEST;
1828 }
1829
1830 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1831
1832 if (Status != STATUS_PENDING)
1833 {
1834 goto Complete;
1835 }
1836
1837 return Status;
1838
1839 Complete:
1840 Irp->IoStatus.Status = Status;
1841 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1842
1843 return Status;
1844 }