[MOUNTMGR]
[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 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 if (RtlPrefixUnicodeString(&DeviceFloppy, &TargetDeviceName, TRUE))
559 {
560 DriveLetter = 'A';
561 }
562 else
563 {
564 DriveLetter = 'C' + RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE);
565 }
566
567 /* We cannot set NO drive letter */
568 ASSERT(DeviceInformation->SuggestedDriveLetter != (UCHAR)-1);
569
570 /* If we don't have suggested letter but it's a FT volume, fail */
571 if (!DeviceInformation->SuggestedDriveLetter && IsFtVolume(&(DeviceInformation->DeviceName)))
572 {
573 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
574 DriveLetterInfo->CurrentDriveLetter = 0;
575
576 goto Release;
577 }
578
579 /* Prepare buffer */
580 RtlCopyMemory(NameBuffer, DosDevices.Buffer, DosDevices.Length);
581 NameBuffer[COLON_POSITION] = L':';
582 SymbolicName.Buffer = NameBuffer;
583 SymbolicName.Length =
584 SymbolicName.MaximumLength = DRIVE_LETTER_LENGTH;
585
586 /* It's all prepared, create mount point */
587 if (DeviceInformation->SuggestedDriveLetter)
588 {
589 DriveLetterInfo->CurrentDriveLetter = DeviceInformation->SuggestedDriveLetter;
590 NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter;
591
592 Status = MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &TargetDeviceName);
593 if (NT_SUCCESS(Status))
594 {
595 goto Release;
596 }
597 }
598
599 /* It failed with this letter... Try another one! */
600 for (DriveLetterInfo->CurrentDriveLetter = DriveLetter;
601 DriveLetterInfo->CurrentDriveLetter <= L'Z';
602 DriveLetterInfo->CurrentDriveLetter++)
603 {
604 NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter;
605
606 Status = MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &TargetDeviceName);
607 if (NT_SUCCESS(Status))
608 {
609 break;
610 }
611 }
612
613 /* We failed setting a letter */
614 if (DriveLetterInfo->CurrentDriveLetter > L'Z')
615 {
616 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
617 DriveLetterInfo->CurrentDriveLetter = 0;
618
619 /* Try at least to add a no drive letter entry */
620 Status = QueryDeviceInformation(&TargetDeviceName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL);
621 if (NT_SUCCESS(Status))
622 {
623 CreateNoDriveLetterEntry(UniqueId);
624 FreePool(UniqueId);
625 }
626 }
627
628 Release:
629 FreePool(TargetDeviceName.Buffer);
630
631 return STATUS_SUCCESS;
632 }
633
634
635 /*
636 * @implemented
637 */
638 NTSTATUS
639 MountMgrNextDriveLetter(IN PDEVICE_EXTENSION DeviceExtension,
640 IN PIRP Irp)
641 {
642 NTSTATUS Status;
643 PIO_STACK_LOCATION Stack;
644 UNICODE_STRING DeviceName;
645 PMOUNTMGR_DRIVE_LETTER_TARGET DriveLetterTarget;
646 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
647
648 Stack = IoGetNextIrpStackLocation(Irp);
649
650 /* Validate input */
651 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) ||
652 Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION))
653 {
654 return STATUS_INVALID_PARAMETER;
655 }
656
657 DriveLetterTarget = (PMOUNTMGR_DRIVE_LETTER_TARGET)Irp->AssociatedIrp.SystemBuffer;
658 if (DriveLetterTarget->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
659 {
660 return STATUS_INVALID_PARAMETER;
661 }
662
663 /* Call the worker */
664 DeviceName.Buffer = DriveLetterTarget->DeviceName;
665 DeviceName.Length =
666 DeviceName.MaximumLength = DriveLetterTarget->DeviceNameLength;
667
668 Status = MountMgrNextDriveLetterWorker(DeviceExtension, &DeviceName,
669 &DriveLetterInformation);
670 if (NT_SUCCESS(Status))
671 {
672 *(PMOUNTMGR_DRIVE_LETTER_INFORMATION)Irp->AssociatedIrp.SystemBuffer =
673 DriveLetterInformation;
674 Irp->IoStatus.Information = sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION);
675 }
676
677 return Status;
678 }
679
680 /*
681 * @implemented
682 */
683 NTSTATUS
684 NTAPI
685 MountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName,
686 IN ULONG ValueType,
687 IN PVOID ValueData,
688 IN ULONG ValueLength,
689 IN PVOID Context,
690 IN PVOID EntryContext)
691 {
692 UNICODE_STRING ValueString;
693 PUNICODE_STRING SystemVolumeName;
694
695 UNREFERENCED_PARAMETER(ValueName);
696 UNREFERENCED_PARAMETER(ValueLength);
697 UNREFERENCED_PARAMETER(EntryContext);
698
699 if (ValueType != REG_SZ)
700 {
701 return STATUS_SUCCESS;
702 }
703
704 RtlInitUnicodeString(&ValueString, ValueData);
705 SystemVolumeName = Context;
706
707 /* Return a string containing system volume name */
708 SystemVolumeName->Length = ValueString.Length;
709 SystemVolumeName->MaximumLength = ValueString.Length + sizeof(WCHAR);
710 SystemVolumeName->Buffer = AllocatePool(SystemVolumeName->MaximumLength);
711 if (SystemVolumeName->Buffer)
712 {
713 RtlCopyMemory(SystemVolumeName->Buffer, ValueData, ValueString.Length);
714 SystemVolumeName->Buffer[ValueString.Length / sizeof(WCHAR)] = UNICODE_NULL;
715 }
716
717 return STATUS_SUCCESS;
718
719 }
720
721 /*
722 * @implemented
723 */
724 NTSTATUS
725 MountMgrQuerySystemVolumeName(OUT PUNICODE_STRING SystemVolumeName)
726 {
727 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
728
729 RtlZeroMemory(QueryTable, sizeof(QueryTable));
730 QueryTable[0].QueryRoutine = MountMgrQuerySystemVolumeNameQueryRoutine;
731 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
732 QueryTable[0].Name = L"SystemPartition";
733
734 SystemVolumeName->Buffer = NULL;
735
736 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
737 L"\\Registry\\Machine\\System\\Setup",
738 QueryTable,
739 SystemVolumeName,
740 NULL);
741
742 if (SystemVolumeName->Buffer)
743 {
744 return STATUS_SUCCESS;
745 }
746
747 return STATUS_UNSUCCESSFUL;
748 }
749
750 /*
751 * @implemented
752 */
753 VOID
754 MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)
755 {
756 NTSTATUS Status;
757 PLIST_ENTRY NextEntry;
758 UNICODE_STRING SystemVolumeName;
759 PDEVICE_INFORMATION DeviceInformation;
760 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
761
762 /* First, get system volume name */
763 Status = MountMgrQuerySystemVolumeName(&SystemVolumeName);
764
765 /* If there are no device, it's all done */
766 if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
767 {
768 if (NT_SUCCESS(Status))
769 {
770 FreePool(SystemVolumeName.Buffer);
771 }
772
773 return;
774 }
775
776 /* Now, for all the devices... */
777 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
778 NextEntry != &(DeviceExtension->DeviceListHead);
779 NextEntry = NextEntry->Flink)
780 {
781 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
782
783 /* If the device doesn't have a letter assigned, do it! */
784 if (!DeviceInformation->LetterAssigned)
785 {
786 MountMgrNextDriveLetterWorker(DeviceExtension,
787 &(DeviceInformation->DeviceName),
788 &DriveLetterInformation);
789 }
790
791 /* If it was the system volume */
792 if (NT_SUCCESS(Status) && RtlEqualUnicodeString(&SystemVolumeName, &(DeviceInformation->DeviceName), TRUE))
793 {
794 /* Keep track of it */
795 DeviceExtension->DriveLetterData = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength +
796 sizeof(MOUNTDEV_UNIQUE_ID));
797 if (DeviceExtension->DriveLetterData)
798 {
799 RtlCopyMemory(DeviceExtension->DriveLetterData,
800 DeviceInformation->UniqueId,
801 DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
802 }
803
804 /* If it was not automount, ensure it gets mounted */
805 if (!DeviceExtension->NoAutoMount)
806 {
807 DeviceExtension->NoAutoMount = TRUE;
808
809 MountMgrNextDriveLetterWorker(DeviceExtension,
810 &(DeviceInformation->DeviceName),
811 &DriveLetterInformation);
812
813 DeviceExtension->NoAutoMount = FALSE;
814 }
815 }
816 }
817
818 if (NT_SUCCESS(Status))
819 {
820 FreePool(SystemVolumeName.Buffer);
821 }
822 }
823
824 NTSTATUS
825 MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,
826 IN PIRP Irp)
827 {
828 UNREFERENCED_PARAMETER(DeviceExtension);
829 UNREFERENCED_PARAMETER(Irp);
830 return STATUS_NOT_IMPLEMENTED;
831 }
832
833 NTSTATUS
834 MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
835 IN PIRP Irp)
836 {
837 UNREFERENCED_PARAMETER(DeviceExtension);
838 UNREFERENCED_PARAMETER(Irp);
839 return STATUS_NOT_IMPLEMENTED;
840 }
841
842 /*
843 * @implemented
844 */
845 NTSTATUS
846 MountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension,
847 IN PIRP Irp)
848 {
849 NTSTATUS Status;
850 PIO_STACK_LOCATION Stack;
851 UNICODE_STRING SymbolicName;
852 PMOUNTMGR_TARGET_NAME Target;
853 PDEVICE_INFORMATION DeviceInformation;
854
855 Stack = IoGetNextIrpStackLocation(Irp);
856
857 /* Validate input */
858 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
859 {
860 return STATUS_INVALID_PARAMETER;
861 }
862
863 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
864 if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
865 {
866 return STATUS_INVALID_PARAMETER;
867 }
868
869 SymbolicName.Length =
870 SymbolicName.MaximumLength = Target->DeviceNameLength;
871 SymbolicName.Buffer = Target->DeviceName;
872
873 /* Find the associated device */
874 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
875 if (!NT_SUCCESS(Status))
876 {
877 return Status;
878 }
879
880 /* Mark we want to keep links */
881 DeviceInformation->KeepLinks = TRUE;
882
883 return STATUS_SUCCESS;
884 }
885
886 /*
887 * @implemented
888 */
889 NTSTATUS
890 MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension,
891 IN PIRP Irp)
892 {
893 NTSTATUS Status;
894 BOOLEAN OldState;
895 PIO_STACK_LOCATION Stack;
896 UNICODE_STRING SymbolicName;
897 PMOUNTMGR_TARGET_NAME Target;
898
899 Stack = IoGetNextIrpStackLocation(Irp);
900
901 /* Validate input */
902 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
903 {
904 return STATUS_INVALID_PARAMETER;
905 }
906
907 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
908 if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
909 {
910 return STATUS_INVALID_PARAMETER;
911 }
912
913 SymbolicName.Length =
914 SymbolicName.MaximumLength = Target->DeviceNameLength;
915 SymbolicName.Buffer = Target->DeviceName;
916
917 /* Disable hard errors */
918 OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
919 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
920
921 /* Call real worker */
922 Status = MountMgrMountedDeviceArrival(DeviceExtension, &SymbolicName, TRUE);
923
924 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
925
926 return Status;
927 }
928
929 /*
930 * @implemented
931 */
932 NTSTATUS
933 MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension,
934 IN PIRP Irp)
935 {
936 NTSTATUS Status;
937 PIO_STACK_LOCATION Stack;
938 PMOUNTDEV_UNIQUE_ID UniqueId;
939 PMOUNTMGR_MOUNT_POINT MountPoint;
940 UNICODE_STRING SymbolicName, DeviceName;
941
942 Stack = IoGetNextIrpStackLocation(Irp);
943
944 /* Validate input... */
945 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
946 {
947 return STATUS_INVALID_PARAMETER;
948 }
949
950 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
951 if (!MountPoint->SymbolicLinkNameLength)
952 {
953 MountPoint->SymbolicLinkNameOffset = 0;
954 }
955
956 if (!MountPoint->UniqueIdLength)
957 {
958 MountPoint->UniqueIdOffset = 0;
959 }
960
961 if (!MountPoint->DeviceNameLength)
962 {
963 MountPoint->DeviceNameOffset = 0;
964 }
965
966 /* Addresses can't be odd */
967 if ((MountPoint->SymbolicLinkNameOffset & 1) ||
968 (MountPoint->SymbolicLinkNameLength & 1))
969 {
970 return STATUS_INVALID_PARAMETER;
971 }
972
973 if ((MountPoint->UniqueIdOffset & 1) ||
974 (MountPoint->UniqueIdLength & 1))
975 {
976 return STATUS_INVALID_PARAMETER;
977 }
978
979 if ((MountPoint->DeviceNameOffset & 1) ||
980 (MountPoint->DeviceNameLength & 1))
981 {
982 return STATUS_INVALID_PARAMETER;
983 }
984
985 /* We can't go beyond */
986 if (((ULONG)MountPoint->SymbolicLinkNameLength + MountPoint->UniqueIdLength +
987 MountPoint->DeviceNameLength) < Stack->Parameters.DeviceIoControl.InputBufferLength)
988 {
989 return STATUS_INVALID_PARAMETER;
990 }
991
992 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_MOUNT_POINTS))
993 {
994 return STATUS_INVALID_PARAMETER;
995 }
996
997 /* If caller provided a Symlink, use it */
998 if (MountPoint->SymbolicLinkNameLength != 0)
999 {
1000 if (MountPoint->SymbolicLinkNameLength > MAXSHORT)
1001 {
1002 return STATUS_INVALID_PARAMETER;
1003 }
1004
1005 SymbolicName.Length = MountPoint->SymbolicLinkNameLength;
1006 SymbolicName.MaximumLength = MountPoint->SymbolicLinkNameLength + sizeof(WCHAR);
1007 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1008 if (!SymbolicName.Buffer)
1009 {
1010 return STATUS_INSUFFICIENT_RESOURCES;
1011 }
1012
1013 RtlCopyMemory(SymbolicName.Buffer,
1014 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->SymbolicLinkNameOffset),
1015 SymbolicName.Length);
1016 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1017
1018 /* Query links using it */
1019 Status = QueryPointsFromSymbolicLinkName(DeviceExtension, &SymbolicName, Irp);
1020 FreePool(SymbolicName.Buffer);
1021 }
1022 /* If user provided an unique ID */
1023 else if (MountPoint->UniqueIdLength != 0)
1024 {
1025 UniqueId = AllocatePool(MountPoint->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1026 if (!UniqueId)
1027 {
1028 return STATUS_INSUFFICIENT_RESOURCES;
1029 }
1030
1031 UniqueId->UniqueIdLength = MountPoint->UniqueIdLength;
1032 RtlCopyMemory(UniqueId->UniqueId,
1033 (PVOID)((ULONG_PTR)MountPoint + MountPoint->UniqueIdOffset),
1034 MountPoint->UniqueIdLength);
1035
1036 /* Query links using it */
1037 Status = QueryPointsFromMemory(DeviceExtension, Irp, UniqueId, NULL);
1038 FreePool(UniqueId);
1039 }
1040 /* If caller provided a device name */
1041 else if (MountPoint->DeviceNameLength != 0)
1042 {
1043 if (MountPoint->DeviceNameLength > MAXSHORT)
1044 {
1045 return STATUS_INVALID_PARAMETER;
1046 }
1047
1048 DeviceName.Length = MountPoint->DeviceNameLength;
1049 DeviceName.MaximumLength = MountPoint->DeviceNameLength + sizeof(WCHAR);
1050 DeviceName.Buffer = AllocatePool(DeviceName.MaximumLength);
1051 if (!DeviceName.Buffer)
1052 {
1053 return STATUS_INSUFFICIENT_RESOURCES;
1054 }
1055
1056 RtlCopyMemory(DeviceName.Buffer,
1057 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->DeviceNameOffset),
1058 DeviceName.Length);
1059 DeviceName.Buffer[DeviceName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1060
1061 /* Query links using it */
1062 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, &DeviceName);
1063 FreePool(DeviceName.Buffer);
1064 }
1065 else
1066 {
1067 /* Otherwise, query all links */
1068 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, NULL);
1069 }
1070
1071 return Status;
1072 }
1073
1074 /*
1075 * @implemented
1076 */
1077 NTSTATUS
1078 MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension,
1079 IN PIRP Irp)
1080 {
1081 ULONG Link;
1082 NTSTATUS Status;
1083 BOOLEAN CreateNoDrive;
1084 PIO_STACK_LOCATION Stack;
1085 PMOUNTDEV_UNIQUE_ID UniqueId;
1086 PMOUNTMGR_MOUNT_POINT MountPoint;
1087 PMOUNTMGR_MOUNT_POINTS MountPoints;
1088 UNICODE_STRING SymbolicName, DeviceName;
1089
1090 Stack = IoGetNextIrpStackLocation(Irp);
1091
1092 /* Validate input */
1093 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
1094 {
1095 return STATUS_INVALID_PARAMETER;
1096 }
1097
1098 /* Query points */
1099 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1100 CreateNoDrive = (MountPoint->SymbolicLinkNameOffset && MountPoint->SymbolicLinkNameLength);
1101
1102 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1103 if (!NT_SUCCESS(Status))
1104 {
1105 return Status;
1106 }
1107
1108 /* For all the points matching the request */
1109 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
1110 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++)
1111 {
1112 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength;
1113 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR);
1114 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1115 if (!SymbolicName.Buffer)
1116 {
1117 return STATUS_INSUFFICIENT_RESOURCES;
1118 }
1119
1120 RtlCopyMemory(SymbolicName.Buffer,
1121 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset),
1122 SymbolicName.Length);
1123 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1124
1125 /* Create a no drive entry for the drive letters */
1126 if (CreateNoDrive && IsDriveLetter(&SymbolicName))
1127 {
1128 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1129 if (UniqueId)
1130 {
1131 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength;
1132 RtlCopyMemory(UniqueId->UniqueId,
1133 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1134 MountPoints->MountPoints[Link].UniqueIdLength);
1135
1136 CreateNoDriveLetterEntry(UniqueId);
1137 FreePool(UniqueId);
1138 }
1139 }
1140
1141 /* If there are no link any more, and no need to create a no drive entry */
1142 if (Link == 0 && !CreateNoDrive)
1143 {
1144 /* Then, delete everything */
1145 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength);
1146 if (UniqueId)
1147 {
1148 RtlCopyMemory(UniqueId,
1149 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1150 MountPoints->MountPoints[Link].UniqueIdLength);
1151
1152 DeleteNoDriveLetterEntry(UniqueId);
1153 FreePool(UniqueId);
1154 }
1155 }
1156
1157 /* Delete all the information about the mount point */
1158 GlobalDeleteSymbolicLink(&SymbolicName);
1159 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, FALSE);
1160 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer);
1161 FreePool(SymbolicName.Buffer);
1162
1163 /* Notify the change */
1164 DeviceName.Length = DeviceName.MaximumLength =
1165 MountPoints->MountPoints[Link].DeviceNameLength;
1166 DeviceName.Buffer = (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].DeviceNameOffset);
1167 MountMgrNotifyNameChange(DeviceExtension, &DeviceName, TRUE);
1168 }
1169
1170 MountMgrNotify(DeviceExtension);
1171
1172 return Status;
1173 }
1174
1175 /*
1176 * @implemented
1177 */
1178 NTSTATUS
1179 MountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension,
1180 IN PIRP Irp)
1181 {
1182 ULONG Link;
1183 NTSTATUS Status;
1184 UNICODE_STRING SymbolicName;
1185 PMOUNTDEV_UNIQUE_ID UniqueId;
1186 PMOUNTMGR_MOUNT_POINTS MountPoints;
1187
1188 /* Query points */
1189 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1190 if (!NT_SUCCESS(Status))
1191 {
1192 return Status;
1193 }
1194
1195 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
1196 if (MountPoints->NumberOfMountPoints == 0)
1197 {
1198 return Status;
1199 }
1200
1201 /* For all the mount points */
1202 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++)
1203 {
1204 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength;
1205 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR);
1206 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1207 if (!SymbolicName.Buffer)
1208 {
1209 return STATUS_INSUFFICIENT_RESOURCES;
1210 }
1211
1212 RtlCopyMemory(SymbolicName.Buffer,
1213 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset),
1214 SymbolicName.Length);
1215 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1216
1217 /* If the only mount point is a drive letter, then create a no letter drive entry */
1218 if (MountPoints->NumberOfMountPoints == 1 && IsDriveLetter(&SymbolicName))
1219 {
1220 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1221 if (UniqueId)
1222 {
1223 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength;
1224 RtlCopyMemory(UniqueId->UniqueId,
1225 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1226 MountPoints->MountPoints[Link].UniqueIdLength);
1227
1228 CreateNoDriveLetterEntry(UniqueId);
1229 FreePool(UniqueId);
1230 }
1231 }
1232
1233 /* Simply delete mount point from DB */
1234 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, TRUE);
1235 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer);
1236 FreePool(SymbolicName.Buffer);
1237 }
1238
1239 return Status;
1240 }
1241
1242 /*
1243 * @implemented
1244 */
1245 NTSTATUS
1246 MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension,
1247 IN PIRP Irp,
1248 IN NTSTATUS LockStatus,
1249 OUT PUNICODE_STRING SourceDeviceName,
1250 OUT PUNICODE_STRING SourceSymbolicName,
1251 OUT PUNICODE_STRING TargetVolumeName)
1252 {
1253 HANDLE Handle;
1254 NTSTATUS Status;
1255 PFILE_OBJECT FileObject;
1256 PIO_STACK_LOCATION Stack;
1257 ULONG Length, SavedLength;
1258 BOOLEAN FOReferenced = FALSE;
1259 IO_STATUS_BLOCK IoStatusBlock;
1260 OBJECT_ATTRIBUTES ObjectAttributes;
1261 PDEVICE_INFORMATION DeviceInformation;
1262 OBJECT_NAME_INFORMATION ObjectNameInfo;
1263 FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
1264 PFILE_NAME_INFORMATION FileNameInfo = NULL;
1265 PMOUNTMGR_VOLUME_MOUNT_POINT VolumeMountPoint;
1266 POBJECT_NAME_INFORMATION ObjectNameInfoPtr = NULL;
1267 UNICODE_STRING SourceVolumeName, TargetDeviceName;
1268
1269 Stack = IoGetNextIrpStackLocation(Irp);
1270
1271 /* Validate input */
1272 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_VOLUME_MOUNT_POINT))
1273 {
1274 return STATUS_INVALID_PARAMETER;
1275 }
1276
1277 VolumeMountPoint = (PMOUNTMGR_VOLUME_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1278
1279 if (((ULONG)VolumeMountPoint->SourceVolumeNameLength + VolumeMountPoint->TargetVolumeNameLength) <
1280 Stack->Parameters.DeviceIoControl.InputBufferLength)
1281 {
1282 return STATUS_INVALID_PARAMETER;
1283 }
1284
1285 /* Get source volume name */
1286 SourceVolumeName.Length =
1287 SourceVolumeName.MaximumLength = VolumeMountPoint->SourceVolumeNameLength;
1288 SourceVolumeName.Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->SourceVolumeNameOffset);
1289
1290 InitializeObjectAttributes(&ObjectAttributes,
1291 &SourceVolumeName,
1292 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
1293 NULL,
1294 NULL);
1295
1296 /* Open it */
1297 Status = ZwOpenFile(&Handle,
1298 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
1299 &ObjectAttributes,
1300 &IoStatusBlock,
1301 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1302 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
1303 if (!NT_SUCCESS(Status))
1304 {
1305 return Status;
1306 }
1307
1308 TargetDeviceName.Buffer = NULL;
1309
1310 /* Query its attributes */
1311 Status = ZwQueryVolumeInformationFile(Handle,
1312 &IoStatusBlock,
1313 &FsDeviceInfo,
1314 sizeof(FsDeviceInfo),
1315 FileFsDeviceInformation);
1316 if (!NT_SUCCESS(Status))
1317 {
1318 goto Cleanup;
1319 }
1320
1321 if (FsDeviceInfo.DeviceType != FILE_DEVICE_DISK && FsDeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK)
1322 {
1323 goto Cleanup;
1324 }
1325
1326 if (FsDeviceInfo.Characteristics != (FILE_REMOTE_DEVICE | FILE_REMOVABLE_MEDIA))
1327 {
1328 goto Cleanup;
1329 }
1330
1331 /* Reference it */
1332 Status = ObReferenceObjectByHandle(Handle, 0, IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL);
1333 if (!NT_SUCCESS(Status))
1334 {
1335 goto Cleanup;
1336 }
1337 FOReferenced = TRUE;
1338
1339 /* Get file name */
1340 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION));
1341 if (!FileNameInfo)
1342 {
1343 Status = STATUS_INSUFFICIENT_RESOURCES;
1344 goto Cleanup;
1345 }
1346
1347 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo,
1348 sizeof(FILE_NAME_INFORMATION),
1349 FileNameInformation);
1350 if (Status == STATUS_BUFFER_OVERFLOW)
1351 {
1352 /* Now we have real length, use it */
1353 Length = FileNameInfo->FileNameLength;
1354 FreePool(FileNameInfo);
1355
1356 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + Length);
1357 if (!FileNameInfo)
1358 {
1359 Status = STATUS_INSUFFICIENT_RESOURCES;
1360 goto Cleanup;
1361 }
1362
1363 /* Really query file name */
1364 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo,
1365 sizeof(FILE_NAME_INFORMATION) + Length,
1366 FileNameInformation);
1367 }
1368
1369 if (!NT_SUCCESS(Status))
1370 {
1371 goto Cleanup;
1372 }
1373
1374 /* Get symbolic name */
1375 ObjectNameInfoPtr = &ObjectNameInfo;
1376 SavedLength = sizeof(OBJECT_NAME_INFORMATION);
1377 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, sizeof(OBJECT_NAME_INFORMATION), &Length);
1378 if (Status == STATUS_INFO_LENGTH_MISMATCH)
1379 {
1380 /* Once again, with proper size, it works better */
1381 ObjectNameInfoPtr = AllocatePool(Length);
1382 if (!ObjectNameInfoPtr)
1383 {
1384 Status = STATUS_INSUFFICIENT_RESOURCES;
1385 goto Cleanup;
1386 }
1387
1388 SavedLength = Length;
1389 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, SavedLength, &Length);
1390 }
1391
1392 if (!NT_SUCCESS(Status))
1393 {
1394 goto Cleanup;
1395 }
1396
1397 /* Now, query the device name */
1398 Status = QueryDeviceInformation(&ObjectNameInfoPtr->Name, SourceDeviceName,
1399 NULL, NULL, NULL, NULL, NULL, NULL);
1400 if (!NT_SUCCESS(Status))
1401 {
1402 goto Cleanup;
1403 }
1404
1405 /* For target volume name, use input */
1406 TargetVolumeName->Length =
1407 TargetVolumeName->MaximumLength = VolumeMountPoint->TargetVolumeNameLength;
1408 TargetVolumeName->Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->TargetVolumeNameOffset);
1409
1410 /* Query its device name */
1411 Status = QueryDeviceInformation(TargetVolumeName, &TargetDeviceName,
1412 NULL, NULL, NULL, NULL, NULL, NULL);
1413 if (!NT_SUCCESS(Status))
1414 {
1415 goto Cleanup;
1416 }
1417
1418 /* Return symbolic name */
1419 SourceSymbolicName->Length =
1420 SourceSymbolicName->MaximumLength = (USHORT)FileNameInfo->FileNameLength;
1421 SourceSymbolicName->Buffer = (PWSTR)FileNameInfo;
1422 /* memmove allows memory overlap */
1423 RtlMoveMemory(SourceSymbolicName->Buffer, FileNameInfo->FileName, SourceSymbolicName->Length);
1424 FileNameInfo = NULL;
1425
1426 /* Notify the change */
1427 MountMgrNotify(DeviceExtension);
1428 MountMgrNotifyNameChange(DeviceExtension, &TargetDeviceName, TRUE);
1429
1430 /* If we are locked, sync databases if possible */
1431 if (NT_SUCCESS(LockStatus))
1432 {
1433 Status = FindDeviceInfo(DeviceExtension, SourceDeviceName, FALSE, &DeviceInformation);
1434 if (NT_SUCCESS(Status))
1435 {
1436 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
1437 }
1438 else
1439 {
1440 Status = STATUS_PENDING;
1441 }
1442 }
1443
1444 Cleanup:
1445 if (TargetDeviceName.Buffer)
1446 {
1447 FreePool(TargetDeviceName.Buffer);
1448 }
1449
1450 if (ObjectNameInfoPtr && ObjectNameInfoPtr != &ObjectNameInfo)
1451 {
1452 FreePool(ObjectNameInfoPtr);
1453 }
1454
1455 if (FileNameInfo)
1456 {
1457 FreePool(FileNameInfo);
1458 }
1459
1460 if (FOReferenced)
1461 {
1462 ObDereferenceObject(FileObject);
1463 }
1464
1465 return Status;
1466 }
1467
1468 NTSTATUS
1469 MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension,
1470 IN PIRP Irp,
1471 IN NTSTATUS LockStatus)
1472 {
1473 UNREFERENCED_PARAMETER(DeviceExtension);
1474 UNREFERENCED_PARAMETER(Irp);
1475 UNREFERENCED_PARAMETER(LockStatus);
1476 return STATUS_NOT_IMPLEMENTED;
1477 }
1478
1479 NTSTATUS
1480 MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension,
1481 IN PIRP Irp,
1482 IN NTSTATUS LockStatus)
1483 {
1484 UNREFERENCED_PARAMETER(DeviceExtension);
1485 UNREFERENCED_PARAMETER(Irp);
1486 UNREFERENCED_PARAMETER(LockStatus);
1487 return STATUS_NOT_IMPLEMENTED;
1488 }
1489
1490 /*
1491 * @implemented
1492 */
1493 NTSTATUS
1494 NTAPI
1495 MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1496 IN PIRP Irp)
1497 {
1498 PIO_STACK_LOCATION Stack;
1499 NTSTATUS Status, LockStatus;
1500 PDEVICE_EXTENSION DeviceExtension;
1501
1502 Stack = IoGetNextIrpStackLocation(Irp);
1503 DeviceExtension = DeviceObject->DeviceExtension;
1504
1505 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1506
1507 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
1508 {
1509 case IOCTL_MOUNTMGR_CREATE_POINT:
1510 Status = MountMgrCreatePoint(DeviceExtension, Irp);
1511 break;
1512
1513 case IOCTL_MOUNTMGR_DELETE_POINTS:
1514 Status = MountMgrDeletePoints(DeviceExtension, Irp);
1515 break;
1516
1517 case IOCTL_MOUNTMGR_QUERY_POINTS:
1518 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1519 break;
1520
1521 case IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY:
1522 Status = MountMgrDeletePointsDbOnly(DeviceExtension, Irp);
1523 break;
1524
1525 case IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER:
1526 Status = MountMgrNextDriveLetter(DeviceExtension, Irp);
1527 break;
1528
1529 case IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS:
1530 DeviceExtension->AutomaticDriveLetter = TRUE;
1531 Status = STATUS_SUCCESS;
1532
1533 MountMgrAssignDriveLetters(DeviceExtension);
1534 ReconcileAllDatabasesWithMaster(DeviceExtension);
1535 WaitForOnlinesToComplete(DeviceExtension);
1536 break;
1537
1538 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED:
1539 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1540
1541 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension);
1542 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1543 Status = MountMgrVolumeMountPointCreated(DeviceExtension, Irp, LockStatus);
1544 if (NT_SUCCESS(LockStatus))
1545 {
1546 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
1547 }
1548
1549 break;
1550
1551 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED:
1552 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1553
1554 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension);
1555 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1556 Status = MountMgrVolumeMountPointDeleted(DeviceExtension, Irp, LockStatus);
1557 if (NT_SUCCESS(LockStatus))
1558 {
1559 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
1560 }
1561
1562 break;
1563
1564 case IOCTL_MOUNTMGR_CHANGE_NOTIFY:
1565 Status = MountMgrChangeNotify(DeviceExtension, Irp);
1566 break;
1567
1568 case IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE:
1569 Status = MountMgrKeepLinksWhenOffline(DeviceExtension, Irp);
1570 break;
1571
1572 case IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES:
1573 Status = MountMgrCheckUnprocessedVolumes(DeviceExtension, Irp);
1574 goto Complete;
1575
1576 case IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION:
1577 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1578 Status = MountMgrVolumeArrivalNotification(DeviceExtension, Irp);
1579 goto Complete;
1580
1581 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH:
1582 Status = MountMgrQueryDosVolumePath(DeviceExtension, Irp);
1583 break;
1584
1585 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS:
1586 Status = MountMgrQueryDosVolumePaths(DeviceExtension, Irp);
1587 break;
1588
1589 case IOCTL_MOUNTMGR_SCRUB_REGISTRY:
1590 Status = MountMgrScrubRegistry(DeviceExtension);
1591 break;
1592
1593 case IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT:
1594 Status = MountMgrQueryAutoMount(DeviceExtension, Irp);
1595 break;
1596
1597 case IOCTL_MOUNTMGR_SET_AUTO_MOUNT:
1598 Status = MountMgrSetAutoMount(DeviceExtension, Irp);
1599 break;
1600
1601 default:
1602 Status = STATUS_INVALID_DEVICE_REQUEST;
1603 }
1604
1605 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1606
1607 if (Status != STATUS_PENDING)
1608 {
1609 goto Complete;
1610 }
1611
1612 return Status;
1613
1614 Complete:
1615 Irp->IoStatus.Status = Status;
1616 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1617
1618 return Status;
1619 }