Sync with trunk for console graphics palettes.
[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 /* 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
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 UNREFERENCED_PARAMETER(DeviceExtension);
837 UNREFERENCED_PARAMETER(Irp);
838 return STATUS_NOT_IMPLEMENTED;
839 }
840
841 NTSTATUS
842 MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
843 IN PIRP Irp)
844 {
845 UNREFERENCED_PARAMETER(DeviceExtension);
846 UNREFERENCED_PARAMETER(Irp);
847 return STATUS_NOT_IMPLEMENTED;
848 }
849
850 /*
851 * @implemented
852 */
853 NTSTATUS
854 MountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension,
855 IN PIRP Irp)
856 {
857 NTSTATUS Status;
858 PIO_STACK_LOCATION Stack;
859 UNICODE_STRING SymbolicName;
860 PMOUNTMGR_TARGET_NAME Target;
861 PDEVICE_INFORMATION DeviceInformation;
862
863 Stack = IoGetNextIrpStackLocation(Irp);
864
865 /* Validate input */
866 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
867 {
868 return STATUS_INVALID_PARAMETER;
869 }
870
871 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
872 if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
873 {
874 return STATUS_INVALID_PARAMETER;
875 }
876
877 SymbolicName.Length =
878 SymbolicName.MaximumLength = Target->DeviceNameLength;
879 SymbolicName.Buffer = Target->DeviceName;
880
881 /* Find the associated device */
882 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
883 if (!NT_SUCCESS(Status))
884 {
885 return Status;
886 }
887
888 /* Mark we want to keep links */
889 DeviceInformation->KeepLinks = TRUE;
890
891 return STATUS_SUCCESS;
892 }
893
894 /*
895 * @implemented
896 */
897 NTSTATUS
898 MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension,
899 IN PIRP Irp)
900 {
901 NTSTATUS Status;
902 BOOLEAN OldState;
903 PIO_STACK_LOCATION Stack;
904 UNICODE_STRING SymbolicName;
905 PMOUNTMGR_TARGET_NAME Target;
906
907 Stack = IoGetNextIrpStackLocation(Irp);
908
909 /* Validate input */
910 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
911 {
912 return STATUS_INVALID_PARAMETER;
913 }
914
915 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
916 if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
917 {
918 return STATUS_INVALID_PARAMETER;
919 }
920
921 SymbolicName.Length =
922 SymbolicName.MaximumLength = Target->DeviceNameLength;
923 SymbolicName.Buffer = Target->DeviceName;
924
925 /* Disable hard errors */
926 OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
927 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
928
929 /* Call real worker */
930 Status = MountMgrMountedDeviceArrival(DeviceExtension, &SymbolicName, TRUE);
931
932 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
933
934 return Status;
935 }
936
937 /*
938 * @implemented
939 */
940 NTSTATUS
941 MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension,
942 IN PIRP Irp)
943 {
944 NTSTATUS Status;
945 PIO_STACK_LOCATION Stack;
946 PMOUNTDEV_UNIQUE_ID UniqueId;
947 PMOUNTMGR_MOUNT_POINT MountPoint;
948 UNICODE_STRING SymbolicName, DeviceName;
949
950 Stack = IoGetNextIrpStackLocation(Irp);
951
952 /* Validate input... */
953 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
954 {
955 return STATUS_INVALID_PARAMETER;
956 }
957
958 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
959 if (!MountPoint->SymbolicLinkNameLength)
960 {
961 MountPoint->SymbolicLinkNameOffset = 0;
962 }
963
964 if (!MountPoint->UniqueIdLength)
965 {
966 MountPoint->UniqueIdOffset = 0;
967 }
968
969 if (!MountPoint->DeviceNameLength)
970 {
971 MountPoint->DeviceNameOffset = 0;
972 }
973
974 /* Addresses can't be odd */
975 if ((MountPoint->SymbolicLinkNameOffset & 1) ||
976 (MountPoint->SymbolicLinkNameLength & 1))
977 {
978 return STATUS_INVALID_PARAMETER;
979 }
980
981 if ((MountPoint->UniqueIdOffset & 1) ||
982 (MountPoint->UniqueIdLength & 1))
983 {
984 return STATUS_INVALID_PARAMETER;
985 }
986
987 if ((MountPoint->DeviceNameOffset & 1) ||
988 (MountPoint->DeviceNameLength & 1))
989 {
990 return STATUS_INVALID_PARAMETER;
991 }
992
993 /* We can't go beyond */
994 if (((ULONG)MountPoint->SymbolicLinkNameLength + MountPoint->UniqueIdLength +
995 MountPoint->DeviceNameLength) < Stack->Parameters.DeviceIoControl.InputBufferLength)
996 {
997 return STATUS_INVALID_PARAMETER;
998 }
999
1000 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_MOUNT_POINTS))
1001 {
1002 return STATUS_INVALID_PARAMETER;
1003 }
1004
1005 /* If caller provided a Symlink, use it */
1006 if (MountPoint->SymbolicLinkNameLength != 0)
1007 {
1008 if (MountPoint->SymbolicLinkNameLength > MAXSHORT)
1009 {
1010 return STATUS_INVALID_PARAMETER;
1011 }
1012
1013 SymbolicName.Length = MountPoint->SymbolicLinkNameLength;
1014 SymbolicName.MaximumLength = MountPoint->SymbolicLinkNameLength + sizeof(WCHAR);
1015 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1016 if (!SymbolicName.Buffer)
1017 {
1018 return STATUS_INSUFFICIENT_RESOURCES;
1019 }
1020
1021 RtlCopyMemory(SymbolicName.Buffer,
1022 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->SymbolicLinkNameOffset),
1023 SymbolicName.Length);
1024 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1025
1026 /* Query links using it */
1027 Status = QueryPointsFromSymbolicLinkName(DeviceExtension, &SymbolicName, Irp);
1028 FreePool(SymbolicName.Buffer);
1029 }
1030 /* If user provided an unique ID */
1031 else if (MountPoint->UniqueIdLength != 0)
1032 {
1033 UniqueId = AllocatePool(MountPoint->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1034 if (!UniqueId)
1035 {
1036 return STATUS_INSUFFICIENT_RESOURCES;
1037 }
1038
1039 UniqueId->UniqueIdLength = MountPoint->UniqueIdLength;
1040 RtlCopyMemory(UniqueId->UniqueId,
1041 (PVOID)((ULONG_PTR)MountPoint + MountPoint->UniqueIdOffset),
1042 MountPoint->UniqueIdLength);
1043
1044 /* Query links using it */
1045 Status = QueryPointsFromMemory(DeviceExtension, Irp, UniqueId, NULL);
1046 FreePool(UniqueId);
1047 }
1048 /* If caller provided a device name */
1049 else if (MountPoint->DeviceNameLength != 0)
1050 {
1051 if (MountPoint->DeviceNameLength > MAXSHORT)
1052 {
1053 return STATUS_INVALID_PARAMETER;
1054 }
1055
1056 DeviceName.Length = MountPoint->DeviceNameLength;
1057 DeviceName.MaximumLength = MountPoint->DeviceNameLength + sizeof(WCHAR);
1058 DeviceName.Buffer = AllocatePool(DeviceName.MaximumLength);
1059 if (!DeviceName.Buffer)
1060 {
1061 return STATUS_INSUFFICIENT_RESOURCES;
1062 }
1063
1064 RtlCopyMemory(DeviceName.Buffer,
1065 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->DeviceNameOffset),
1066 DeviceName.Length);
1067 DeviceName.Buffer[DeviceName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1068
1069 /* Query links using it */
1070 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, &DeviceName);
1071 FreePool(DeviceName.Buffer);
1072 }
1073 else
1074 {
1075 /* Otherwise, query all links */
1076 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, NULL);
1077 }
1078
1079 return Status;
1080 }
1081
1082 /*
1083 * @implemented
1084 */
1085 NTSTATUS
1086 MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension,
1087 IN PIRP Irp)
1088 {
1089 ULONG Link;
1090 NTSTATUS Status;
1091 BOOLEAN CreateNoDrive;
1092 PIO_STACK_LOCATION Stack;
1093 PMOUNTDEV_UNIQUE_ID UniqueId;
1094 PMOUNTMGR_MOUNT_POINT MountPoint;
1095 PMOUNTMGR_MOUNT_POINTS MountPoints;
1096 UNICODE_STRING SymbolicName, DeviceName;
1097
1098 Stack = IoGetNextIrpStackLocation(Irp);
1099
1100 /* Validate input */
1101 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
1102 {
1103 return STATUS_INVALID_PARAMETER;
1104 }
1105
1106 /* Query points */
1107 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1108 CreateNoDrive = (MountPoint->SymbolicLinkNameOffset && MountPoint->SymbolicLinkNameLength);
1109
1110 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1111 if (!NT_SUCCESS(Status))
1112 {
1113 return Status;
1114 }
1115
1116 /* For all the points matching the request */
1117 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
1118 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++)
1119 {
1120 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength;
1121 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR);
1122 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1123 if (!SymbolicName.Buffer)
1124 {
1125 return STATUS_INSUFFICIENT_RESOURCES;
1126 }
1127
1128 RtlCopyMemory(SymbolicName.Buffer,
1129 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset),
1130 SymbolicName.Length);
1131 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1132
1133 /* Create a no drive entry for the drive letters */
1134 if (CreateNoDrive && IsDriveLetter(&SymbolicName))
1135 {
1136 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1137 if (UniqueId)
1138 {
1139 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength;
1140 RtlCopyMemory(UniqueId->UniqueId,
1141 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1142 MountPoints->MountPoints[Link].UniqueIdLength);
1143
1144 CreateNoDriveLetterEntry(UniqueId);
1145 FreePool(UniqueId);
1146 }
1147 }
1148
1149 /* If there are no link any more, and no need to create a no drive entry */
1150 if (Link == 0 && !CreateNoDrive)
1151 {
1152 /* Then, delete everything */
1153 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength);
1154 if (UniqueId)
1155 {
1156 RtlCopyMemory(UniqueId,
1157 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1158 MountPoints->MountPoints[Link].UniqueIdLength);
1159
1160 DeleteNoDriveLetterEntry(UniqueId);
1161 FreePool(UniqueId);
1162 }
1163 }
1164
1165 /* Delete all the information about the mount point */
1166 GlobalDeleteSymbolicLink(&SymbolicName);
1167 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, FALSE);
1168 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer);
1169 FreePool(SymbolicName.Buffer);
1170
1171 /* Notify the change */
1172 DeviceName.Length = DeviceName.MaximumLength =
1173 MountPoints->MountPoints[Link].DeviceNameLength;
1174 DeviceName.Buffer = (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].DeviceNameOffset);
1175 MountMgrNotifyNameChange(DeviceExtension, &DeviceName, TRUE);
1176 }
1177
1178 MountMgrNotify(DeviceExtension);
1179
1180 return Status;
1181 }
1182
1183 /*
1184 * @implemented
1185 */
1186 NTSTATUS
1187 MountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension,
1188 IN PIRP Irp)
1189 {
1190 ULONG Link;
1191 NTSTATUS Status;
1192 UNICODE_STRING SymbolicName;
1193 PMOUNTDEV_UNIQUE_ID UniqueId;
1194 PMOUNTMGR_MOUNT_POINTS MountPoints;
1195
1196 /* Query points */
1197 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1198 if (!NT_SUCCESS(Status))
1199 {
1200 return Status;
1201 }
1202
1203 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
1204 if (MountPoints->NumberOfMountPoints == 0)
1205 {
1206 return Status;
1207 }
1208
1209 /* For all the mount points */
1210 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++)
1211 {
1212 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength;
1213 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR);
1214 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1215 if (!SymbolicName.Buffer)
1216 {
1217 return STATUS_INSUFFICIENT_RESOURCES;
1218 }
1219
1220 RtlCopyMemory(SymbolicName.Buffer,
1221 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset),
1222 SymbolicName.Length);
1223 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1224
1225 /* If the only mount point is a drive letter, then create a no letter drive entry */
1226 if (MountPoints->NumberOfMountPoints == 1 && IsDriveLetter(&SymbolicName))
1227 {
1228 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1229 if (UniqueId)
1230 {
1231 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength;
1232 RtlCopyMemory(UniqueId->UniqueId,
1233 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1234 MountPoints->MountPoints[Link].UniqueIdLength);
1235
1236 CreateNoDriveLetterEntry(UniqueId);
1237 FreePool(UniqueId);
1238 }
1239 }
1240
1241 /* Simply delete mount point from DB */
1242 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, TRUE);
1243 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer);
1244 FreePool(SymbolicName.Buffer);
1245 }
1246
1247 return Status;
1248 }
1249
1250 /*
1251 * @implemented
1252 */
1253 NTSTATUS
1254 MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension,
1255 IN PIRP Irp,
1256 IN NTSTATUS LockStatus,
1257 OUT PUNICODE_STRING SourceDeviceName,
1258 OUT PUNICODE_STRING SourceSymbolicName,
1259 OUT PUNICODE_STRING TargetVolumeName)
1260 {
1261 HANDLE Handle;
1262 NTSTATUS Status;
1263 PFILE_OBJECT FileObject;
1264 PIO_STACK_LOCATION Stack;
1265 ULONG Length, SavedLength;
1266 BOOLEAN FOReferenced = FALSE;
1267 IO_STATUS_BLOCK IoStatusBlock;
1268 OBJECT_ATTRIBUTES ObjectAttributes;
1269 PDEVICE_INFORMATION DeviceInformation;
1270 OBJECT_NAME_INFORMATION ObjectNameInfo;
1271 FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
1272 PFILE_NAME_INFORMATION FileNameInfo = NULL;
1273 PMOUNTMGR_VOLUME_MOUNT_POINT VolumeMountPoint;
1274 POBJECT_NAME_INFORMATION ObjectNameInfoPtr = NULL;
1275 UNICODE_STRING SourceVolumeName, TargetDeviceName;
1276
1277 Stack = IoGetNextIrpStackLocation(Irp);
1278
1279 /* Validate input */
1280 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_VOLUME_MOUNT_POINT))
1281 {
1282 return STATUS_INVALID_PARAMETER;
1283 }
1284
1285 VolumeMountPoint = (PMOUNTMGR_VOLUME_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1286
1287 if (((ULONG)VolumeMountPoint->SourceVolumeNameLength + VolumeMountPoint->TargetVolumeNameLength) <
1288 Stack->Parameters.DeviceIoControl.InputBufferLength)
1289 {
1290 return STATUS_INVALID_PARAMETER;
1291 }
1292
1293 /* Get source volume name */
1294 SourceVolumeName.Length =
1295 SourceVolumeName.MaximumLength = VolumeMountPoint->SourceVolumeNameLength;
1296 SourceVolumeName.Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->SourceVolumeNameOffset);
1297
1298 InitializeObjectAttributes(&ObjectAttributes,
1299 &SourceVolumeName,
1300 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
1301 NULL,
1302 NULL);
1303
1304 /* Open it */
1305 Status = ZwOpenFile(&Handle,
1306 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
1307 &ObjectAttributes,
1308 &IoStatusBlock,
1309 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1310 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
1311 if (!NT_SUCCESS(Status))
1312 {
1313 return Status;
1314 }
1315
1316 TargetDeviceName.Buffer = NULL;
1317
1318 /* Query its attributes */
1319 Status = ZwQueryVolumeInformationFile(Handle,
1320 &IoStatusBlock,
1321 &FsDeviceInfo,
1322 sizeof(FsDeviceInfo),
1323 FileFsDeviceInformation);
1324 if (!NT_SUCCESS(Status))
1325 {
1326 goto Cleanup;
1327 }
1328
1329 if (FsDeviceInfo.DeviceType != FILE_DEVICE_DISK && FsDeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK)
1330 {
1331 goto Cleanup;
1332 }
1333
1334 if (FsDeviceInfo.Characteristics != (FILE_REMOTE_DEVICE | FILE_REMOVABLE_MEDIA))
1335 {
1336 goto Cleanup;
1337 }
1338
1339 /* Reference it */
1340 Status = ObReferenceObjectByHandle(Handle, 0, IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL);
1341 if (!NT_SUCCESS(Status))
1342 {
1343 goto Cleanup;
1344 }
1345 FOReferenced = TRUE;
1346
1347 /* Get file name */
1348 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION));
1349 if (!FileNameInfo)
1350 {
1351 Status = STATUS_INSUFFICIENT_RESOURCES;
1352 goto Cleanup;
1353 }
1354
1355 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo,
1356 sizeof(FILE_NAME_INFORMATION),
1357 FileNameInformation);
1358 if (Status == STATUS_BUFFER_OVERFLOW)
1359 {
1360 /* Now we have real length, use it */
1361 Length = FileNameInfo->FileNameLength;
1362 FreePool(FileNameInfo);
1363
1364 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + Length);
1365 if (!FileNameInfo)
1366 {
1367 Status = STATUS_INSUFFICIENT_RESOURCES;
1368 goto Cleanup;
1369 }
1370
1371 /* Really query file name */
1372 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo,
1373 sizeof(FILE_NAME_INFORMATION) + Length,
1374 FileNameInformation);
1375 }
1376
1377 if (!NT_SUCCESS(Status))
1378 {
1379 goto Cleanup;
1380 }
1381
1382 /* Get symbolic name */
1383 ObjectNameInfoPtr = &ObjectNameInfo;
1384 SavedLength = sizeof(OBJECT_NAME_INFORMATION);
1385 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, sizeof(OBJECT_NAME_INFORMATION), &Length);
1386 if (Status == STATUS_INFO_LENGTH_MISMATCH)
1387 {
1388 /* Once again, with proper size, it works better */
1389 ObjectNameInfoPtr = AllocatePool(Length);
1390 if (!ObjectNameInfoPtr)
1391 {
1392 Status = STATUS_INSUFFICIENT_RESOURCES;
1393 goto Cleanup;
1394 }
1395
1396 SavedLength = Length;
1397 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, SavedLength, &Length);
1398 }
1399
1400 if (!NT_SUCCESS(Status))
1401 {
1402 goto Cleanup;
1403 }
1404
1405 /* Now, query the device name */
1406 Status = QueryDeviceInformation(&ObjectNameInfoPtr->Name, SourceDeviceName,
1407 NULL, NULL, NULL, NULL, NULL, NULL);
1408 if (!NT_SUCCESS(Status))
1409 {
1410 goto Cleanup;
1411 }
1412
1413 /* For target volume name, use input */
1414 TargetVolumeName->Length =
1415 TargetVolumeName->MaximumLength = VolumeMountPoint->TargetVolumeNameLength;
1416 TargetVolumeName->Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->TargetVolumeNameOffset);
1417
1418 /* Query its device name */
1419 Status = QueryDeviceInformation(TargetVolumeName, &TargetDeviceName,
1420 NULL, NULL, NULL, NULL, NULL, NULL);
1421 if (!NT_SUCCESS(Status))
1422 {
1423 goto Cleanup;
1424 }
1425
1426 /* Return symbolic name */
1427 SourceSymbolicName->Length =
1428 SourceSymbolicName->MaximumLength = (USHORT)FileNameInfo->FileNameLength;
1429 SourceSymbolicName->Buffer = (PWSTR)FileNameInfo;
1430 /* memmove allows memory overlap */
1431 RtlMoveMemory(SourceSymbolicName->Buffer, FileNameInfo->FileName, SourceSymbolicName->Length);
1432 FileNameInfo = NULL;
1433
1434 /* Notify the change */
1435 MountMgrNotify(DeviceExtension);
1436 MountMgrNotifyNameChange(DeviceExtension, &TargetDeviceName, TRUE);
1437
1438 /* If we are locked, sync databases if possible */
1439 if (NT_SUCCESS(LockStatus))
1440 {
1441 Status = FindDeviceInfo(DeviceExtension, SourceDeviceName, FALSE, &DeviceInformation);
1442 if (NT_SUCCESS(Status))
1443 {
1444 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
1445 }
1446 else
1447 {
1448 Status = STATUS_PENDING;
1449 }
1450 }
1451
1452 Cleanup:
1453 if (TargetDeviceName.Buffer)
1454 {
1455 FreePool(TargetDeviceName.Buffer);
1456 }
1457
1458 if (ObjectNameInfoPtr && ObjectNameInfoPtr != &ObjectNameInfo)
1459 {
1460 FreePool(ObjectNameInfoPtr);
1461 }
1462
1463 if (FileNameInfo)
1464 {
1465 FreePool(FileNameInfo);
1466 }
1467
1468 if (FOReferenced)
1469 {
1470 ObDereferenceObject(FileObject);
1471 }
1472
1473 return Status;
1474 }
1475
1476 NTSTATUS
1477 MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension,
1478 IN PIRP Irp,
1479 IN NTSTATUS LockStatus)
1480 {
1481 UNREFERENCED_PARAMETER(DeviceExtension);
1482 UNREFERENCED_PARAMETER(Irp);
1483 UNREFERENCED_PARAMETER(LockStatus);
1484 return STATUS_NOT_IMPLEMENTED;
1485 }
1486
1487 NTSTATUS
1488 MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension,
1489 IN PIRP Irp,
1490 IN NTSTATUS LockStatus)
1491 {
1492 UNREFERENCED_PARAMETER(DeviceExtension);
1493 UNREFERENCED_PARAMETER(Irp);
1494 UNREFERENCED_PARAMETER(LockStatus);
1495 return STATUS_NOT_IMPLEMENTED;
1496 }
1497
1498 /*
1499 * @implemented
1500 */
1501 NTSTATUS
1502 NTAPI
1503 MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject,
1504 IN PIRP Irp)
1505 {
1506 PIO_STACK_LOCATION Stack;
1507 NTSTATUS Status, LockStatus;
1508 PDEVICE_EXTENSION DeviceExtension;
1509
1510 Stack = IoGetNextIrpStackLocation(Irp);
1511 DeviceExtension = DeviceObject->DeviceExtension;
1512
1513 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1514
1515 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
1516 {
1517 case IOCTL_MOUNTMGR_CREATE_POINT:
1518 Status = MountMgrCreatePoint(DeviceExtension, Irp);
1519 break;
1520
1521 case IOCTL_MOUNTMGR_DELETE_POINTS:
1522 Status = MountMgrDeletePoints(DeviceExtension, Irp);
1523 break;
1524
1525 case IOCTL_MOUNTMGR_QUERY_POINTS:
1526 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1527 break;
1528
1529 case IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY:
1530 Status = MountMgrDeletePointsDbOnly(DeviceExtension, Irp);
1531 break;
1532
1533 case IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER:
1534 Status = MountMgrNextDriveLetter(DeviceExtension, Irp);
1535 break;
1536
1537 case IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS:
1538 DeviceExtension->AutomaticDriveLetter = TRUE;
1539 Status = STATUS_SUCCESS;
1540
1541 MountMgrAssignDriveLetters(DeviceExtension);
1542 ReconcileAllDatabasesWithMaster(DeviceExtension);
1543 WaitForOnlinesToComplete(DeviceExtension);
1544 break;
1545
1546 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED:
1547 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1548
1549 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension);
1550 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1551 Status = MountMgrVolumeMountPointCreated(DeviceExtension, Irp, LockStatus);
1552 if (NT_SUCCESS(LockStatus))
1553 {
1554 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
1555 }
1556
1557 break;
1558
1559 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED:
1560 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1561
1562 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension);
1563 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1564 Status = MountMgrVolumeMountPointDeleted(DeviceExtension, Irp, LockStatus);
1565 if (NT_SUCCESS(LockStatus))
1566 {
1567 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
1568 }
1569
1570 break;
1571
1572 case IOCTL_MOUNTMGR_CHANGE_NOTIFY:
1573 Status = MountMgrChangeNotify(DeviceExtension, Irp);
1574 break;
1575
1576 case IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE:
1577 Status = MountMgrKeepLinksWhenOffline(DeviceExtension, Irp);
1578 break;
1579
1580 case IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES:
1581 Status = MountMgrCheckUnprocessedVolumes(DeviceExtension, Irp);
1582 goto Complete;
1583
1584 case IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION:
1585 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1586 Status = MountMgrVolumeArrivalNotification(DeviceExtension, Irp);
1587 goto Complete;
1588
1589 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH:
1590 Status = MountMgrQueryDosVolumePath(DeviceExtension, Irp);
1591 break;
1592
1593 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS:
1594 Status = MountMgrQueryDosVolumePaths(DeviceExtension, Irp);
1595 break;
1596
1597 case IOCTL_MOUNTMGR_SCRUB_REGISTRY:
1598 Status = MountMgrScrubRegistry(DeviceExtension);
1599 break;
1600
1601 case IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT:
1602 Status = MountMgrQueryAutoMount(DeviceExtension, Irp);
1603 break;
1604
1605 case IOCTL_MOUNTMGR_SET_AUTO_MOUNT:
1606 Status = MountMgrSetAutoMount(DeviceExtension, Irp);
1607 break;
1608
1609 default:
1610 Status = STATUS_INVALID_DEVICE_REQUEST;
1611 }
1612
1613 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1614
1615 if (Status != STATUS_PENDING)
1616 {
1617 goto Complete;
1618 }
1619
1620 return Status;
1621
1622 Complete:
1623 Irp->IoStatus.Status = Status;
1624 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1625
1626 return Status;
1627 }