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