1 /*
2 * ReactOS kernel
3 * Copyright (C) 2011-2012 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/mountmgr/device.c
22 * PURPOSE: Mount Manager - Device Control
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
24 */
25
26 #include "mntmgr.h"
27
28 #define MAX_DEVICES 0x3E8 /* Matches 1000 devices */
29
30 #define NDEBUG
31 #include <debug.h>
32
33 /*
34 * @implemented
35 */
36 NTSTATUS
MountMgrChangeNotify(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)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 = sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO);
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
MountmgrWriteNoAutoMount(IN PDEVICE_EXTENSION DeviceExtension)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 * @implemented
101 */
102 NTSTATUS
MountMgrSetAutoMount(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)103 MountMgrSetAutoMount(IN PDEVICE_EXTENSION DeviceExtension,
104 IN PIRP Irp)
105 {
106 PIO_STACK_LOCATION Stack;
107 PMOUNTMGR_SET_AUTO_MOUNT SetState;
108
109 Stack = IoGetCurrentIrpStackLocation(Irp);
110
111 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_SET_AUTO_MOUNT))
112 {
113 Irp->IoStatus.Information = 0;
114 return STATUS_INVALID_PARAMETER;
115 }
116
117 /* Change the state only if there is a real difference
118 * with the user-provided NewState (normalized) */
119 SetState = (PMOUNTMGR_SET_AUTO_MOUNT)Irp->AssociatedIrp.SystemBuffer;
120 if ((SetState->NewState != Enabled) == DeviceExtension->NoAutoMount)
121 {
122 Irp->IoStatus.Information = 0;
123 return STATUS_SUCCESS;
124 }
125
126 /* Set new state */
127 DeviceExtension->NoAutoMount = (SetState->NewState != Enabled);
128 Irp->IoStatus.Information = 0;
129 return MountmgrWriteNoAutoMount(DeviceExtension);
130 }
131
132 /*
133 * @implemented
134 */
135 NTSTATUS
MountMgrQueryAutoMount(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)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
ScrubRegistryRoutine(IN PWSTR ValueName,IN ULONG ValueType,IN PVOID ValueData,IN ULONG ValueLength,IN PVOID Context,IN PVOID EntryContext)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
MountMgrScrubRegistry(IN PDEVICE_EXTENSION DeviceExtension)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
MountMgrCreatePoint(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)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
MountMgrCheckUnprocessedVolumes(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)288 MountMgrCheckUnprocessedVolumes(IN PDEVICE_EXTENSION DeviceExtension,
289 IN PIRP Irp)
290 {
291 PLIST_ENTRY NextEntry;
292 PDEVICE_INFORMATION DeviceInformation;
293 NTSTATUS ArrivalStatus, Status = STATUS_SUCCESS;
294
295 UNREFERENCED_PARAMETER(Irp);
296
297 /* No offline volumes, nothing more to do */
298 if (IsListEmpty(&(DeviceExtension->OfflineDeviceListHead)))
299 {
300 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
301 return STATUS_SUCCESS;
302 }
303
304 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
305
306 /* Reactivate all the offline volumes */
307 while (!IsListEmpty(&(DeviceExtension->OfflineDeviceListHead)))
308 {
309 NextEntry = RemoveHeadList(&(DeviceExtension->OfflineDeviceListHead));
310 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
311
312 ArrivalStatus = MountMgrMountedDeviceArrival(DeviceExtension,
313 &(DeviceInformation->SymbolicName),
314 DeviceInformation->ManuallyRegistered);
315 /* Then, remove them dead information */
316 MountMgrFreeDeadDeviceInfo(DeviceInformation);
317
318 if (NT_SUCCESS(Status))
319 {
320 Status = ArrivalStatus;
321 }
322 }
323
324 return Status;
325 }
326
327 /*
328 * @implemented
329 */
330 BOOLEAN
IsFtVolume(IN PUNICODE_STRING SymbolicName)331 IsFtVolume(IN PUNICODE_STRING SymbolicName)
332 {
333 NTSTATUS Status;
334 PFILE_OBJECT FileObject;
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 return FALSE;
345
346 /* Get attached device */
347 FileDeviceObject = FileObject->DeviceObject;
348 DeviceObject = IoGetAttachedDeviceReference(FileDeviceObject);
349
350 /* FT volume can't be removable */
351 if (FileDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
352 {
353 ObDereferenceObject(DeviceObject);
354 ObDereferenceObject(FileObject);
355 return FALSE;
356 }
357
358 ObDereferenceObject(FileObject);
359
360 /* Get partition information */
361 Status = MountMgrSendSyncDeviceIoCtl(IOCTL_DISK_GET_PARTITION_INFO,
362 DeviceObject,
363 NULL,
364 0,
365 &PartitionInfo,
366 sizeof(PartitionInfo),
367 NULL);
368
369 ObDereferenceObject(DeviceObject);
370 if (!NT_SUCCESS(Status))
371 return FALSE;
372
373 /* Check if this is a FT volume */
374 return IsFTPartition(PartitionInfo.PartitionType);
375 }
376
377 /*
378 * @implemented
379 */
380 VOID
ProcessSuggestedDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)381 ProcessSuggestedDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)
382 {
383 WCHAR NameBuffer[DRIVE_LETTER_LENGTH / sizeof(WCHAR)];
384 PLIST_ENTRY NextEntry;
385 UNICODE_STRING SymbolicName;
386 PDEVICE_INFORMATION DeviceInformation;
387
388 /* No devices? Nothing to do! */
389 if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
390 {
391 return;
392 }
393
394 /* For all the devices */
395 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
396 NextEntry != &(DeviceExtension->DeviceListHead);
397 NextEntry = NextEntry->Flink)
398 {
399 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
400
401 /* If no drive letter */
402 if (DeviceInformation->SuggestedDriveLetter == (UCHAR)-1)
403 {
404 /* Ensure it has no entry yet */
405 if (!HasDriveLetter(DeviceInformation) &&
406 !HasNoDriveLetterEntry(DeviceInformation->UniqueId))
407 {
408 /* And create one */
409 CreateNoDriveLetterEntry(DeviceInformation->UniqueId);
410 }
411
412 DeviceInformation->SuggestedDriveLetter = 0;
413 }
414 /* Suggested letter & no entry */
415 else if (DeviceInformation->SuggestedDriveLetter &&
416 !HasNoDriveLetterEntry(DeviceInformation->UniqueId))
417 {
418 /* Just create a mount point */
419 SymbolicName.Buffer = NameBuffer;
420 RtlCopyMemory(NameBuffer, DosDevices.Buffer, DosDevices.Length);
421 NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter;
422 NameBuffer[COLON_POSITION] = L':';
423 SymbolicName.Length =
424 SymbolicName.MaximumLength = DRIVE_LETTER_LENGTH;
425
426 MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &(DeviceInformation->DeviceName));
427 }
428 }
429 }
430
431 /*
432 * @implemented
433 */
434 NTSTATUS
MountMgrNextDriveLetterWorker(IN PDEVICE_EXTENSION DeviceExtension,IN PUNICODE_STRING DeviceName,OUT PMOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInfo)435 MountMgrNextDriveLetterWorker(IN PDEVICE_EXTENSION DeviceExtension,
436 IN PUNICODE_STRING DeviceName,
437 OUT PMOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInfo)
438 {
439 NTSTATUS Status;
440 UCHAR DriveLetter;
441 PLIST_ENTRY NextEntry;
442 PMOUNTDEV_UNIQUE_ID UniqueId;
443 BOOLEAN Removable, GptDriveLetter;
444 PDEVICE_INFORMATION DeviceInformation;
445 WCHAR NameBuffer[DRIVE_LETTER_LENGTH];
446 PSYMLINK_INFORMATION SymlinkInformation;
447 UNICODE_STRING TargetDeviceName, SymbolicName;
448
449 /* First, process suggested letters */
450 if (!DeviceExtension->ProcessedSuggestions)
451 {
452 ProcessSuggestedDriveLetters(DeviceExtension);
453 DeviceExtension->ProcessedSuggestions = TRUE;
454 }
455
456 /* Then, get information about the device */
457 Status = QueryDeviceInformation(DeviceName, &TargetDeviceName, NULL, &Removable, &GptDriveLetter, NULL, NULL, NULL);
458 if (!NT_SUCCESS(Status))
459 {
460 return Status;
461 }
462
463 /* Ensure we have such device */
464 NextEntry = DeviceExtension->DeviceListHead.Flink;
465 while (NextEntry != &(DeviceExtension->DeviceListHead))
466 {
467 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
468
469 if (RtlCompareUnicodeString(&(DeviceInformation->DeviceName), &TargetDeviceName, TRUE) == 0)
470 {
471 break;
472 }
473
474 NextEntry = NextEntry->Flink;
475 }
476
477 if (NextEntry == &(DeviceExtension->DeviceListHead))
478 {
479 FreePool(TargetDeviceName.Buffer);
480 return STATUS_OBJECT_NAME_NOT_FOUND;
481 }
482
483 /* Now, assume we will assign a letter */
484 DeviceInformation->LetterAssigned =
485 DriveLetterInfo->DriveLetterWasAssigned = TRUE;
486
487 /* Browse all the symlinks to check if there is already a drive letter */
488 NextEntry = DeviceInformation->SymbolicLinksListHead.Flink;
489 while (NextEntry != &(DeviceInformation->SymbolicLinksListHead))
490 {
491 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
492
493 /* If this is a drive letter and it is online, forget about new drive letter */
494 if (IsDriveLetter(&(SymlinkInformation->Name)) && SymlinkInformation->Online)
495 {
496 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
497 DriveLetterInfo->CurrentDriveLetter = (CHAR)SymlinkInformation->Name.Buffer[LETTER_POSITION];
498 break;
499 }
500
501 NextEntry = NextEntry->Flink;
502 }
503
504 /* If we didn't find a drive letter online, ensure this is not
505 * a no-drive entry by querying GPT attributes & database */
506 if (NextEntry == &(DeviceInformation->SymbolicLinksListHead))
507 {
508 if (!GptDriveLetter || HasNoDriveLetterEntry(DeviceInformation->UniqueId))
509 {
510 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
511 DriveLetterInfo->CurrentDriveLetter = 0;
512 goto Release;
513 }
514 }
515
516 /* If automount is disabled, and the device is not removable
517 * but needs a drive letter, don't assign one and bail out */
518 if (DeviceExtension->NoAutoMount && !Removable)
519 {
520 if (DriveLetterInfo->DriveLetterWasAssigned)
521 {
522 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
523 DriveLetterInfo->CurrentDriveLetter = 0;
524 goto Release;
525 }
526 }
527
528 /* Stop now if we don't need to assign the drive a letter */
529 if (!DriveLetterInfo->DriveLetterWasAssigned)
530 goto Release;
531
532 /* Now everything is fine, begin drive letter assignment */
533
534 if (RtlPrefixUnicodeString(&DeviceFloppy, &TargetDeviceName, TRUE))
535 {
536 /* If the device is a floppy, start with letter A */
537 DriveLetter = 'A';
538 }
539 else if (RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE))
540 {
541 /* If the device is a CD-ROM, start with letter D */
542 DriveLetter = 'D';
543 }
544 else
545 {
546 /* Finally, if it's a disk, use C */
547 DriveLetter = 'C';
548 }
549
550 /* We cannot set NO drive letter */
551 ASSERT(DeviceInformation->SuggestedDriveLetter != (UCHAR)-1);
552
553 /* If we don't have suggested letter but it's a FT volume, fail */
554 if (!DeviceInformation->SuggestedDriveLetter && IsFtVolume(&(DeviceInformation->DeviceName)))
555 {
556 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
557 DriveLetterInfo->CurrentDriveLetter = 0;
558 goto Release;
559 }
560
561 /* Prepare buffer */
562 RtlCopyMemory(NameBuffer, DosDevices.Buffer, DosDevices.Length);
563 NameBuffer[COLON_POSITION] = L':';
564 SymbolicName.Buffer = NameBuffer;
565 SymbolicName.Length =
566 SymbolicName.MaximumLength = DRIVE_LETTER_LENGTH;
567
568 /* It's all prepared, create mount point */
569 if (DeviceInformation->SuggestedDriveLetter)
570 {
571 DriveLetterInfo->CurrentDriveLetter = DeviceInformation->SuggestedDriveLetter;
572 NameBuffer[LETTER_POSITION] = DeviceInformation->SuggestedDriveLetter;
573
574 Status = MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &TargetDeviceName);
575 if (NT_SUCCESS(Status))
576 {
577 goto Release;
578 }
579 }
580
581 /* It failed with this letter... Try another one! */
582 for (DriveLetterInfo->CurrentDriveLetter = DriveLetter;
583 DriveLetterInfo->CurrentDriveLetter <= L'Z';
584 DriveLetterInfo->CurrentDriveLetter++)
585 {
586 NameBuffer[LETTER_POSITION] = DriveLetterInfo->CurrentDriveLetter;
587
588 Status = MountMgrCreatePointWorker(DeviceExtension, &SymbolicName, &TargetDeviceName);
589 if (NT_SUCCESS(Status))
590 {
591 break;
592 }
593 }
594
595 /* We failed setting a letter */
596 if (DriveLetterInfo->CurrentDriveLetter > L'Z')
597 {
598 DriveLetterInfo->DriveLetterWasAssigned = FALSE;
599 DriveLetterInfo->CurrentDriveLetter = 0;
600
601 /* Try at least to add a no drive letter entry */
602 Status = QueryDeviceInformation(&TargetDeviceName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL);
603 if (NT_SUCCESS(Status))
604 {
605 CreateNoDriveLetterEntry(UniqueId);
606 FreePool(UniqueId);
607 }
608 }
609
610 Release:
611 FreePool(TargetDeviceName.Buffer);
612
613 return STATUS_SUCCESS;
614 }
615
616
617 /*
618 * @implemented
619 */
620 NTSTATUS
MountMgrNextDriveLetter(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)621 MountMgrNextDriveLetter(IN PDEVICE_EXTENSION DeviceExtension,
622 IN PIRP Irp)
623 {
624 NTSTATUS Status;
625 PIO_STACK_LOCATION Stack;
626 UNICODE_STRING DeviceName;
627 PMOUNTMGR_DRIVE_LETTER_TARGET DriveLetterTarget;
628 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
629
630 Stack = IoGetCurrentIrpStackLocation(Irp);
631
632 /* Validate input */
633 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) ||
634 Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION))
635 {
636 return STATUS_INVALID_PARAMETER;
637 }
638
639 DriveLetterTarget = (PMOUNTMGR_DRIVE_LETTER_TARGET)Irp->AssociatedIrp.SystemBuffer;
640 if (DriveLetterTarget->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
641 {
642 return STATUS_INVALID_PARAMETER;
643 }
644
645 /* Call the worker */
646 DeviceName.Buffer = DriveLetterTarget->DeviceName;
647 DeviceName.Length =
648 DeviceName.MaximumLength = DriveLetterTarget->DeviceNameLength;
649
650 Status = MountMgrNextDriveLetterWorker(DeviceExtension, &DeviceName,
651 &DriveLetterInformation);
652 if (NT_SUCCESS(Status))
653 {
654 *(PMOUNTMGR_DRIVE_LETTER_INFORMATION)Irp->AssociatedIrp.SystemBuffer =
655 DriveLetterInformation;
656 Irp->IoStatus.Information = sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION);
657 }
658
659 return Status;
660 }
661
662 /*
663 * @implemented
664 */
665 NTSTATUS
666 NTAPI
MountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName,IN ULONG ValueType,IN PVOID ValueData,IN ULONG ValueLength,IN PVOID Context,IN PVOID EntryContext)667 MountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName,
668 IN ULONG ValueType,
669 IN PVOID ValueData,
670 IN ULONG ValueLength,
671 IN PVOID Context,
672 IN PVOID EntryContext)
673 {
674 UNICODE_STRING ValueString;
675 PUNICODE_STRING SystemVolumeName;
676
677 UNREFERENCED_PARAMETER(ValueName);
678 UNREFERENCED_PARAMETER(ValueLength);
679 UNREFERENCED_PARAMETER(EntryContext);
680
681 if (ValueType != REG_SZ)
682 {
683 return STATUS_SUCCESS;
684 }
685
686 RtlInitUnicodeString(&ValueString, ValueData);
687 SystemVolumeName = Context;
688
689 /* Return a string containing system volume name */
690 SystemVolumeName->Length = ValueString.Length;
691 SystemVolumeName->MaximumLength = ValueString.Length + sizeof(WCHAR);
692 SystemVolumeName->Buffer = AllocatePool(SystemVolumeName->MaximumLength);
693 if (SystemVolumeName->Buffer)
694 {
695 RtlCopyMemory(SystemVolumeName->Buffer, ValueData, ValueString.Length);
696 SystemVolumeName->Buffer[ValueString.Length / sizeof(WCHAR)] = UNICODE_NULL;
697 }
698
699 return STATUS_SUCCESS;
700
701 }
702
703 /*
704 * @implemented
705 */
706 NTSTATUS
MountMgrQuerySystemVolumeName(OUT PUNICODE_STRING SystemVolumeName)707 MountMgrQuerySystemVolumeName(OUT PUNICODE_STRING SystemVolumeName)
708 {
709 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
710
711 RtlZeroMemory(QueryTable, sizeof(QueryTable));
712 QueryTable[0].QueryRoutine = MountMgrQuerySystemVolumeNameQueryRoutine;
713 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
714 QueryTable[0].Name = L"SystemPartition";
715
716 SystemVolumeName->Buffer = NULL;
717
718 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
719 L"\\Registry\\Machine\\System\\Setup",
720 QueryTable,
721 SystemVolumeName,
722 NULL);
723
724 if (SystemVolumeName->Buffer)
725 {
726 return STATUS_SUCCESS;
727 }
728
729 return STATUS_UNSUCCESSFUL;
730 }
731
732 /*
733 * @implemented
734 */
735 VOID
MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)736 MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)
737 {
738 NTSTATUS Status;
739 PLIST_ENTRY NextEntry;
740 UNICODE_STRING SystemVolumeName;
741 PDEVICE_INFORMATION DeviceInformation;
742 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
743
744 /* First, get system volume name */
745 Status = MountMgrQuerySystemVolumeName(&SystemVolumeName);
746
747 /* If there are no device, it's all done */
748 if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
749 {
750 if (NT_SUCCESS(Status))
751 {
752 FreePool(SystemVolumeName.Buffer);
753 }
754
755 return;
756 }
757
758 /* Now, for all the devices... */
759 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
760 NextEntry != &(DeviceExtension->DeviceListHead);
761 NextEntry = NextEntry->Flink)
762 {
763 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
764
765 /* If the device doesn't have a letter assigned, do it! */
766 if (!DeviceInformation->LetterAssigned)
767 {
768 MountMgrNextDriveLetterWorker(DeviceExtension,
769 &(DeviceInformation->DeviceName),
770 &DriveLetterInformation);
771 }
772
773 /* If it's the system volume */
774 if (NT_SUCCESS(Status) && RtlEqualUnicodeString(&SystemVolumeName, &(DeviceInformation->DeviceName), TRUE))
775 {
776 /* Keep track of it */
777 DeviceExtension->DriveLetterData = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength +
778 sizeof(MOUNTDEV_UNIQUE_ID));
779 if (DeviceExtension->DriveLetterData)
780 {
781 RtlCopyMemory(DeviceExtension->DriveLetterData,
782 DeviceInformation->UniqueId,
783 DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
784 }
785
786 /* Ensure it gets mounted if automount is disabled */
787 if (DeviceExtension->NoAutoMount)
788 {
789 /* Temporarily re-enable automount for the
790 * worker to mount and set a drive letter */
791 DeviceExtension->NoAutoMount = FALSE;
792
793 MountMgrNextDriveLetterWorker(DeviceExtension,
794 &(DeviceInformation->DeviceName),
795 &DriveLetterInformation);
796
797 /* And re-disable automount */
798 DeviceExtension->NoAutoMount = TRUE;
799 }
800 }
801 }
802
803 if (NT_SUCCESS(Status))
804 {
805 FreePool(SystemVolumeName.Buffer);
806 }
807 }
808
809 /*
810 * @implemented
811 */
812 NTSTATUS
MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)813 MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,
814 IN PIRP Irp)
815 {
816 NTSTATUS Status;
817 ULONG DevicesFound;
818 PIO_STACK_LOCATION Stack;
819 PLIST_ENTRY SymlinksEntry;
820 UNICODE_STRING SymbolicName;
821 PMOUNTMGR_TARGET_NAME Target;
822 PWSTR DeviceString, OldBuffer;
823 USHORT DeviceLength, OldLength;
824 PDEVICE_INFORMATION DeviceInformation;
825 PSYMLINK_INFORMATION SymlinkInformation;
826 PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
827
828 Stack = IoGetCurrentIrpStackLocation(Irp);
829
830 /* Validate input size */
831 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
832 {
833 return STATUS_INVALID_PARAMETER;
834 }
835
836 /* Ensure we have received UNICODE_STRING */
837 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
838 if (Target->DeviceNameLength & 1)
839 {
840 return STATUS_INVALID_PARAMETER;
841 }
842
843 /* Validate the entry structure size */
844 if ((FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceNameLength) + Target->DeviceNameLength) >
845 Stack->Parameters.DeviceIoControl.InputBufferLength)
846 {
847 return STATUS_INVALID_PARAMETER;
848 }
849
850 /* Ensure we can at least return needed size */
851 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
852 {
853 return STATUS_INVALID_PARAMETER;
854 }
855
856 /* Construct string for query */
857 SymbolicName.Length = Target->DeviceNameLength;
858 SymbolicName.MaximumLength = Target->DeviceNameLength;
859 SymbolicName.Buffer = Target->DeviceName;
860
861 /* Find device with our info */
862 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
863 if (!NT_SUCCESS(Status))
864 {
865 return Status;
866 }
867
868 DeviceLength = 0;
869 DeviceString = NULL;
870 DevicesFound = 0;
871
872 /* Try to find associated device info */
873 while (TRUE)
874 {
875 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
876 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
877 SymlinksEntry = SymlinksEntry->Flink)
878 {
879 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
880
881 /* Try to find with drive letter */
882 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online)
883 {
884 break;
885 }
886 }
887
888 /* We didn't find, break */
889 if (SymlinksEntry == &(DeviceInformation->SymbolicLinksListHead))
890 {
891 return STATUS_NOT_FOUND;
892 }
893
894 /* It doesn't have associated device, go to fallback method */
895 if (IsListEmpty(&DeviceInformation->AssociatedDevicesHead))
896 {
897 goto TryWithVolumeName;
898 }
899
900 /* Create a string with the information about the device */
901 AssociatedDevice = CONTAINING_RECORD(&(DeviceInformation->SymbolicLinksListHead), ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
902 OldLength = DeviceLength;
903 OldBuffer = DeviceString;
904 DeviceLength += AssociatedDevice->String.Length;
905 DeviceString = AllocatePool(DeviceLength);
906 if (!DeviceString)
907 {
908 if (OldBuffer)
909 {
910 FreePool(OldBuffer);
911 }
912
913 return STATUS_INSUFFICIENT_RESOURCES;
914 }
915
916 /* Store our info and previous if any */
917 RtlCopyMemory(DeviceString, AssociatedDevice->String.Buffer, AssociatedDevice->String.Length);
918 if (OldBuffer)
919 {
920 RtlCopyMemory(&DeviceString[AssociatedDevice->String.Length / sizeof(WCHAR)], OldBuffer, OldLength);
921 FreePool(OldBuffer);
922 }
923
924 /* Count and continue looking */
925 ++DevicesFound;
926 DeviceInformation = AssociatedDevice->DeviceInformation;
927
928 /* If too many devices, try another way */
929 if (DevicesFound > MAX_DEVICES) /* 1000 */
930 {
931 goto TryWithVolumeName;
932 }
933 }
934
935 /* Reallocate our string, so that we can prepend disk letter */
936 OldBuffer = DeviceString;
937 OldLength = DeviceLength;
938 DeviceLength += 2 * sizeof(WCHAR);
939 DeviceString = AllocatePool(DeviceLength);
940 if (!DeviceString)
941 {
942 if (OldBuffer)
943 {
944 FreePool(OldBuffer);
945 }
946
947 return STATUS_INSUFFICIENT_RESOURCES;
948 }
949
950 /* Get the letter */
951 DeviceString[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION];
952 DeviceString[1] = L':';
953
954 /* And copy the rest */
955 if (OldBuffer)
956 {
957 RtlCopyMemory(&DeviceString[2], OldBuffer, OldLength);
958 FreePool(OldBuffer);
959 }
960
961 TryWithVolumeName:
962 /* If we didn't find anything, try differently */
963 if (DeviceLength < 2 * sizeof(WCHAR) || DeviceString[1] != L':')
964 {
965 if (DeviceString)
966 {
967 FreePool(DeviceString);
968 DeviceLength = 0;
969 }
970
971 /* Try to find a volume name matching */
972 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
973 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
974 SymlinksEntry = SymlinksEntry->Flink)
975 {
976 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
977
978 if (MOUNTMGR_IS_VOLUME_NAME(&SymlinkInformation->Name))
979 {
980 break;
981 }
982 }
983
984 /* If found copy */
985 if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead))
986 {
987 DeviceLength = SymlinkInformation->Name.Length;
988 DeviceString = AllocatePool(DeviceLength);
989 if (!DeviceString)
990 {
991 return STATUS_INSUFFICIENT_RESOURCES;
992 }
993
994 RtlCopyMemory(DeviceString, SymlinkInformation->Name.Buffer, DeviceLength);
995 /* Ensure we are in the right namespace; [1] can be ? */
996 DeviceString[1] = L'\\';
997 }
998 }
999
1000 /* If we found something */
1001 if (DeviceString)
1002 {
1003 /* At least, we will return our length */
1004 ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSzLength = DeviceLength;
1005 /* MOUNTMGR_VOLUME_PATHS is a string + a ULONG */
1006 Irp->IoStatus.Information = DeviceLength + sizeof(ULONG);
1007
1008 /* If we have enough room for copying the string */
1009 if (sizeof(ULONG) + DeviceLength <= Stack->Parameters.DeviceIoControl.OutputBufferLength)
1010 {
1011 /* Copy it */
1012 if (DeviceLength)
1013 {
1014 RtlCopyMemory(((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz, DeviceString, DeviceLength);
1015 }
1016
1017 /* And double zero at its end - this is needed in case of multiple paths which are separated by a single 0 */
1018 FreePool(DeviceString);
1019 ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz[DeviceLength / sizeof(WCHAR)] = 0;
1020 ((PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer)->MultiSz[DeviceLength / sizeof(WCHAR) + 1] = 0;
1021
1022 return STATUS_SUCCESS;
1023 }
1024 else
1025 {
1026 /* Just return appropriate size and leave */
1027 FreePool(DeviceString);
1028 Irp->IoStatus.Information = sizeof(ULONG);
1029 return STATUS_BUFFER_OVERFLOW;
1030 }
1031 }
1032
1033 /* Fail */
1034 return STATUS_NOT_FOUND;
1035 }
1036
1037 /*
1038 * @implemented
1039 */
1040 NTSTATUS
MountMgrValidateBackPointer(IN PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry,IN PDEVICE_INFORMATION DeviceInformation,OUT PBOOLEAN Invalid)1041 MountMgrValidateBackPointer(IN PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry,
1042 IN PDEVICE_INFORMATION DeviceInformation,
1043 OUT PBOOLEAN Invalid)
1044 {
1045 HANDLE Handle;
1046 NTSTATUS Status;
1047 PLIST_ENTRY SymlinksEntry;
1048 IO_STATUS_BLOCK IoStatusBlock;
1049 PREPARSE_DATA_BUFFER ReparseData;
1050 OBJECT_ATTRIBUTES ObjectAttributes;
1051 UNICODE_STRING FullName, SubstituteName;
1052 PSYMLINK_INFORMATION SymlinkInformation;
1053
1054 /* Initialize & allocate a string big enough to contain our complete mount point name */
1055 FullName.Length = 0;
1056 FullName.MaximumLength = AssociatedDeviceEntry->String.Length
1057 + AssociatedDeviceEntry->DeviceInformation->DeviceName.Length
1058 + sizeof(WCHAR)
1059 + sizeof(UNICODE_NULL);
1060 FullName.Buffer = AllocatePool(FullName.MaximumLength);
1061 if (!FullName.Buffer)
1062 {
1063 return STATUS_INSUFFICIENT_RESOURCES;
1064 }
1065
1066 /* Create the path */
1067 RtlAppendUnicodeStringToString(&FullName, &AssociatedDeviceEntry->DeviceInformation->DeviceName);
1068 FullName.Buffer[FullName.Length / sizeof(WCHAR)] = L'\\';
1069 RtlAppendUnicodeStringToString(&FullName, &AssociatedDeviceEntry->String);
1070 FullName.Buffer[FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1071
1072 /* Open it to query the reparse point */
1073 InitializeObjectAttributes(&ObjectAttributes,
1074 &FullName,
1075 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1076 NULL,
1077 NULL);
1078 Status = ZwOpenFile(&Handle,
1079 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
1080 &ObjectAttributes, &IoStatusBlock,
1081 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1082 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
1083 FreePool(FullName.Buffer);
1084
1085 if (!NT_SUCCESS(Status))
1086 {
1087 *Invalid = TRUE;
1088 return STATUS_SUCCESS;
1089 }
1090
1091 /* Allocate a buffer big enough to read reparse data */
1092 ReparseData = AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1093 if (ReparseData == NULL)
1094 {
1095 ZwClose(Handle);
1096 return STATUS_INSUFFICIENT_RESOURCES;
1097 }
1098
1099 /* Query reparse data */
1100 Status = ZwFsControlFile(Handle,
1101 NULL, NULL, NULL,
1102 &IoStatusBlock,
1103 FSCTL_GET_REPARSE_POINT,
1104 NULL, 0,
1105 ReparseData, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1106 ZwClose(Handle);
1107
1108 if (!NT_SUCCESS(Status))
1109 {
1110 FreePool(ReparseData);
1111 *Invalid = TRUE;
1112 return STATUS_SUCCESS;
1113 }
1114
1115 /* Create a string with the substitute name */
1116 SubstituteName.Length = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
1117 SubstituteName.MaximumLength = SubstituteName.Length;
1118 SubstituteName.Buffer = (PWSTR)((ULONG_PTR)ReparseData->SymbolicLinkReparseBuffer.PathBuffer + ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset);
1119
1120 /* If that's a volume name that matches our associated device, that's a success! */
1121 if (MOUNTMGR_IS_VOLUME_NAME(&SubstituteName))
1122 {
1123 if (SubstituteName.Length == 98 && SubstituteName.Buffer[1] == L'?')
1124 {
1125 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
1126 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
1127 SymlinksEntry = SymlinksEntry->Flink)
1128 {
1129 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
1130
1131 if (RtlEqualUnicodeString(&SubstituteName, &SymlinkInformation->Name, TRUE))
1132 {
1133 FreePool(ReparseData);
1134 return STATUS_SUCCESS;
1135 }
1136 }
1137 }
1138 }
1139
1140 FreePool(ReparseData);
1141 *Invalid = TRUE;
1142 return STATUS_SUCCESS;
1143 }
1144
1145 /*
1146 * @implemented
1147 */
1148 NTSTATUS
MountMgrQueryVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,IN PDEVICE_INFORMATION DeviceInformation,IN PLIST_ENTRY DeviceInfoList,OUT PMOUNTMGR_VOLUME_PATHS * VolumePaths,OUT PDEVICE_INFORMATION * FailedDevice)1149 MountMgrQueryVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
1150 IN PDEVICE_INFORMATION DeviceInformation,
1151 IN PLIST_ENTRY DeviceInfoList,
1152 OUT PMOUNTMGR_VOLUME_PATHS * VolumePaths,
1153 OUT PDEVICE_INFORMATION *FailedDevice)
1154 {
1155 ULONG Written;
1156 NTSTATUS Status;
1157 PLIST_ENTRY Entry;
1158 PSYMLINK_INFORMATION SymlinkInformation;
1159 PDEVICE_INFORMATION_ENTRY DeviceInfoEntry;
1160 PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry;
1161 PMOUNTMGR_VOLUME_PATHS * Paths = NULL, * CurrentPath;
1162 ULONG OutputPathLength, NumberOfPaths, ReturnedPaths;
1163
1164 /* We return at least null char */
1165 OutputPathLength = sizeof(UNICODE_NULL);
1166
1167 for (Entry = DeviceInformation->SymbolicLinksListHead.Flink;
1168 Entry != &(DeviceInformation->SymbolicLinksListHead);
1169 Entry = Entry->Flink)
1170 {
1171 SymlinkInformation = CONTAINING_RECORD(Entry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
1172
1173 /* Try to find the drive letter (ie, DOS device) */
1174 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online)
1175 {
1176 /* We'll return the letter */
1177 OutputPathLength = 4 * sizeof(WCHAR);
1178 break;
1179 }
1180 }
1181
1182 /* We didn't find any */
1183 if (Entry == &(DeviceInformation->SymbolicLinksListHead))
1184 {
1185 SymlinkInformation = NULL;
1186 }
1187
1188 /* Do we have any device info to return? */
1189 for (Entry = DeviceInfoList->Flink; Entry != DeviceInfoList; Entry = Entry->Flink)
1190 {
1191 DeviceInfoEntry = CONTAINING_RECORD(Entry, DEVICE_INFORMATION_ENTRY, DeviceInformationEntry);
1192
1193 /* Matching current device */
1194 if (DeviceInfoEntry->DeviceInformation == DeviceInformation)
1195 {
1196 /* Allocate the output buffer */
1197 *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength);
1198 if (*VolumePaths == NULL)
1199 {
1200 return STATUS_INSUFFICIENT_RESOURCES;
1201 }
1202
1203 /* Set size */
1204 (*VolumePaths)->MultiSzLength = OutputPathLength;
1205 /* If we have a drive letter, return it */
1206 if (SymlinkInformation != NULL)
1207 {
1208 (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION];
1209 (*VolumePaths)->MultiSz[1] = L':';
1210 (*VolumePaths)->MultiSz[2] = UNICODE_NULL;
1211 (*VolumePaths)->MultiSz[3] = UNICODE_NULL;
1212 }
1213 else
1214 {
1215 (*VolumePaths)->MultiSz[0] = UNICODE_NULL;
1216 }
1217
1218 return STATUS_SUCCESS;
1219 }
1220 }
1221
1222 /* Allocate a new device entry */
1223 DeviceInfoEntry = AllocatePool(sizeof(DEVICE_INFORMATION_ENTRY));
1224 if (DeviceInfoEntry == NULL)
1225 {
1226 return STATUS_INSUFFICIENT_RESOURCES;
1227 }
1228
1229 /* Add it to the list */
1230 DeviceInfoEntry->DeviceInformation = DeviceInformation;
1231 InsertTailList(DeviceInfoList, &DeviceInfoEntry->DeviceInformationEntry);
1232
1233 NumberOfPaths = 0;
1234 /* Count the amount of devices we will have to handle */
1235 if (!IsListEmpty(&DeviceInformation->AssociatedDevicesHead))
1236 {
1237 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink;
1238 Entry != &DeviceInformation->AssociatedDevicesHead;
1239 Entry = Entry->Flink)
1240 {
1241 ++NumberOfPaths;
1242 }
1243
1244 ASSERT(NumberOfPaths != 0);
1245 /* And allocate a big enough buffer */
1246 Paths = AllocatePool(NumberOfPaths * sizeof(PMOUNTMGR_VOLUME_PATHS));
1247 if (Paths == NULL)
1248 {
1249 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
1250 FreePool(DeviceInfoEntry);
1251 return STATUS_INSUFFICIENT_RESOURCES;
1252 }
1253 }
1254
1255 /* Start the hot loop to gather all the paths and be able to compute total output length! */
1256 ReturnedPaths = 0;
1257 CurrentPath = Paths;
1258 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink;
1259 Entry != &DeviceInformation->AssociatedDevicesHead;
1260 Entry = Entry->Flink)
1261 {
1262 USHORT InnerStrings;
1263 BOOLEAN Invalid = FALSE;
1264
1265 AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
1266
1267 /* Validate the fact its a mount point by query reparse data */
1268 Status = MountMgrValidateBackPointer(AssociatedDeviceEntry, DeviceInformation, &Invalid);
1269
1270 /* If we found an invalid device, that's a failure */
1271 if (Invalid)
1272 {
1273 *FailedDevice = AssociatedDeviceEntry->DeviceInformation;
1274 Status = STATUS_UNSUCCESSFUL;
1275 }
1276
1277 /* Check whether we failed, if so, bail out */
1278 if (!NT_SUCCESS(Status))
1279 {
1280 ULONG i;
1281
1282 for (i = 0; i < ReturnedPaths; ++i)
1283 {
1284 FreePool(Paths[i]);
1285 }
1286
1287 if (Paths != NULL)
1288 {
1289 FreePool(Paths);
1290 }
1291 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
1292 FreePool(DeviceInfoEntry);
1293 return Status;
1294 }
1295
1296 /* Query associated paths (hello ourselves :-)) */
1297 Status = MountMgrQueryVolumePaths(DeviceExtension,
1298 AssociatedDeviceEntry->DeviceInformation,
1299 DeviceInfoList,
1300 CurrentPath,
1301 FailedDevice);
1302 if (!NT_SUCCESS(Status))
1303 {
1304 ULONG i;
1305
1306 for (i = 0; i < ReturnedPaths; ++i)
1307 {
1308 FreePool(Paths[i]);
1309 }
1310
1311 if (Paths != NULL)
1312 {
1313 FreePool(Paths);
1314 }
1315 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
1316 FreePool(DeviceInfoEntry);
1317 return Status;
1318 }
1319
1320 /* Count the number of strings we have in the multi string buffer */
1321 InnerStrings = 0;
1322 if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL))
1323 {
1324 ULONG i;
1325 PWSTR MultiSz = (*CurrentPath)->MultiSz;
1326
1327 for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR); ++i, ++MultiSz)
1328 {
1329 if (*MultiSz == UNICODE_NULL)
1330 {
1331 ++InnerStrings;
1332 }
1333 }
1334 }
1335
1336 /* We returned one more path (ie, one more allocated buffer) */
1337 ++ReturnedPaths;
1338 /* Move the next pointer to use in the array */
1339 ++CurrentPath;
1340 /* Multiply String.Length by the number of found paths, we always add it after a path */
1341 OutputPathLength += (*CurrentPath)->MultiSzLength + InnerStrings * AssociatedDeviceEntry->String.Length - sizeof(UNICODE_NULL);
1342 }
1343
1344 /* Allocate the output buffer */
1345 *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength);
1346 if (*VolumePaths == NULL)
1347 {
1348 ULONG i;
1349
1350 for (i = 0; i < ReturnedPaths; ++i)
1351 {
1352 FreePool(Paths[i]);
1353 }
1354
1355 if (Paths != NULL)
1356 {
1357 FreePool(Paths);
1358 }
1359 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
1360 FreePool(DeviceInfoEntry);
1361 return STATUS_INSUFFICIENT_RESOURCES;
1362 }
1363
1364 Written = 0;
1365 /* If we had found a DOS letter, that's the first thing we return */
1366 (*VolumePaths)->MultiSzLength = OutputPathLength;
1367 if (SymlinkInformation != NULL)
1368 {
1369 (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION];
1370 (*VolumePaths)->MultiSz[1] = L':';
1371 (*VolumePaths)->MultiSz[2] = UNICODE_NULL;
1372 Written = 3;
1373 }
1374
1375 /* Now, browse again all our paths to return them */
1376 CurrentPath = Paths;
1377 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink;
1378 Entry != &DeviceInformation->AssociatedDevicesHead;
1379 Entry = Entry->Flink)
1380 {
1381 AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
1382
1383 /* If we had a path... */
1384 if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL))
1385 {
1386 ULONG i, Offset;
1387 PWSTR MultiSz;
1388
1389 /* This offset is used to "jump" into MultiSz, so, start with the string begin (ie, skip MultiSzLength) */
1390 Offset = sizeof(ULONG);
1391 /* Browse every single letter, and skip last UNICODE_NULL */
1392 for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR) - 1; ++i)
1393 {
1394 /* Get the letter */
1395 MultiSz = (PWSTR)((ULONG_PTR)(*CurrentPath) + Offset);
1396 /* If it was part of the path, just return it */
1397 if (*MultiSz != UNICODE_NULL)
1398 {
1399 (*VolumePaths)->MultiSz[Written] = *MultiSz;
1400 }
1401 else
1402 {
1403 /* Otherwise, as planed, return our whole associated device name */
1404 RtlCopyMemory(&(*VolumePaths)->MultiSz[Written],
1405 AssociatedDeviceEntry->String.Buffer,
1406 AssociatedDeviceEntry->String.Length);
1407 Written += AssociatedDeviceEntry->String.Length / sizeof(WCHAR);
1408 /* And don't forget to nullify */
1409 (*VolumePaths)->MultiSz[Written] = UNICODE_NULL;
1410 }
1411
1412 /* We at least return a letter or a null char */
1413 ++Written;
1414 /* Move to the next letter */
1415 Offset += sizeof(WCHAR);
1416 }
1417 }
1418
1419 FreePool(*CurrentPath);
1420 ++CurrentPath;
1421 }
1422
1423 /* MultiSz: don't forget last null char */
1424 (*VolumePaths)->MultiSz[Written] = UNICODE_NULL;
1425 /* Cleanup everything and return success! */
1426 if (Paths != NULL)
1427 {
1428 FreePool(Paths);
1429 }
1430 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
1431 FreePool(DeviceInfoEntry);
1432 return STATUS_SUCCESS;
1433 }
1434
1435 /*
1436 * @implemented
1437 */
1438 NTSTATUS
MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1439 MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
1440 IN PIRP Irp)
1441 {
1442 NTSTATUS Status;
1443 PLIST_ENTRY Entry;
1444 LIST_ENTRY Devices;
1445 BOOLEAN NeedNotification;
1446 PIO_STACK_LOCATION Stack;
1447 UNICODE_STRING SymbolicName;
1448 ULONG Attempts, OutputLength;
1449 PMOUNTMGR_TARGET_NAME Target;
1450 PMOUNTMGR_VOLUME_PATHS Paths, Output;
1451 RECONCILE_WORK_ITEM_CONTEXT ReconcileContext;
1452 PDEVICE_INFORMATION DeviceInformation, ListDeviceInfo, FailedDevice;
1453
1454 Stack = IoGetCurrentIrpStackLocation(Irp);
1455
1456 /* Validate input size */
1457 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
1458 {
1459 return STATUS_INVALID_PARAMETER;
1460 }
1461
1462 /* Ensure we have received UNICODE_STRING */
1463 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
1464 if (Target->DeviceNameLength & 1)
1465 {
1466 return STATUS_INVALID_PARAMETER;
1467 }
1468
1469 /* Validate the entry structure size */
1470 if (Target->DeviceNameLength + FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) > Stack->Parameters.DeviceIoControl.InputBufferLength)
1471 {
1472 return STATUS_INVALID_PARAMETER;
1473 }
1474
1475 /* Ensure we can at least return needed size */
1476 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
1477 {
1478 return STATUS_INVALID_PARAMETER;
1479 }
1480
1481 /* Construct string for query */
1482 SymbolicName.Length = Target->DeviceNameLength;
1483 SymbolicName.MaximumLength = Target->DeviceNameLength + sizeof(UNICODE_NULL);
1484 SymbolicName.Buffer = Target->DeviceName;
1485
1486 /* Find device with our info */
1487 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
1488 if (!NT_SUCCESS(Status))
1489 {
1490 return Status;
1491 }
1492
1493 NeedNotification = FALSE;
1494 Attempts = 0;
1495 for (;;)
1496 {
1497 FailedDevice = NULL;
1498 InitializeListHead(&Devices);
1499
1500 /* Query paths */
1501 Status = MountMgrQueryVolumePaths(DeviceExtension, DeviceInformation, &Devices, &Paths, &FailedDevice);
1502 if (NT_SUCCESS(Status))
1503 {
1504 break;
1505 }
1506
1507 /* If it failed for generic reason (memory, whatever), bail out (ie, FailedDevice not set) */
1508 if (FailedDevice == NULL)
1509 {
1510 return Status;
1511 }
1512
1513 /* If PnP, let's notify in case of success */
1514 if (!DeviceInformation->ManuallyRegistered)
1515 {
1516 NeedNotification = TRUE;
1517 }
1518
1519 /* Reconcile database */
1520 ReconcileContext.DeviceExtension = DeviceExtension;
1521 ReconcileContext.DeviceInformation = FailedDevice;
1522 KeReleaseSemaphore(&DeviceExtension->DeviceLock, IO_NO_INCREMENT, 1, FALSE);
1523 ReconcileThisDatabaseWithMasterWorker(&ReconcileContext);
1524 KeWaitForSingleObject(&DeviceExtension->DeviceLock, Executive, KernelMode, FALSE, NULL);
1525
1526 /* Look for our device, to check it's online */
1527 for (Entry = DeviceExtension->DeviceListHead.Flink;
1528 Entry != &DeviceExtension->DeviceListHead;
1529 Entry = Entry->Flink)
1530 {
1531 ListDeviceInfo = CONTAINING_RECORD(Entry, DEVICE_INFORMATION, DeviceListEntry);
1532 /* It's online, it's OK! */
1533 if (ListDeviceInfo == DeviceInformation)
1534 {
1535 break;
1536 }
1537 }
1538
1539 /* It's not online, it's not good */
1540 if (Entry == &DeviceExtension->DeviceListHead)
1541 {
1542 return STATUS_OBJECT_NAME_NOT_FOUND;
1543 }
1544
1545 /* Increase attempts count */
1546 ++Attempts;
1547 /* Don't look forever and fail if we get out of attempts */
1548 if (Attempts >= 1000)
1549 {
1550 return Status;
1551 }
1552 }
1553
1554 /* We need to notify? Go ahead */
1555 if (NeedNotification)
1556 {
1557 MountMgrNotifyNameChange(DeviceExtension, &SymbolicName, FALSE);
1558 }
1559
1560 /* Get output buffer */
1561 Output = (PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer;
1562
1563 /* Set required size */
1564 Output->MultiSzLength = Paths->MultiSzLength;
1565
1566 /* Compute total length */
1567 OutputLength = Output->MultiSzLength + sizeof(ULONG);
1568
1569 /* If it cannot fit, just return need size and quit */
1570 if (OutputLength > Stack->Parameters.DeviceIoControl.OutputBufferLength)
1571 {
1572 Irp->IoStatus.Information = sizeof(ULONG);
1573 FreePool(Paths);
1574 return STATUS_BUFFER_OVERFLOW;
1575 }
1576
1577 /* Copy data and quit */
1578 Irp->IoStatus.Information = OutputLength;
1579 RtlCopyMemory(Output->MultiSz, Paths->MultiSz, Output->MultiSzLength);
1580 FreePool(Paths);
1581 return STATUS_SUCCESS;
1582 }
1583
1584 /*
1585 * @implemented
1586 */
1587 NTSTATUS
MountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1588 MountMgrKeepLinksWhenOffline(IN PDEVICE_EXTENSION DeviceExtension,
1589 IN PIRP Irp)
1590 {
1591 NTSTATUS Status;
1592 PIO_STACK_LOCATION Stack;
1593 UNICODE_STRING SymbolicName;
1594 PMOUNTMGR_TARGET_NAME Target;
1595 PDEVICE_INFORMATION DeviceInformation;
1596
1597 Stack = IoGetCurrentIrpStackLocation(Irp);
1598
1599 /* Validate input */
1600 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
1601 {
1602 return STATUS_INVALID_PARAMETER;
1603 }
1604
1605 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
1606 if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
1607 {
1608 return STATUS_INVALID_PARAMETER;
1609 }
1610
1611 SymbolicName.Length =
1612 SymbolicName.MaximumLength = Target->DeviceNameLength;
1613 SymbolicName.Buffer = Target->DeviceName;
1614
1615 /* Find the associated device */
1616 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
1617 if (!NT_SUCCESS(Status))
1618 {
1619 return Status;
1620 }
1621
1622 /* Mark we want to keep links */
1623 DeviceInformation->KeepLinks = TRUE;
1624
1625 return STATUS_SUCCESS;
1626 }
1627
1628 /*
1629 * @implemented
1630 */
1631 NTSTATUS
MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1632 MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension,
1633 IN PIRP Irp)
1634 {
1635 NTSTATUS Status;
1636 BOOLEAN OldState;
1637 PIO_STACK_LOCATION Stack;
1638 UNICODE_STRING SymbolicName;
1639 PMOUNTMGR_TARGET_NAME Target;
1640
1641 Stack = IoGetCurrentIrpStackLocation(Irp);
1642
1643 /* Validate input */
1644 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
1645 {
1646 return STATUS_INVALID_PARAMETER;
1647 }
1648
1649 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
1650 if (Target->DeviceNameLength + sizeof(USHORT) > Stack->Parameters.DeviceIoControl.InputBufferLength)
1651 {
1652 return STATUS_INVALID_PARAMETER;
1653 }
1654
1655 SymbolicName.Length =
1656 SymbolicName.MaximumLength = Target->DeviceNameLength;
1657 SymbolicName.Buffer = Target->DeviceName;
1658
1659 /* Disable hard errors */
1660 OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1661 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
1662
1663 /* Call real worker */
1664 Status = MountMgrMountedDeviceArrival(DeviceExtension, &SymbolicName, TRUE);
1665
1666 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
1667
1668 return Status;
1669 }
1670
1671 /*
1672 * @implemented
1673 */
1674 NTSTATUS
MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1675 MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension,
1676 IN PIRP Irp)
1677 {
1678 NTSTATUS Status;
1679 PIO_STACK_LOCATION Stack;
1680 PMOUNTDEV_UNIQUE_ID UniqueId;
1681 PMOUNTMGR_MOUNT_POINT MountPoint;
1682 UNICODE_STRING SymbolicName, DeviceName;
1683
1684 Stack = IoGetCurrentIrpStackLocation(Irp);
1685
1686 /* Validate input... */
1687 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
1688 {
1689 return STATUS_INVALID_PARAMETER;
1690 }
1691
1692 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1693 if (!MountPoint->SymbolicLinkNameLength)
1694 {
1695 MountPoint->SymbolicLinkNameOffset = 0;
1696 }
1697
1698 if (!MountPoint->UniqueIdLength)
1699 {
1700 MountPoint->UniqueIdOffset = 0;
1701 }
1702
1703 if (!MountPoint->DeviceNameLength)
1704 {
1705 MountPoint->DeviceNameOffset = 0;
1706 }
1707
1708 /* Addresses can't be odd */
1709 if ((MountPoint->SymbolicLinkNameOffset & 1) ||
1710 (MountPoint->SymbolicLinkNameLength & 1))
1711 {
1712 return STATUS_INVALID_PARAMETER;
1713 }
1714
1715 if ((MountPoint->UniqueIdOffset & 1) ||
1716 (MountPoint->UniqueIdLength & 1))
1717 {
1718 return STATUS_INVALID_PARAMETER;
1719 }
1720
1721 if ((MountPoint->DeviceNameOffset & 1) ||
1722 (MountPoint->DeviceNameLength & 1))
1723 {
1724 return STATUS_INVALID_PARAMETER;
1725 }
1726
1727 /* We can't go beyond */
1728 if (((ULONG)MountPoint->SymbolicLinkNameLength + MountPoint->UniqueIdLength +
1729 MountPoint->DeviceNameLength) > Stack->Parameters.DeviceIoControl.InputBufferLength)
1730 {
1731 return STATUS_INVALID_PARAMETER;
1732 }
1733
1734 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_MOUNT_POINTS))
1735 {
1736 return STATUS_INVALID_PARAMETER;
1737 }
1738
1739 /* If caller provided a Symlink, use it */
1740 if (MountPoint->SymbolicLinkNameLength != 0)
1741 {
1742 if (MountPoint->SymbolicLinkNameLength > MAXSHORT)
1743 {
1744 return STATUS_INVALID_PARAMETER;
1745 }
1746
1747 SymbolicName.Length = MountPoint->SymbolicLinkNameLength;
1748 SymbolicName.MaximumLength = MountPoint->SymbolicLinkNameLength + sizeof(WCHAR);
1749 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1750 if (!SymbolicName.Buffer)
1751 {
1752 return STATUS_INSUFFICIENT_RESOURCES;
1753 }
1754
1755 RtlCopyMemory(SymbolicName.Buffer,
1756 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->SymbolicLinkNameOffset),
1757 SymbolicName.Length);
1758 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1759
1760 /* Query links using it */
1761 Status = QueryPointsFromSymbolicLinkName(DeviceExtension, &SymbolicName, Irp);
1762 FreePool(SymbolicName.Buffer);
1763 }
1764 /* If user provided an unique ID */
1765 else if (MountPoint->UniqueIdLength != 0)
1766 {
1767 UniqueId = AllocatePool(MountPoint->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1768 if (!UniqueId)
1769 {
1770 return STATUS_INSUFFICIENT_RESOURCES;
1771 }
1772
1773 UniqueId->UniqueIdLength = MountPoint->UniqueIdLength;
1774 RtlCopyMemory(UniqueId->UniqueId,
1775 (PVOID)((ULONG_PTR)MountPoint + MountPoint->UniqueIdOffset),
1776 MountPoint->UniqueIdLength);
1777
1778 /* Query links using it */
1779 Status = QueryPointsFromMemory(DeviceExtension, Irp, UniqueId, NULL);
1780 FreePool(UniqueId);
1781 }
1782 /* If caller provided a device name */
1783 else if (MountPoint->DeviceNameLength != 0)
1784 {
1785 if (MountPoint->DeviceNameLength > MAXSHORT)
1786 {
1787 return STATUS_INVALID_PARAMETER;
1788 }
1789
1790 DeviceName.Length = MountPoint->DeviceNameLength;
1791 DeviceName.MaximumLength = MountPoint->DeviceNameLength + sizeof(WCHAR);
1792 DeviceName.Buffer = AllocatePool(DeviceName.MaximumLength);
1793 if (!DeviceName.Buffer)
1794 {
1795 return STATUS_INSUFFICIENT_RESOURCES;
1796 }
1797
1798 RtlCopyMemory(DeviceName.Buffer,
1799 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->DeviceNameOffset),
1800 DeviceName.Length);
1801 DeviceName.Buffer[DeviceName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1802
1803 /* Query links using it */
1804 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, &DeviceName);
1805 FreePool(DeviceName.Buffer);
1806 }
1807 else
1808 {
1809 /* Otherwise, query all links */
1810 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, NULL);
1811 }
1812
1813 return Status;
1814 }
1815
1816 /*
1817 * @implemented
1818 */
1819 NTSTATUS
MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1820 MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension,
1821 IN PIRP Irp)
1822 {
1823 ULONG Link;
1824 NTSTATUS Status;
1825 BOOLEAN CreateNoDrive;
1826 PIO_STACK_LOCATION Stack;
1827 PMOUNTDEV_UNIQUE_ID UniqueId;
1828 PMOUNTMGR_MOUNT_POINT MountPoint;
1829 PMOUNTMGR_MOUNT_POINTS MountPoints;
1830 UNICODE_STRING SymbolicName, DeviceName;
1831
1832 Stack = IoGetCurrentIrpStackLocation(Irp);
1833
1834 /* Validate input */
1835 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
1836 {
1837 return STATUS_INVALID_PARAMETER;
1838 }
1839
1840 /* Query points */
1841 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1842 CreateNoDrive = (MountPoint->SymbolicLinkNameOffset && MountPoint->SymbolicLinkNameLength);
1843
1844 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1845 if (!NT_SUCCESS(Status))
1846 {
1847 return Status;
1848 }
1849
1850 /* For all the points matching the request */
1851 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
1852 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++)
1853 {
1854 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength;
1855 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR);
1856 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1857 if (!SymbolicName.Buffer)
1858 {
1859 return STATUS_INSUFFICIENT_RESOURCES;
1860 }
1861
1862 RtlCopyMemory(SymbolicName.Buffer,
1863 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset),
1864 SymbolicName.Length);
1865 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1866
1867 /* Create a no drive entry for the drive letters */
1868 if (CreateNoDrive && IsDriveLetter(&SymbolicName))
1869 {
1870 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1871 if (UniqueId)
1872 {
1873 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength;
1874 RtlCopyMemory(UniqueId->UniqueId,
1875 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1876 MountPoints->MountPoints[Link].UniqueIdLength);
1877
1878 CreateNoDriveLetterEntry(UniqueId);
1879 FreePool(UniqueId);
1880 }
1881 }
1882
1883 /* If there are no link any more, and no need to create a no drive entry */
1884 if (Link == 0 && !CreateNoDrive)
1885 {
1886 /* Then, delete everything */
1887 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength);
1888 if (UniqueId)
1889 {
1890 RtlCopyMemory(UniqueId,
1891 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1892 MountPoints->MountPoints[Link].UniqueIdLength);
1893
1894 DeleteNoDriveLetterEntry(UniqueId);
1895 FreePool(UniqueId);
1896 }
1897 }
1898
1899 /* Delete all the information about the mount point */
1900 GlobalDeleteSymbolicLink(&SymbolicName);
1901 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, FALSE);
1902 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer);
1903 FreePool(SymbolicName.Buffer);
1904
1905 /* Notify the change */
1906 DeviceName.Length = DeviceName.MaximumLength =
1907 MountPoints->MountPoints[Link].DeviceNameLength;
1908 DeviceName.Buffer = (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].DeviceNameOffset);
1909 MountMgrNotifyNameChange(DeviceExtension, &DeviceName, TRUE);
1910 }
1911
1912 MountMgrNotify(DeviceExtension);
1913
1914 return Status;
1915 }
1916
1917 /*
1918 * @implemented
1919 */
1920 NTSTATUS
MountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1921 MountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension,
1922 IN PIRP Irp)
1923 {
1924 ULONG Link;
1925 NTSTATUS Status;
1926 UNICODE_STRING SymbolicName;
1927 PMOUNTDEV_UNIQUE_ID UniqueId;
1928 PMOUNTMGR_MOUNT_POINTS MountPoints;
1929
1930 /* Query points */
1931 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1932 if (!NT_SUCCESS(Status))
1933 {
1934 return Status;
1935 }
1936
1937 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
1938 if (MountPoints->NumberOfMountPoints == 0)
1939 {
1940 return Status;
1941 }
1942
1943 /* For all the mount points */
1944 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++)
1945 {
1946 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength;
1947 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR);
1948 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1949 if (!SymbolicName.Buffer)
1950 {
1951 return STATUS_INSUFFICIENT_RESOURCES;
1952 }
1953
1954 RtlCopyMemory(SymbolicName.Buffer,
1955 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset),
1956 SymbolicName.Length);
1957 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1958
1959 /* If the only mount point is a drive letter, then create a no letter drive entry */
1960 if (MountPoints->NumberOfMountPoints == 1 && IsDriveLetter(&SymbolicName))
1961 {
1962 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1963 if (UniqueId)
1964 {
1965 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength;
1966 RtlCopyMemory(UniqueId->UniqueId,
1967 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1968 MountPoints->MountPoints[Link].UniqueIdLength);
1969
1970 CreateNoDriveLetterEntry(UniqueId);
1971 FreePool(UniqueId);
1972 }
1973 }
1974
1975 /* Simply delete mount point from DB */
1976 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, TRUE);
1977 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer);
1978 FreePool(SymbolicName.Buffer);
1979 }
1980
1981 return Status;
1982 }
1983
1984 /*
1985 * @implemented
1986 */
1987 NTSTATUS
MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp,IN NTSTATUS LockStatus,OUT PUNICODE_STRING SourceDeviceName,OUT PUNICODE_STRING SourceSymbolicName,OUT PUNICODE_STRING TargetVolumeName)1988 MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension,
1989 IN PIRP Irp,
1990 IN NTSTATUS LockStatus,
1991 OUT PUNICODE_STRING SourceDeviceName,
1992 OUT PUNICODE_STRING SourceSymbolicName,
1993 OUT PUNICODE_STRING TargetVolumeName)
1994 {
1995 HANDLE Handle;
1996 NTSTATUS Status;
1997 PFILE_OBJECT FileObject;
1998 PIO_STACK_LOCATION Stack;
1999 ULONG Length, SavedLength;
2000 BOOLEAN FOReferenced = FALSE;
2001 IO_STATUS_BLOCK IoStatusBlock;
2002 OBJECT_ATTRIBUTES ObjectAttributes;
2003 PDEVICE_INFORMATION DeviceInformation;
2004 OBJECT_NAME_INFORMATION ObjectNameInfo;
2005 FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
2006 PFILE_NAME_INFORMATION FileNameInfo = NULL;
2007 PMOUNTMGR_VOLUME_MOUNT_POINT VolumeMountPoint;
2008 POBJECT_NAME_INFORMATION ObjectNameInfoPtr = NULL;
2009 UNICODE_STRING SourceVolumeName, TargetDeviceName;
2010
2011 Stack = IoGetCurrentIrpStackLocation(Irp);
2012
2013 /* Validate input */
2014 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_VOLUME_MOUNT_POINT))
2015 {
2016 return STATUS_INVALID_PARAMETER;
2017 }
2018
2019 VolumeMountPoint = (PMOUNTMGR_VOLUME_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
2020
2021 if (((ULONG)VolumeMountPoint->SourceVolumeNameLength + VolumeMountPoint->TargetVolumeNameLength) <
2022 Stack->Parameters.DeviceIoControl.InputBufferLength)
2023 {
2024 return STATUS_INVALID_PARAMETER;
2025 }
2026
2027 /* Get source volume name */
2028 SourceVolumeName.Length =
2029 SourceVolumeName.MaximumLength = VolumeMountPoint->SourceVolumeNameLength;
2030 SourceVolumeName.Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->SourceVolumeNameOffset);
2031
2032 InitializeObjectAttributes(&ObjectAttributes,
2033 &SourceVolumeName,
2034 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
2035 NULL,
2036 NULL);
2037
2038 /* Open it */
2039 Status = ZwOpenFile(&Handle,
2040 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
2041 &ObjectAttributes,
2042 &IoStatusBlock,
2043 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2044 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
2045 if (!NT_SUCCESS(Status))
2046 {
2047 return Status;
2048 }
2049
2050 TargetDeviceName.Buffer = NULL;
2051
2052 /* Query its attributes */
2053 Status = ZwQueryVolumeInformationFile(Handle,
2054 &IoStatusBlock,
2055 &FsDeviceInfo,
2056 sizeof(FsDeviceInfo),
2057 FileFsDeviceInformation);
2058 if (!NT_SUCCESS(Status))
2059 {
2060 goto Cleanup;
2061 }
2062
2063 if (FsDeviceInfo.DeviceType != FILE_DEVICE_DISK && FsDeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK)
2064 {
2065 goto Cleanup;
2066 }
2067
2068 if (FsDeviceInfo.Characteristics != (FILE_REMOTE_DEVICE | FILE_REMOVABLE_MEDIA))
2069 {
2070 goto Cleanup;
2071 }
2072
2073 /* Reference it */
2074 Status = ObReferenceObjectByHandle(Handle, 0, *IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL);
2075 if (!NT_SUCCESS(Status))
2076 {
2077 goto Cleanup;
2078 }
2079 FOReferenced = TRUE;
2080
2081 /* Get file name */
2082 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION));
2083 if (!FileNameInfo)
2084 {
2085 Status = STATUS_INSUFFICIENT_RESOURCES;
2086 goto Cleanup;
2087 }
2088
2089 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo,
2090 sizeof(FILE_NAME_INFORMATION),
2091 FileNameInformation);
2092 if (Status == STATUS_BUFFER_OVERFLOW)
2093 {
2094 /* Now we have real length, use it */
2095 Length = FileNameInfo->FileNameLength;
2096 FreePool(FileNameInfo);
2097
2098 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + Length);
2099 if (!FileNameInfo)
2100 {
2101 Status = STATUS_INSUFFICIENT_RESOURCES;
2102 goto Cleanup;
2103 }
2104
2105 /* Really query file name */
2106 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo,
2107 sizeof(FILE_NAME_INFORMATION) + Length,
2108 FileNameInformation);
2109 }
2110
2111 if (!NT_SUCCESS(Status))
2112 {
2113 goto Cleanup;
2114 }
2115
2116 /* Get symbolic name */
2117 ObjectNameInfoPtr = &ObjectNameInfo;
2118 SavedLength = sizeof(OBJECT_NAME_INFORMATION);
2119 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, sizeof(OBJECT_NAME_INFORMATION), &Length);
2120 if (Status == STATUS_INFO_LENGTH_MISMATCH)
2121 {
2122 /* Once again, with proper size, it works better */
2123 ObjectNameInfoPtr = AllocatePool(Length);
2124 if (!ObjectNameInfoPtr)
2125 {
2126 Status = STATUS_INSUFFICIENT_RESOURCES;
2127 goto Cleanup;
2128 }
2129
2130 SavedLength = Length;
2131 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, SavedLength, &Length);
2132 }
2133
2134 if (!NT_SUCCESS(Status))
2135 {
2136 goto Cleanup;
2137 }
2138
2139 /* Now, query the device name */
2140 Status = QueryDeviceInformation(&ObjectNameInfoPtr->Name, SourceDeviceName,
2141 NULL, NULL, NULL, NULL, NULL, NULL);
2142 if (!NT_SUCCESS(Status))
2143 {
2144 goto Cleanup;
2145 }
2146
2147 /* For target volume name, use input */
2148 TargetVolumeName->Length =
2149 TargetVolumeName->MaximumLength = VolumeMountPoint->TargetVolumeNameLength;
2150 TargetVolumeName->Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->TargetVolumeNameOffset);
2151
2152 /* Query its device name */
2153 Status = QueryDeviceInformation(TargetVolumeName, &TargetDeviceName,
2154 NULL, NULL, NULL, NULL, NULL, NULL);
2155 if (!NT_SUCCESS(Status))
2156 {
2157 goto Cleanup;
2158 }
2159
2160 /* Return symbolic name */
2161 SourceSymbolicName->Length =
2162 SourceSymbolicName->MaximumLength = (USHORT)FileNameInfo->FileNameLength;
2163 SourceSymbolicName->Buffer = (PWSTR)FileNameInfo;
2164 /* memmove allows memory overlap */
2165 RtlMoveMemory(SourceSymbolicName->Buffer, FileNameInfo->FileName, SourceSymbolicName->Length);
2166 FileNameInfo = NULL;
2167
2168 /* Notify the change */
2169 MountMgrNotify(DeviceExtension);
2170 MountMgrNotifyNameChange(DeviceExtension, &TargetDeviceName, TRUE);
2171
2172 /* If we are locked, sync databases if possible */
2173 if (NT_SUCCESS(LockStatus))
2174 {
2175 Status = FindDeviceInfo(DeviceExtension, SourceDeviceName, FALSE, &DeviceInformation);
2176 if (NT_SUCCESS(Status))
2177 {
2178 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
2179 }
2180 else
2181 {
2182 Status = STATUS_PENDING;
2183 }
2184 }
2185
2186 Cleanup:
2187 if (TargetDeviceName.Buffer)
2188 {
2189 FreePool(TargetDeviceName.Buffer);
2190 }
2191
2192 if (ObjectNameInfoPtr && ObjectNameInfoPtr != &ObjectNameInfo)
2193 {
2194 FreePool(ObjectNameInfoPtr);
2195 }
2196
2197 if (FileNameInfo)
2198 {
2199 FreePool(FileNameInfo);
2200 }
2201
2202 if (FOReferenced)
2203 {
2204 ObDereferenceObject(FileObject);
2205 }
2206
2207 return Status;
2208 }
2209
2210 /*
2211 * @implemented
2212 */
2213 NTSTATUS
MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp,IN NTSTATUS LockStatus)2214 MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension,
2215 IN PIRP Irp,
2216 IN NTSTATUS LockStatus)
2217 {
2218 LONG Offset;
2219 BOOLEAN Found;
2220 NTSTATUS Status;
2221 HANDLE RemoteDatabase;
2222 PMOUNTDEV_UNIQUE_ID UniqueId;
2223 PDATABASE_ENTRY DatabaseEntry;
2224 PASSOCIATED_DEVICE_ENTRY AssociatedEntry;
2225 PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation;
2226 UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName;
2227
2228 /* Initialize string */
2229 LinkTarget.Length = 0;
2230 LinkTarget.MaximumLength = 0xC8;
2231 LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength);
2232 if (LinkTarget.Buffer == NULL)
2233 {
2234 return STATUS_INSUFFICIENT_RESOURCES;
2235 }
2236
2237 /* If the mount point was created, then, it changed!
2238 * Also use it to query some information
2239 */
2240 Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName);
2241 /* Pending means DB are under synchronization, bail out */
2242 if (Status == STATUS_PENDING)
2243 {
2244 FreePool(LinkTarget.Buffer);
2245 FreePool(SourceDeviceName.Buffer);
2246 FreePool(SourceSymbolicName.Buffer);
2247 return STATUS_SUCCESS;
2248 }
2249 else if (!NT_SUCCESS(Status))
2250 {
2251 FreePool(LinkTarget.Buffer);
2252 return Status;
2253 }
2254
2255 /* Query the device information */
2256 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation);
2257 if (!NT_SUCCESS(Status))
2258 {
2259 /* If it failed, first try to get volume name */
2260 Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName);
2261 if (!NT_SUCCESS(Status))
2262 {
2263 /* Then, try to read the symlink */
2264 Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget);
2265 if (!NT_SUCCESS(Status))
2266 {
2267 FreePool(LinkTarget.Buffer);
2268 FreePool(SourceDeviceName.Buffer);
2269 FreePool(SourceSymbolicName.Buffer);
2270 return Status;
2271 }
2272 }
2273 else
2274 {
2275 FreePool(VolumeName.Buffer);
2276 }
2277
2278 FreePool(SourceDeviceName.Buffer);
2279
2280 SourceDeviceName.Length = LinkTarget.Length;
2281 SourceDeviceName.MaximumLength = LinkTarget.MaximumLength;
2282 SourceDeviceName.Buffer = LinkTarget.Buffer;
2283
2284 /* Now that we have the correct source, reattempt to query information */
2285 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation);
2286 if (!NT_SUCCESS(Status))
2287 {
2288 FreePool(SourceDeviceName.Buffer);
2289 FreePool(SourceSymbolicName.Buffer);
2290 return Status;
2291 }
2292 }
2293
2294 FreePool(SourceDeviceName.Buffer);
2295
2296 /* Get information about target device */
2297 Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation);
2298 if (!NT_SUCCESS(Status))
2299 {
2300 FreePool(SourceSymbolicName.Buffer);
2301 return Status;
2302 }
2303
2304 /* Notify if not disabled */
2305 if (!TargetDeviceInformation->SkipNotifications)
2306 {
2307 PostOnlineNotification(DeviceExtension, &TargetDeviceInformation->SymbolicName);
2308 }
2309
2310 /* Open the remote database */
2311 RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE);
2312 if (RemoteDatabase == 0)
2313 {
2314 FreePool(SourceSymbolicName.Buffer);
2315 return STATUS_INSUFFICIENT_RESOURCES;
2316 }
2317
2318 /* Browse all the entries */
2319 Offset = 0;
2320 Found = FALSE;
2321 for (;;)
2322 {
2323 DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset);
2324 if (DatabaseEntry == NULL)
2325 {
2326 break;
2327 }
2328
2329 /* Try to find ourselves */
2330 DbName.MaximumLength = DatabaseEntry->SymbolicNameLength;
2331 DbName.Length = DbName.MaximumLength;
2332 DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
2333 if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE))
2334 {
2335 /* Reference ourselves and update the entry */
2336 ++DatabaseEntry->EntryReferences;
2337 Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry);
2338 FreePool(DatabaseEntry);
2339 Found = TRUE;
2340 break;
2341 }
2342
2343 Offset += DatabaseEntry->EntrySize;
2344 FreePool(DatabaseEntry);
2345 }
2346
2347 /* We couldn't find ourselves, we'll have to add ourselves */
2348 if (!Found)
2349 {
2350 ULONG EntrySize;
2351 PUNIQUE_ID_REPLICATE UniqueIdReplicate;
2352
2353 /* Query the device unique ID */
2354 Status = QueryDeviceInformation(&TargetVolumeName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL);
2355 if (!NT_SUCCESS(Status))
2356 {
2357 FreePool(SourceSymbolicName.Buffer);
2358 CloseRemoteDatabase(RemoteDatabase);
2359 return Status;
2360 }
2361
2362 /* Allocate a database entry */
2363 EntrySize = UniqueId->UniqueIdLength + TargetVolumeName.Length + sizeof(DATABASE_ENTRY);
2364 DatabaseEntry = AllocatePool(EntrySize);
2365 if (DatabaseEntry == NULL)
2366 {
2367 FreePool(UniqueId);
2368 FreePool(SourceSymbolicName.Buffer);
2369 CloseRemoteDatabase(RemoteDatabase);
2370 return STATUS_INSUFFICIENT_RESOURCES;
2371 }
2372
2373 /* Fill it in */
2374 DatabaseEntry->EntrySize = EntrySize;
2375 DatabaseEntry->EntryReferences = 1;
2376 DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
2377 DatabaseEntry->SymbolicNameLength = TargetVolumeName.Length;
2378 DatabaseEntry->UniqueIdOffset = TargetVolumeName.Length + sizeof(DATABASE_ENTRY);
2379 DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
2380 RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + sizeof(DATABASE_ENTRY)), TargetVolumeName.Buffer, DatabaseEntry->SymbolicNameLength);
2381 RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
2382
2383 /* And write it down */
2384 Status = AddRemoteDatabaseEntry(RemoteDatabase, DatabaseEntry);
2385 FreePool(DatabaseEntry);
2386 if (!NT_SUCCESS(Status))
2387 {
2388 FreePool(UniqueId);
2389 FreePool(SourceSymbolicName.Buffer);
2390 CloseRemoteDatabase(RemoteDatabase);
2391 return Status;
2392 }
2393
2394 /* And now, allocate an Unique ID item */
2395 UniqueIdReplicate = AllocatePool(sizeof(UNIQUE_ID_REPLICATE));
2396 if (UniqueIdReplicate == NULL)
2397 {
2398 FreePool(UniqueId);
2399 FreePool(SourceSymbolicName.Buffer);
2400 CloseRemoteDatabase(RemoteDatabase);
2401 return Status;
2402 }
2403
2404 /* To associate it with the device */
2405 UniqueIdReplicate->UniqueId = UniqueId;
2406 InsertTailList(&DeviceInformation->ReplicatedUniqueIdsListHead, &UniqueIdReplicate->ReplicatedUniqueIdsListEntry);
2407 }
2408
2409 /* We're done with the remote database */
2410 CloseRemoteDatabase(RemoteDatabase);
2411
2412 /* Check we were find writing the entry */
2413 if (!NT_SUCCESS(Status))
2414 {
2415 FreePool(SourceSymbolicName.Buffer);
2416 return Status;
2417 }
2418
2419 /* This is the end, allocate an associated entry */
2420 AssociatedEntry = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY));
2421 if (AssociatedEntry == NULL)
2422 {
2423 FreePool(SourceSymbolicName.Buffer);
2424 return STATUS_INSUFFICIENT_RESOURCES;
2425 }
2426
2427 /* Initialize its source name string */
2428 AssociatedEntry->String.Length = SourceSymbolicName.Length;
2429 AssociatedEntry->String.MaximumLength = AssociatedEntry->String.Length + sizeof(UNICODE_NULL);
2430 AssociatedEntry->String.Buffer = AllocatePool(AssociatedEntry->String.MaximumLength);
2431 if (AssociatedEntry->String.Buffer == NULL)
2432 {
2433 FreePool(AssociatedEntry);
2434 FreePool(SourceSymbolicName.Buffer);
2435 return STATUS_INSUFFICIENT_RESOURCES;
2436 }
2437
2438 /* Copy data & insert in list */
2439 RtlCopyMemory(AssociatedEntry->String.Buffer, SourceSymbolicName.Buffer, SourceSymbolicName.Length);
2440 AssociatedEntry->String.Buffer[SourceSymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
2441 AssociatedEntry->DeviceInformation = DeviceInformation;
2442 InsertTailList(&TargetDeviceInformation->AssociatedDevicesHead, &AssociatedEntry->AssociatedDevicesEntry);
2443
2444 /* We're done! */
2445 FreePool(SourceSymbolicName.Buffer);
2446 return STATUS_SUCCESS;
2447 }
2448
2449 /*
2450 * @implemented
2451 */
2452 NTSTATUS
MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp,IN NTSTATUS LockStatus)2453 MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension,
2454 IN PIRP Irp,
2455 IN NTSTATUS LockStatus)
2456 {
2457 LONG Offset;
2458 NTSTATUS Status;
2459 PLIST_ENTRY Entry;
2460 HANDLE RemoteDatabase;
2461 PDATABASE_ENTRY DatabaseEntry;
2462 PUNIQUE_ID_REPLICATE UniqueIdReplicate;
2463 PASSOCIATED_DEVICE_ENTRY AssociatedEntry;
2464 PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation;
2465 UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName;
2466
2467 /* Initialize string */
2468 LinkTarget.Length = 0;
2469 LinkTarget.MaximumLength = 0xC8;
2470 LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength);
2471 if (LinkTarget.Buffer == NULL)
2472 {
2473 return STATUS_INSUFFICIENT_RESOURCES;
2474 }
2475
2476 /* If the mount point was deleted, then, it changed!
2477 * Also use it to query some information
2478 */
2479 Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName);
2480 /* Pending means DB are under synchronization, bail out */
2481 if (Status == STATUS_PENDING)
2482 {
2483 FreePool(LinkTarget.Buffer);
2484 FreePool(SourceDeviceName.Buffer);
2485 FreePool(SourceSymbolicName.Buffer);
2486 return STATUS_SUCCESS;
2487 }
2488 else if (!NT_SUCCESS(Status))
2489 {
2490 FreePool(LinkTarget.Buffer);
2491 return Status;
2492 }
2493
2494 /* Query the device information */
2495 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation);
2496 if (!NT_SUCCESS(Status))
2497 {
2498 /* If it failed, first try to get volume name */
2499 Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName);
2500 if (!NT_SUCCESS(Status))
2501 {
2502 /* Then, try to read the symlink */
2503 Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget);
2504 if (!NT_SUCCESS(Status))
2505 {
2506 FreePool(LinkTarget.Buffer);
2507 FreePool(SourceDeviceName.Buffer);
2508 FreePool(SourceSymbolicName.Buffer);
2509 return Status;
2510 }
2511 }
2512 else
2513 {
2514 FreePool(VolumeName.Buffer);
2515 }
2516
2517 FreePool(SourceDeviceName.Buffer);
2518
2519 SourceDeviceName.Length = LinkTarget.Length;
2520 SourceDeviceName.MaximumLength = LinkTarget.MaximumLength;
2521 SourceDeviceName.Buffer = LinkTarget.Buffer;
2522
2523 /* Now that we have the correct source, reattempt to query information */
2524 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation);
2525 if (!NT_SUCCESS(Status))
2526 {
2527 FreePool(SourceDeviceName.Buffer);
2528 FreePool(SourceSymbolicName.Buffer);
2529 return Status;
2530 }
2531 }
2532
2533 FreePool(SourceDeviceName.Buffer);
2534
2535 /* Get information about target device */
2536 Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation);
2537 if (!NT_SUCCESS(Status))
2538 {
2539 FreePool(SourceSymbolicName.Buffer);
2540 return Status;
2541 }
2542
2543 /* Open the remote database */
2544 RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE);
2545 if (RemoteDatabase == 0)
2546 {
2547 FreePool(SourceSymbolicName.Buffer);
2548 return STATUS_INSUFFICIENT_RESOURCES;
2549 }
2550
2551 /* Browse all the entries */
2552 Offset = 0;
2553 for (;;)
2554 {
2555 DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset);
2556 if (DatabaseEntry == NULL)
2557 {
2558 /* We didn't find ourselves, that's infortunate! */
2559 FreePool(SourceSymbolicName.Buffer);
2560 CloseRemoteDatabase(RemoteDatabase);
2561 return STATUS_INVALID_PARAMETER;
2562 }
2563
2564 /* Try to find ourselves */
2565 DbName.MaximumLength = DatabaseEntry->SymbolicNameLength;
2566 DbName.Length = DbName.MaximumLength;
2567 DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
2568 if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE))
2569 {
2570 break;
2571 }
2572
2573 Offset += DatabaseEntry->EntrySize;
2574 FreePool(DatabaseEntry);
2575 }
2576
2577 /* Dereference ourselves */
2578 DatabaseEntry->EntryReferences--;
2579 if (DatabaseEntry->EntryReferences == 0)
2580 {
2581 /* If we're still referenced, just update the entry */
2582 Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry);
2583 }
2584 else
2585 {
2586 /* Otherwise, delete the entry */
2587 Status = DeleteRemoteDatabaseEntry(RemoteDatabase, Offset);
2588 if (!NT_SUCCESS(Status))
2589 {
2590 FreePool(DatabaseEntry);
2591 FreePool(SourceSymbolicName.Buffer);
2592 CloseRemoteDatabase(RemoteDatabase);
2593 return Status;
2594 }
2595
2596 /* Also, delete our unique ID replicated record */
2597 for (Entry = DeviceInformation->ReplicatedUniqueIdsListHead.Flink;
2598 Entry != &DeviceInformation->ReplicatedUniqueIdsListHead;
2599 Entry = Entry->Flink)
2600 {
2601 UniqueIdReplicate = CONTAINING_RECORD(Entry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
2602
2603 if (UniqueIdReplicate->UniqueId->UniqueIdLength == DatabaseEntry->UniqueIdLength &&
2604 RtlCompareMemory(UniqueIdReplicate->UniqueId->UniqueId,
2605 (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
2606 DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
2607 {
2608 break;
2609 }
2610 }
2611
2612 /* It has to exist! */
2613 if (Entry == &DeviceInformation->ReplicatedUniqueIdsListHead)
2614 {
2615 FreePool(DatabaseEntry);
2616 FreePool(SourceSymbolicName.Buffer);
2617 CloseRemoteDatabase(RemoteDatabase);
2618 return STATUS_UNSUCCESSFUL;
2619 }
2620
2621 /* Remove it and free it */
2622 RemoveEntryList(&UniqueIdReplicate->ReplicatedUniqueIdsListEntry);
2623 FreePool(UniqueIdReplicate->UniqueId);
2624 FreePool(UniqueIdReplicate);
2625 }
2626
2627 /* We're done with the remote database */
2628 FreePool(DatabaseEntry);
2629 CloseRemoteDatabase(RemoteDatabase);
2630
2631 /* Check write operation succeed */
2632 if (!NT_SUCCESS(Status))
2633 {
2634 FreePool(SourceSymbolicName.Buffer);
2635 return Status;
2636 }
2637
2638 /* Try to find our associated device entry */
2639 for (Entry = TargetDeviceInformation->AssociatedDevicesHead.Flink;
2640 Entry != &TargetDeviceInformation->AssociatedDevicesHead;
2641 Entry = Entry->Flink)
2642 {
2643 AssociatedEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
2644
2645 /* If found, delete it */
2646 if (AssociatedEntry->DeviceInformation == DeviceInformation &&
2647 RtlEqualUnicodeString(&AssociatedEntry->String, &SourceSymbolicName, TRUE))
2648 {
2649 RemoveEntryList(&AssociatedEntry->AssociatedDevicesEntry);
2650 FreePool(AssociatedEntry->String.Buffer);
2651 FreePool(AssociatedEntry);
2652 break;
2653 }
2654 }
2655
2656 /* We're done! */
2657 FreePool(SourceSymbolicName.Buffer);
2658 return STATUS_SUCCESS;
2659 }
2660
2661 /*
2662 * @implemented
2663 */
2664 NTSTATUS
2665 NTAPI
MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)2666 MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject,
2667 IN PIRP Irp)
2668 {
2669 PIO_STACK_LOCATION Stack;
2670 NTSTATUS Status, LockStatus;
2671 PDEVICE_EXTENSION DeviceExtension;
2672
2673 Stack = IoGetCurrentIrpStackLocation(Irp);
2674 DeviceExtension = DeviceObject->DeviceExtension;
2675
2676 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
2677
2678 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2679 {
2680 case IOCTL_MOUNTMGR_CREATE_POINT:
2681 Status = MountMgrCreatePoint(DeviceExtension, Irp);
2682 break;
2683
2684 case IOCTL_MOUNTMGR_DELETE_POINTS:
2685 Status = MountMgrDeletePoints(DeviceExtension, Irp);
2686 break;
2687
2688 case IOCTL_MOUNTMGR_QUERY_POINTS:
2689 Status = MountMgrQueryPoints(DeviceExtension, Irp);
2690 break;
2691
2692 case IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY:
2693 Status = MountMgrDeletePointsDbOnly(DeviceExtension, Irp);
2694 break;
2695
2696 case IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER:
2697 Status = MountMgrNextDriveLetter(DeviceExtension, Irp);
2698 break;
2699
2700 case IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS:
2701 // NOTE: On Win7+, this is handled during driver re-initialization.
2702 DeviceExtension->AutomaticDriveLetter = TRUE;
2703 MountMgrAssignDriveLetters(DeviceExtension);
2704 ReconcileAllDatabasesWithMaster(DeviceExtension);
2705 WaitForOnlinesToComplete(DeviceExtension);
2706 Status = STATUS_SUCCESS;
2707 break;
2708
2709 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED:
2710 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
2711
2712 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension);
2713 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
2714 Status = MountMgrVolumeMountPointCreated(DeviceExtension, Irp, LockStatus);
2715 if (NT_SUCCESS(LockStatus))
2716 {
2717 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
2718 }
2719
2720 break;
2721
2722 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED:
2723 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
2724
2725 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension);
2726 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
2727 Status = MountMgrVolumeMountPointDeleted(DeviceExtension, Irp, LockStatus);
2728 if (NT_SUCCESS(LockStatus))
2729 {
2730 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
2731 }
2732
2733 break;
2734
2735 case IOCTL_MOUNTMGR_CHANGE_NOTIFY:
2736 Status = MountMgrChangeNotify(DeviceExtension, Irp);
2737 break;
2738
2739 case IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE:
2740 Status = MountMgrKeepLinksWhenOffline(DeviceExtension, Irp);
2741 break;
2742
2743 case IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES:
2744 Status = MountMgrCheckUnprocessedVolumes(DeviceExtension, Irp);
2745 goto Complete;
2746
2747 case IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION:
2748 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
2749 Status = MountMgrVolumeArrivalNotification(DeviceExtension, Irp);
2750 goto Complete;
2751
2752 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH:
2753 Status = MountMgrQueryDosVolumePath(DeviceExtension, Irp);
2754 break;
2755
2756 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS:
2757 Status = MountMgrQueryDosVolumePaths(DeviceExtension, Irp);
2758 break;
2759
2760 case IOCTL_MOUNTMGR_SCRUB_REGISTRY:
2761 Status = MountMgrScrubRegistry(DeviceExtension);
2762 break;
2763
2764 case IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT:
2765 Status = MountMgrQueryAutoMount(DeviceExtension, Irp);
2766 break;
2767
2768 case IOCTL_MOUNTMGR_SET_AUTO_MOUNT:
2769 Status = MountMgrSetAutoMount(DeviceExtension, Irp);
2770 break;
2771
2772 default:
2773 Status = STATUS_INVALID_DEVICE_REQUEST;
2774 }
2775
2776 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
2777
2778 if (Status != STATUS_PENDING)
2779 {
2780 goto Complete;
2781 }
2782
2783 return Status;
2784
2785 Complete:
2786 Irp->IoStatus.Status = Status;
2787 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2788
2789 return Status;
2790 }
2791