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