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