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 (FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName) + DriveLetterTarget->DeviceNameLength >
641 Stack->Parameters.DeviceIoControl.InputBufferLength)
642 {
643 return STATUS_INVALID_PARAMETER;
644 }
645
646 /* Call the worker */
647 DeviceName.Buffer = DriveLetterTarget->DeviceName;
648 DeviceName.Length =
649 DeviceName.MaximumLength = DriveLetterTarget->DeviceNameLength;
650
651 Status = MountMgrNextDriveLetterWorker(DeviceExtension, &DeviceName,
652 &DriveLetterInformation);
653 if (NT_SUCCESS(Status))
654 {
655 *(PMOUNTMGR_DRIVE_LETTER_INFORMATION)Irp->AssociatedIrp.SystemBuffer =
656 DriveLetterInformation;
657 Irp->IoStatus.Information = sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION);
658 }
659
660 return Status;
661 }
662
663 /*
664 * @implemented
665 */
666 NTSTATUS
667 NTAPI
MountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName,IN ULONG ValueType,IN PVOID ValueData,IN ULONG ValueLength,IN PVOID Context,IN PVOID EntryContext)668 MountMgrQuerySystemVolumeNameQueryRoutine(IN PWSTR ValueName,
669 IN ULONG ValueType,
670 IN PVOID ValueData,
671 IN ULONG ValueLength,
672 IN PVOID Context,
673 IN PVOID EntryContext)
674 {
675 UNICODE_STRING ValueString;
676 PUNICODE_STRING SystemVolumeName;
677
678 UNREFERENCED_PARAMETER(ValueName);
679 UNREFERENCED_PARAMETER(ValueLength);
680 UNREFERENCED_PARAMETER(EntryContext);
681
682 if (ValueType != REG_SZ)
683 {
684 return STATUS_SUCCESS;
685 }
686
687 RtlInitUnicodeString(&ValueString, ValueData);
688 SystemVolumeName = Context;
689
690 /* Return a string containing system volume name */
691 SystemVolumeName->Length = ValueString.Length;
692 SystemVolumeName->MaximumLength = ValueString.Length + sizeof(WCHAR);
693 SystemVolumeName->Buffer = AllocatePool(SystemVolumeName->MaximumLength);
694 if (SystemVolumeName->Buffer)
695 {
696 RtlCopyMemory(SystemVolumeName->Buffer, ValueData, ValueString.Length);
697 SystemVolumeName->Buffer[ValueString.Length / sizeof(WCHAR)] = UNICODE_NULL;
698 }
699
700 return STATUS_SUCCESS;
701
702 }
703
704 /*
705 * @implemented
706 */
707 NTSTATUS
MountMgrQuerySystemVolumeName(OUT PUNICODE_STRING SystemVolumeName)708 MountMgrQuerySystemVolumeName(OUT PUNICODE_STRING SystemVolumeName)
709 {
710 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
711
712 RtlZeroMemory(QueryTable, sizeof(QueryTable));
713 QueryTable[0].QueryRoutine = MountMgrQuerySystemVolumeNameQueryRoutine;
714 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
715 QueryTable[0].Name = L"SystemPartition";
716
717 SystemVolumeName->Buffer = NULL;
718
719 RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
720 L"\\Registry\\Machine\\System\\Setup",
721 QueryTable,
722 SystemVolumeName,
723 NULL);
724
725 if (SystemVolumeName->Buffer)
726 {
727 return STATUS_SUCCESS;
728 }
729
730 return STATUS_UNSUCCESSFUL;
731 }
732
733 /*
734 * @implemented
735 */
736 VOID
MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)737 MountMgrAssignDriveLetters(IN PDEVICE_EXTENSION DeviceExtension)
738 {
739 NTSTATUS Status;
740 PLIST_ENTRY NextEntry;
741 UNICODE_STRING SystemVolumeName;
742 PDEVICE_INFORMATION DeviceInformation;
743 MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation;
744
745 /* First, get system volume name */
746 Status = MountMgrQuerySystemVolumeName(&SystemVolumeName);
747
748 /* If there are no device, it's all done */
749 if (IsListEmpty(&(DeviceExtension->DeviceListHead)))
750 {
751 if (NT_SUCCESS(Status))
752 {
753 FreePool(SystemVolumeName.Buffer);
754 }
755
756 return;
757 }
758
759 /* Now, for all the devices... */
760 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
761 NextEntry != &(DeviceExtension->DeviceListHead);
762 NextEntry = NextEntry->Flink)
763 {
764 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
765
766 /* If the device doesn't have a letter assigned, do it! */
767 if (!DeviceInformation->LetterAssigned)
768 {
769 MountMgrNextDriveLetterWorker(DeviceExtension,
770 &(DeviceInformation->DeviceName),
771 &DriveLetterInformation);
772 }
773
774 /* If it's the system volume */
775 if (NT_SUCCESS(Status) && RtlEqualUnicodeString(&SystemVolumeName, &(DeviceInformation->DeviceName), TRUE))
776 {
777 /* Keep track of it */
778 DeviceExtension->DriveLetterData = AllocatePool(DeviceInformation->UniqueId->UniqueIdLength +
779 sizeof(MOUNTDEV_UNIQUE_ID));
780 if (DeviceExtension->DriveLetterData)
781 {
782 RtlCopyMemory(DeviceExtension->DriveLetterData,
783 DeviceInformation->UniqueId,
784 DeviceInformation->UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
785 }
786
787 /* Ensure it gets mounted if automount is disabled */
788 if (DeviceExtension->NoAutoMount)
789 {
790 /* Temporarily re-enable automount for the
791 * worker to mount and set a drive letter */
792 DeviceExtension->NoAutoMount = FALSE;
793
794 MountMgrNextDriveLetterWorker(DeviceExtension,
795 &(DeviceInformation->DeviceName),
796 &DriveLetterInformation);
797
798 /* And re-disable automount */
799 DeviceExtension->NoAutoMount = TRUE;
800 }
801 }
802 }
803
804 if (NT_SUCCESS(Status))
805 {
806 FreePool(SystemVolumeName.Buffer);
807 }
808 }
809
810 /*
811 * @implemented
812 */
813 NTSTATUS
MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)814 MountMgrQueryDosVolumePath(IN PDEVICE_EXTENSION DeviceExtension,
815 IN PIRP Irp)
816 {
817 NTSTATUS Status;
818 ULONG DevicesFound;
819 PIO_STACK_LOCATION Stack;
820 PLIST_ENTRY SymlinksEntry;
821 UNICODE_STRING SymbolicName;
822 PMOUNTMGR_TARGET_NAME Target;
823 PMOUNTMGR_VOLUME_PATHS Output;
824 PWSTR DeviceString, OldBuffer;
825 USHORT DeviceLength, OldLength;
826 PDEVICE_INFORMATION DeviceInformation;
827 PSYMLINK_INFORMATION SymlinkInformation;
828 PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
829
830 Stack = IoGetCurrentIrpStackLocation(Irp);
831
832 /* Validate input size */
833 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
834 {
835 return STATUS_INVALID_PARAMETER;
836 }
837
838 /* Ensure we have received UNICODE_STRING */
839 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
840 if (Target->DeviceNameLength & 1)
841 {
842 return STATUS_INVALID_PARAMETER;
843 }
844
845 /* Validate the entry structure size */
846 if (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength >
847 Stack->Parameters.DeviceIoControl.InputBufferLength)
848 {
849 return STATUS_INVALID_PARAMETER;
850 }
851
852 /* Ensure we can at least return needed size */
853 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz))
854 {
855 return STATUS_INVALID_PARAMETER;
856 }
857
858 /* Construct string for query */
859 SymbolicName.Length =
860 SymbolicName.MaximumLength = Target->DeviceNameLength;
861 SymbolicName.Buffer = Target->DeviceName;
862
863 /* Find device with our info */
864 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
865 if (!NT_SUCCESS(Status))
866 {
867 return Status;
868 }
869
870 DeviceLength = 0;
871 DeviceString = NULL;
872 DevicesFound = 0;
873
874 /* Try to find associated device info */
875 while (TRUE)
876 {
877 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
878 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
879 SymlinksEntry = SymlinksEntry->Flink)
880 {
881 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
882
883 /* Try to find with drive letter */
884 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online)
885 {
886 break;
887 }
888 }
889
890 /* If we've found a device via drive letter, do default processing */
891 if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead))
892 break;
893
894 /* If it doesn't have an associated device, go to fallback method */
895 if (IsListEmpty(&DeviceInformation->AssociatedDevicesHead))
896 goto TryWithVolumeName;
897
898 /* Create a string with the information about the device */
899 AssociatedDevice = CONTAINING_RECORD(&(DeviceInformation->AssociatedDevicesHead), ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
900 OldLength = DeviceLength;
901 OldBuffer = DeviceString;
902 DeviceLength += AssociatedDevice->String.Length;
903 DeviceString = AllocatePool(DeviceLength);
904 if (!DeviceString)
905 {
906 if (OldBuffer)
907 {
908 FreePool(OldBuffer);
909 }
910
911 return STATUS_INSUFFICIENT_RESOURCES;
912 }
913
914 /* Store our info and previous if any */
915 RtlCopyMemory(DeviceString, AssociatedDevice->String.Buffer, AssociatedDevice->String.Length);
916 if (OldBuffer)
917 {
918 RtlCopyMemory(&DeviceString[AssociatedDevice->String.Length / sizeof(WCHAR)], OldBuffer, OldLength);
919 FreePool(OldBuffer);
920 }
921
922 /* Count and continue looking */
923 ++DevicesFound;
924 DeviceInformation = AssociatedDevice->DeviceInformation;
925
926 /* If too many devices, try another way */
927 if (DevicesFound > MAX_DEVICES) /* 1000 */
928 {
929 goto TryWithVolumeName;
930 }
931 }
932
933 /* Reallocate our string, so that we can prepend disk letter */
934 OldBuffer = DeviceString;
935 OldLength = DeviceLength;
936 DeviceLength += 2 * sizeof(WCHAR);
937 DeviceString = AllocatePool(DeviceLength);
938 if (!DeviceString)
939 {
940 if (OldBuffer)
941 {
942 FreePool(OldBuffer);
943 }
944
945 return STATUS_INSUFFICIENT_RESOURCES;
946 }
947
948 /* Get the letter */
949 DeviceString[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION];
950 DeviceString[1] = L':';
951
952 /* And copy the rest */
953 if (OldBuffer)
954 {
955 RtlCopyMemory(&DeviceString[2], OldBuffer, OldLength);
956 FreePool(OldBuffer);
957 }
958
959 TryWithVolumeName:
960 /* If we didn't find anything, try differently */
961 if (DeviceLength < 2 * sizeof(WCHAR) || DeviceString[1] != L':')
962 {
963 if (DeviceString)
964 {
965 FreePool(DeviceString);
966 DeviceString = NULL;
967 DeviceLength = 0;
968 }
969
970 /* Try to find a volume name matching */
971 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
972 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
973 SymlinksEntry = SymlinksEntry->Flink)
974 {
975 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
976
977 if (MOUNTMGR_IS_VOLUME_NAME(&SymlinkInformation->Name))
978 {
979 break;
980 }
981 }
982
983 /* If found copy */
984 if (SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead))
985 {
986 DeviceLength = SymlinkInformation->Name.Length;
987 DeviceString = AllocatePool(DeviceLength);
988 if (!DeviceString)
989 {
990 return STATUS_INSUFFICIENT_RESOURCES;
991 }
992
993 RtlCopyMemory(DeviceString, SymlinkInformation->Name.Buffer, DeviceLength);
994 /* Ensure we are in the Win32 namespace; [1] can be '?' */
995 DeviceString[1] = L'\\';
996 }
997 }
998
999 /* If we didn't find something, fail */
1000 if (!DeviceString)
1001 return STATUS_NOT_FOUND;
1002
1003 /* Get the output buffer */
1004 Output = (PMOUNTMGR_VOLUME_PATHS)Irp->AssociatedIrp.SystemBuffer;
1005
1006 /* At least, we will return our length */
1007 Output->MultiSzLength = DeviceLength + 2 * sizeof(UNICODE_NULL);
1008 Irp->IoStatus.Information = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz) + Output->MultiSzLength;
1009
1010 /* If we have enough room for copying the string */
1011 if (Irp->IoStatus.Information <= Stack->Parameters.DeviceIoControl.OutputBufferLength)
1012 {
1013 /* Copy it */
1014 if (DeviceLength)
1015 {
1016 RtlCopyMemory(Output->MultiSz, DeviceString, DeviceLength);
1017 }
1018
1019 /* And double-NUL at its end - this is needed in case of
1020 * multiple paths which are separated by a single NUL */
1021 FreePool(DeviceString);
1022 Output->MultiSz[DeviceLength / sizeof(WCHAR)] = UNICODE_NULL;
1023 Output->MultiSz[DeviceLength / sizeof(WCHAR) + 1] = UNICODE_NULL;
1024
1025 return STATUS_SUCCESS;
1026 }
1027 else
1028 {
1029 /* Just return the size needed and leave */
1030 FreePool(DeviceString);
1031 Irp->IoStatus.Information = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz);
1032 return STATUS_BUFFER_OVERFLOW;
1033 }
1034 }
1035
1036 /*
1037 * @implemented
1038 */
1039 NTSTATUS
MountMgrValidateBackPointer(IN PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry,IN PDEVICE_INFORMATION DeviceInformation,OUT PBOOLEAN Invalid)1040 MountMgrValidateBackPointer(IN PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry,
1041 IN PDEVICE_INFORMATION DeviceInformation,
1042 OUT PBOOLEAN Invalid)
1043 {
1044 HANDLE Handle;
1045 NTSTATUS Status;
1046 PLIST_ENTRY SymlinksEntry;
1047 IO_STATUS_BLOCK IoStatusBlock;
1048 PREPARSE_DATA_BUFFER ReparseData;
1049 OBJECT_ATTRIBUTES ObjectAttributes;
1050 UNICODE_STRING FullName, SubstituteName;
1051 PSYMLINK_INFORMATION SymlinkInformation;
1052
1053 /* Initialize & allocate a string big enough to contain our complete mount point name */
1054 FullName.Length = 0;
1055 FullName.MaximumLength = AssociatedDeviceEntry->String.Length
1056 + AssociatedDeviceEntry->DeviceInformation->DeviceName.Length
1057 + sizeof(WCHAR)
1058 + sizeof(UNICODE_NULL);
1059 FullName.Buffer = AllocatePool(FullName.MaximumLength);
1060 if (!FullName.Buffer)
1061 {
1062 return STATUS_INSUFFICIENT_RESOURCES;
1063 }
1064
1065 /* Create the path */
1066 RtlAppendUnicodeStringToString(&FullName, &AssociatedDeviceEntry->DeviceInformation->DeviceName);
1067 FullName.Buffer[FullName.Length / sizeof(WCHAR)] = L'\\';
1068 RtlAppendUnicodeStringToString(&FullName, &AssociatedDeviceEntry->String);
1069 FullName.Buffer[FullName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1070
1071 /* Open it to query the reparse point */
1072 InitializeObjectAttributes(&ObjectAttributes,
1073 &FullName,
1074 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1075 NULL,
1076 NULL);
1077 Status = ZwOpenFile(&Handle,
1078 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
1079 &ObjectAttributes, &IoStatusBlock,
1080 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1081 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
1082 FreePool(FullName.Buffer);
1083
1084 if (!NT_SUCCESS(Status))
1085 {
1086 *Invalid = TRUE;
1087 return STATUS_SUCCESS;
1088 }
1089
1090 /* Allocate a buffer big enough to read reparse data */
1091 ReparseData = AllocatePool(MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1092 if (ReparseData == NULL)
1093 {
1094 ZwClose(Handle);
1095 return STATUS_INSUFFICIENT_RESOURCES;
1096 }
1097
1098 /* Query reparse data */
1099 Status = ZwFsControlFile(Handle,
1100 NULL, NULL, NULL,
1101 &IoStatusBlock,
1102 FSCTL_GET_REPARSE_POINT,
1103 NULL, 0,
1104 ReparseData, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1105 ZwClose(Handle);
1106
1107 if (!NT_SUCCESS(Status))
1108 {
1109 FreePool(ReparseData);
1110 *Invalid = TRUE;
1111 return STATUS_SUCCESS;
1112 }
1113
1114 /* Create a string with the substitute name */
1115 SubstituteName.Length = ReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
1116 SubstituteName.MaximumLength = SubstituteName.Length;
1117 SubstituteName.Buffer = (PWSTR)((ULONG_PTR)ReparseData->SymbolicLinkReparseBuffer.PathBuffer + ReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset);
1118
1119 /* If that's a volume name that matches our associated device, that's a success! */
1120 if (MOUNTMGR_IS_VOLUME_NAME(&SubstituteName))
1121 {
1122 if (SubstituteName.Length == 98 && SubstituteName.Buffer[1] == L'?')
1123 {
1124 for (SymlinksEntry = DeviceInformation->SymbolicLinksListHead.Flink;
1125 SymlinksEntry != &(DeviceInformation->SymbolicLinksListHead);
1126 SymlinksEntry = SymlinksEntry->Flink)
1127 {
1128 SymlinkInformation = CONTAINING_RECORD(SymlinksEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
1129
1130 if (RtlEqualUnicodeString(&SubstituteName, &SymlinkInformation->Name, TRUE))
1131 {
1132 FreePool(ReparseData);
1133 return STATUS_SUCCESS;
1134 }
1135 }
1136 }
1137 }
1138
1139 FreePool(ReparseData);
1140 *Invalid = TRUE;
1141 return STATUS_SUCCESS;
1142 }
1143
1144 /*
1145 * @implemented
1146 */
1147 NTSTATUS
MountMgrQueryVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,IN PDEVICE_INFORMATION DeviceInformation,IN PLIST_ENTRY DeviceInfoList,OUT PMOUNTMGR_VOLUME_PATHS * VolumePaths,OUT PDEVICE_INFORMATION * FailedDevice)1148 MountMgrQueryVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
1149 IN PDEVICE_INFORMATION DeviceInformation,
1150 IN PLIST_ENTRY DeviceInfoList,
1151 OUT PMOUNTMGR_VOLUME_PATHS * VolumePaths,
1152 OUT PDEVICE_INFORMATION *FailedDevice)
1153 {
1154 ULONG Written;
1155 NTSTATUS Status;
1156 PLIST_ENTRY Entry;
1157 PSYMLINK_INFORMATION SymlinkInformation;
1158 PDEVICE_INFORMATION_ENTRY DeviceInfoEntry;
1159 PASSOCIATED_DEVICE_ENTRY AssociatedDeviceEntry;
1160 PMOUNTMGR_VOLUME_PATHS * Paths = NULL, * CurrentPath;
1161 ULONG OutputPathLength, NumberOfPaths, ReturnedPaths;
1162
1163 /* We return at least null char */
1164 OutputPathLength = sizeof(UNICODE_NULL);
1165
1166 for (Entry = DeviceInformation->SymbolicLinksListHead.Flink;
1167 Entry != &(DeviceInformation->SymbolicLinksListHead);
1168 Entry = Entry->Flink)
1169 {
1170 SymlinkInformation = CONTAINING_RECORD(Entry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
1171
1172 /* Try to find the drive letter (ie, DOS device) */
1173 if (MOUNTMGR_IS_DRIVE_LETTER(&SymlinkInformation->Name) && SymlinkInformation->Online)
1174 {
1175 /* We'll return the letter */
1176 OutputPathLength = 4 * sizeof(WCHAR);
1177 break;
1178 }
1179 }
1180
1181 /* We didn't find any */
1182 if (Entry == &(DeviceInformation->SymbolicLinksListHead))
1183 {
1184 SymlinkInformation = NULL;
1185 }
1186
1187 /* Do we have any device info to return? */
1188 for (Entry = DeviceInfoList->Flink; Entry != DeviceInfoList; Entry = Entry->Flink)
1189 {
1190 DeviceInfoEntry = CONTAINING_RECORD(Entry, DEVICE_INFORMATION_ENTRY, DeviceInformationEntry);
1191
1192 /* Matching current device */
1193 if (DeviceInfoEntry->DeviceInformation == DeviceInformation)
1194 {
1195 /* Allocate the output buffer */
1196 *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength);
1197 if (*VolumePaths == NULL)
1198 {
1199 return STATUS_INSUFFICIENT_RESOURCES;
1200 }
1201
1202 /* Set size */
1203 (*VolumePaths)->MultiSzLength = OutputPathLength;
1204 /* If we have a drive letter, return it */
1205 if (SymlinkInformation != NULL)
1206 {
1207 (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION];
1208 (*VolumePaths)->MultiSz[1] = L':';
1209 (*VolumePaths)->MultiSz[2] = UNICODE_NULL;
1210 (*VolumePaths)->MultiSz[3] = UNICODE_NULL;
1211 }
1212 else
1213 {
1214 (*VolumePaths)->MultiSz[0] = UNICODE_NULL;
1215 }
1216
1217 return STATUS_SUCCESS;
1218 }
1219 }
1220
1221 /* Allocate a new device entry */
1222 DeviceInfoEntry = AllocatePool(sizeof(DEVICE_INFORMATION_ENTRY));
1223 if (DeviceInfoEntry == NULL)
1224 {
1225 return STATUS_INSUFFICIENT_RESOURCES;
1226 }
1227
1228 /* Add it to the list */
1229 DeviceInfoEntry->DeviceInformation = DeviceInformation;
1230 InsertTailList(DeviceInfoList, &DeviceInfoEntry->DeviceInformationEntry);
1231
1232 NumberOfPaths = 0;
1233 /* Count the amount of devices we will have to handle */
1234 if (!IsListEmpty(&DeviceInformation->AssociatedDevicesHead))
1235 {
1236 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink;
1237 Entry != &DeviceInformation->AssociatedDevicesHead;
1238 Entry = Entry->Flink)
1239 {
1240 ++NumberOfPaths;
1241 }
1242
1243 ASSERT(NumberOfPaths != 0);
1244 /* And allocate a big enough buffer */
1245 Paths = AllocatePool(NumberOfPaths * sizeof(PMOUNTMGR_VOLUME_PATHS));
1246 if (Paths == NULL)
1247 {
1248 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
1249 FreePool(DeviceInfoEntry);
1250 return STATUS_INSUFFICIENT_RESOURCES;
1251 }
1252 }
1253
1254 /* Start the hot loop to gather all the paths and be able to compute total output length! */
1255 ReturnedPaths = 0;
1256 CurrentPath = Paths;
1257 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink;
1258 Entry != &DeviceInformation->AssociatedDevicesHead;
1259 Entry = Entry->Flink)
1260 {
1261 USHORT InnerStrings;
1262 BOOLEAN Invalid = FALSE;
1263
1264 AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
1265
1266 /* Validate the fact its a mount point by query reparse data */
1267 Status = MountMgrValidateBackPointer(AssociatedDeviceEntry, DeviceInformation, &Invalid);
1268
1269 /* If we found an invalid device, that's a failure */
1270 if (Invalid)
1271 {
1272 *FailedDevice = AssociatedDeviceEntry->DeviceInformation;
1273 Status = STATUS_UNSUCCESSFUL;
1274 }
1275
1276 /* Check whether we failed, if so, bail out */
1277 if (!NT_SUCCESS(Status))
1278 {
1279 ULONG i;
1280
1281 for (i = 0; i < ReturnedPaths; ++i)
1282 {
1283 FreePool(Paths[i]);
1284 }
1285
1286 if (Paths != NULL)
1287 {
1288 FreePool(Paths);
1289 }
1290 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
1291 FreePool(DeviceInfoEntry);
1292 return Status;
1293 }
1294
1295 /* Query associated paths (hello ourselves :-)) */
1296 Status = MountMgrQueryVolumePaths(DeviceExtension,
1297 AssociatedDeviceEntry->DeviceInformation,
1298 DeviceInfoList,
1299 CurrentPath,
1300 FailedDevice);
1301 if (!NT_SUCCESS(Status))
1302 {
1303 ULONG i;
1304
1305 for (i = 0; i < ReturnedPaths; ++i)
1306 {
1307 FreePool(Paths[i]);
1308 }
1309
1310 if (Paths != NULL)
1311 {
1312 FreePool(Paths);
1313 }
1314 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
1315 FreePool(DeviceInfoEntry);
1316 return Status;
1317 }
1318
1319 /* Count the number of strings we have in the multi string buffer */
1320 InnerStrings = 0;
1321 if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL))
1322 {
1323 ULONG i;
1324 PWSTR MultiSz = (*CurrentPath)->MultiSz;
1325
1326 for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR); ++i, ++MultiSz)
1327 {
1328 if (*MultiSz == UNICODE_NULL)
1329 {
1330 ++InnerStrings;
1331 }
1332 }
1333 }
1334
1335 /* We returned one more path (ie, one more allocated buffer) */
1336 ++ReturnedPaths;
1337 /* Move the next pointer to use in the array */
1338 ++CurrentPath;
1339 /* Multiply String.Length by the number of found paths, we always add it after a path */
1340 OutputPathLength += (*CurrentPath)->MultiSzLength + InnerStrings * AssociatedDeviceEntry->String.Length - sizeof(UNICODE_NULL);
1341 }
1342
1343 /* Allocate the output buffer */
1344 *VolumePaths = AllocatePool(sizeof(ULONG) + OutputPathLength);
1345 if (*VolumePaths == NULL)
1346 {
1347 ULONG i;
1348
1349 for (i = 0; i < ReturnedPaths; ++i)
1350 {
1351 FreePool(Paths[i]);
1352 }
1353
1354 if (Paths != NULL)
1355 {
1356 FreePool(Paths);
1357 }
1358 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
1359 FreePool(DeviceInfoEntry);
1360 return STATUS_INSUFFICIENT_RESOURCES;
1361 }
1362
1363 Written = 0;
1364 /* If we had found a DOS letter, that's the first thing we return */
1365 (*VolumePaths)->MultiSzLength = OutputPathLength;
1366 if (SymlinkInformation != NULL)
1367 {
1368 (*VolumePaths)->MultiSz[0] = SymlinkInformation->Name.Buffer[LETTER_POSITION];
1369 (*VolumePaths)->MultiSz[1] = L':';
1370 (*VolumePaths)->MultiSz[2] = UNICODE_NULL;
1371 Written = 3;
1372 }
1373
1374 /* Now, browse again all our paths to return them */
1375 CurrentPath = Paths;
1376 for (Entry = DeviceInformation->AssociatedDevicesHead.Flink;
1377 Entry != &DeviceInformation->AssociatedDevicesHead;
1378 Entry = Entry->Flink)
1379 {
1380 AssociatedDeviceEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
1381
1382 /* If we had a path... */
1383 if ((*CurrentPath)->MultiSzLength != sizeof(UNICODE_NULL))
1384 {
1385 ULONG i, Offset;
1386 PWSTR MultiSz;
1387
1388 /* This offset is used to "jump" into MultiSz, so, start with the string begin (ie, skip MultiSzLength) */
1389 Offset = sizeof(ULONG);
1390 /* Browse every single letter, and skip last UNICODE_NULL */
1391 for (i = 0; i < (*CurrentPath)->MultiSzLength / sizeof(WCHAR) - 1; ++i)
1392 {
1393 /* Get the letter */
1394 MultiSz = (PWSTR)((ULONG_PTR)(*CurrentPath) + Offset);
1395 /* If it was part of the path, just return it */
1396 if (*MultiSz != UNICODE_NULL)
1397 {
1398 (*VolumePaths)->MultiSz[Written] = *MultiSz;
1399 }
1400 else
1401 {
1402 /* Otherwise, as planed, return our whole associated device name */
1403 RtlCopyMemory(&(*VolumePaths)->MultiSz[Written],
1404 AssociatedDeviceEntry->String.Buffer,
1405 AssociatedDeviceEntry->String.Length);
1406 Written += AssociatedDeviceEntry->String.Length / sizeof(WCHAR);
1407 /* And don't forget to nullify */
1408 (*VolumePaths)->MultiSz[Written] = UNICODE_NULL;
1409 }
1410
1411 /* We at least return a letter or a null char */
1412 ++Written;
1413 /* Move to the next letter */
1414 Offset += sizeof(WCHAR);
1415 }
1416 }
1417
1418 FreePool(*CurrentPath);
1419 ++CurrentPath;
1420 }
1421
1422 /* MultiSz: don't forget last null char */
1423 (*VolumePaths)->MultiSz[Written] = UNICODE_NULL;
1424 /* Cleanup everything and return success! */
1425 if (Paths != NULL)
1426 {
1427 FreePool(Paths);
1428 }
1429 RemoveEntryList(&DeviceInfoEntry->DeviceInformationEntry);
1430 FreePool(DeviceInfoEntry);
1431 return STATUS_SUCCESS;
1432 }
1433
1434 /*
1435 * @implemented
1436 */
1437 NTSTATUS
MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1438 MountMgrQueryDosVolumePaths(IN PDEVICE_EXTENSION DeviceExtension,
1439 IN PIRP Irp)
1440 {
1441 NTSTATUS Status;
1442 PLIST_ENTRY Entry;
1443 LIST_ENTRY Devices;
1444 BOOLEAN NeedNotification;
1445 PIO_STACK_LOCATION Stack;
1446 UNICODE_STRING SymbolicName;
1447 ULONG Attempts, OutputLength;
1448 PMOUNTMGR_TARGET_NAME Target;
1449 PMOUNTMGR_VOLUME_PATHS Paths, Output;
1450 RECONCILE_WORK_ITEM_CONTEXT ReconcileContext;
1451 PDEVICE_INFORMATION DeviceInformation, ListDeviceInfo, FailedDevice;
1452
1453 Stack = IoGetCurrentIrpStackLocation(Irp);
1454
1455 /* Validate input size */
1456 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
1457 {
1458 return STATUS_INVALID_PARAMETER;
1459 }
1460
1461 /* Ensure we have received UNICODE_STRING */
1462 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
1463 if (Target->DeviceNameLength & 1)
1464 {
1465 return STATUS_INVALID_PARAMETER;
1466 }
1467
1468 /* Validate the entry structure size */
1469 if (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength >
1470 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 < FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz))
1477 {
1478 return STATUS_INVALID_PARAMETER;
1479 }
1480
1481 /* Construct string for query */
1482 SymbolicName.Length =
1483 SymbolicName.MaximumLength = Target->DeviceNameLength;
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 the 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 = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz) + Output->MultiSzLength;
1568
1569 /* If it cannot fit, just return the size needed and leave */
1570 if (OutputLength > Stack->Parameters.DeviceIoControl.OutputBufferLength)
1571 {
1572 Irp->IoStatus.Information = FIELD_OFFSET(MOUNTMGR_VOLUME_PATHS, MultiSz);
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 (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength >
1607 Stack->Parameters.DeviceIoControl.InputBufferLength)
1608 {
1609 return STATUS_INVALID_PARAMETER;
1610 }
1611
1612 SymbolicName.Length =
1613 SymbolicName.MaximumLength = Target->DeviceNameLength;
1614 SymbolicName.Buffer = Target->DeviceName;
1615
1616 /* Find the associated device */
1617 Status = FindDeviceInfo(DeviceExtension, &SymbolicName, FALSE, &DeviceInformation);
1618 if (!NT_SUCCESS(Status))
1619 {
1620 return Status;
1621 }
1622
1623 /* Mark we want to keep links */
1624 DeviceInformation->KeepLinks = TRUE;
1625
1626 return STATUS_SUCCESS;
1627 }
1628
1629 /*
1630 * @implemented
1631 */
1632 NTSTATUS
MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1633 MountMgrVolumeArrivalNotification(IN PDEVICE_EXTENSION DeviceExtension,
1634 IN PIRP Irp)
1635 {
1636 NTSTATUS Status;
1637 BOOLEAN OldState;
1638 PIO_STACK_LOCATION Stack;
1639 UNICODE_STRING SymbolicName;
1640 PMOUNTMGR_TARGET_NAME Target;
1641
1642 Stack = IoGetCurrentIrpStackLocation(Irp);
1643
1644 /* Validate input */
1645 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_TARGET_NAME))
1646 {
1647 return STATUS_INVALID_PARAMETER;
1648 }
1649
1650 Target = (PMOUNTMGR_TARGET_NAME)Irp->AssociatedIrp.SystemBuffer;
1651 if (FIELD_OFFSET(MOUNTMGR_TARGET_NAME, DeviceName) + Target->DeviceNameLength >
1652 Stack->Parameters.DeviceIoControl.InputBufferLength)
1653 {
1654 return STATUS_INVALID_PARAMETER;
1655 }
1656
1657 SymbolicName.Length =
1658 SymbolicName.MaximumLength = Target->DeviceNameLength;
1659 SymbolicName.Buffer = Target->DeviceName;
1660
1661 /* Disable hard errors */
1662 OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1663 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
1664
1665 /* Call real worker */
1666 Status = MountMgrMountedDeviceArrival(DeviceExtension, &SymbolicName, TRUE);
1667
1668 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
1669
1670 return Status;
1671 }
1672
1673 /*
1674 * @implemented
1675 */
1676 NTSTATUS
MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1677 MountMgrQueryPoints(IN PDEVICE_EXTENSION DeviceExtension,
1678 IN PIRP Irp)
1679 {
1680 NTSTATUS Status;
1681 PIO_STACK_LOCATION Stack;
1682 PMOUNTDEV_UNIQUE_ID UniqueId;
1683 PMOUNTMGR_MOUNT_POINT MountPoint;
1684 UNICODE_STRING SymbolicName, DeviceName;
1685
1686 Stack = IoGetCurrentIrpStackLocation(Irp);
1687
1688 /* Validate input... */
1689 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
1690 {
1691 return STATUS_INVALID_PARAMETER;
1692 }
1693
1694 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1695 if (!MountPoint->SymbolicLinkNameLength)
1696 {
1697 MountPoint->SymbolicLinkNameOffset = 0;
1698 }
1699
1700 if (!MountPoint->UniqueIdLength)
1701 {
1702 MountPoint->UniqueIdOffset = 0;
1703 }
1704
1705 if (!MountPoint->DeviceNameLength)
1706 {
1707 MountPoint->DeviceNameOffset = 0;
1708 }
1709
1710 /* Addresses can't be odd */
1711 if ((MountPoint->SymbolicLinkNameOffset & 1) ||
1712 (MountPoint->SymbolicLinkNameLength & 1))
1713 {
1714 return STATUS_INVALID_PARAMETER;
1715 }
1716
1717 if ((MountPoint->UniqueIdOffset & 1) ||
1718 (MountPoint->UniqueIdLength & 1))
1719 {
1720 return STATUS_INVALID_PARAMETER;
1721 }
1722
1723 if ((MountPoint->DeviceNameOffset & 1) ||
1724 (MountPoint->DeviceNameLength & 1))
1725 {
1726 return STATUS_INVALID_PARAMETER;
1727 }
1728
1729 /* We can't go beyond */
1730 if (((ULONG)MountPoint->SymbolicLinkNameLength + MountPoint->UniqueIdLength +
1731 MountPoint->DeviceNameLength) > Stack->Parameters.DeviceIoControl.InputBufferLength)
1732 {
1733 return STATUS_INVALID_PARAMETER;
1734 }
1735
1736 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTMGR_MOUNT_POINTS))
1737 {
1738 return STATUS_INVALID_PARAMETER;
1739 }
1740
1741 /* If caller provided a Symlink, use it */
1742 if (MountPoint->SymbolicLinkNameLength != 0)
1743 {
1744 if (MountPoint->SymbolicLinkNameLength > MAXSHORT)
1745 {
1746 return STATUS_INVALID_PARAMETER;
1747 }
1748
1749 SymbolicName.Length = MountPoint->SymbolicLinkNameLength;
1750 SymbolicName.MaximumLength = MountPoint->SymbolicLinkNameLength + sizeof(WCHAR);
1751 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1752 if (!SymbolicName.Buffer)
1753 {
1754 return STATUS_INSUFFICIENT_RESOURCES;
1755 }
1756
1757 RtlCopyMemory(SymbolicName.Buffer,
1758 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->SymbolicLinkNameOffset),
1759 SymbolicName.Length);
1760 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1761
1762 /* Query links using it */
1763 Status = QueryPointsFromSymbolicLinkName(DeviceExtension, &SymbolicName, Irp);
1764 FreePool(SymbolicName.Buffer);
1765 }
1766 /* If user provided an unique ID */
1767 else if (MountPoint->UniqueIdLength != 0)
1768 {
1769 UniqueId = AllocatePool(MountPoint->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1770 if (!UniqueId)
1771 {
1772 return STATUS_INSUFFICIENT_RESOURCES;
1773 }
1774
1775 UniqueId->UniqueIdLength = MountPoint->UniqueIdLength;
1776 RtlCopyMemory(UniqueId->UniqueId,
1777 (PVOID)((ULONG_PTR)MountPoint + MountPoint->UniqueIdOffset),
1778 MountPoint->UniqueIdLength);
1779
1780 /* Query links using it */
1781 Status = QueryPointsFromMemory(DeviceExtension, Irp, UniqueId, NULL);
1782 FreePool(UniqueId);
1783 }
1784 /* If caller provided a device name */
1785 else if (MountPoint->DeviceNameLength != 0)
1786 {
1787 if (MountPoint->DeviceNameLength > MAXSHORT)
1788 {
1789 return STATUS_INVALID_PARAMETER;
1790 }
1791
1792 DeviceName.Length = MountPoint->DeviceNameLength;
1793 DeviceName.MaximumLength = MountPoint->DeviceNameLength + sizeof(WCHAR);
1794 DeviceName.Buffer = AllocatePool(DeviceName.MaximumLength);
1795 if (!DeviceName.Buffer)
1796 {
1797 return STATUS_INSUFFICIENT_RESOURCES;
1798 }
1799
1800 RtlCopyMemory(DeviceName.Buffer,
1801 (PWSTR)((ULONG_PTR)MountPoint + MountPoint->DeviceNameOffset),
1802 DeviceName.Length);
1803 DeviceName.Buffer[DeviceName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1804
1805 /* Query links using it */
1806 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, &DeviceName);
1807 FreePool(DeviceName.Buffer);
1808 }
1809 else
1810 {
1811 /* Otherwise, query all links */
1812 Status = QueryPointsFromMemory(DeviceExtension, Irp, NULL, NULL);
1813 }
1814
1815 return Status;
1816 }
1817
1818 /*
1819 * @implemented
1820 */
1821 NTSTATUS
MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1822 MountMgrDeletePoints(IN PDEVICE_EXTENSION DeviceExtension,
1823 IN PIRP Irp)
1824 {
1825 ULONG Link;
1826 NTSTATUS Status;
1827 BOOLEAN CreateNoDrive;
1828 PIO_STACK_LOCATION Stack;
1829 PMOUNTDEV_UNIQUE_ID UniqueId;
1830 PMOUNTMGR_MOUNT_POINT MountPoint;
1831 PMOUNTMGR_MOUNT_POINTS MountPoints;
1832 UNICODE_STRING SymbolicName, DeviceName;
1833
1834 Stack = IoGetCurrentIrpStackLocation(Irp);
1835
1836 /* Validate input */
1837 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_MOUNT_POINT))
1838 {
1839 return STATUS_INVALID_PARAMETER;
1840 }
1841
1842 /* Query points */
1843 MountPoint = (PMOUNTMGR_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
1844 CreateNoDrive = (MountPoint->SymbolicLinkNameOffset && MountPoint->SymbolicLinkNameLength);
1845
1846 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1847 if (!NT_SUCCESS(Status))
1848 {
1849 return Status;
1850 }
1851
1852 /* For all the points matching the request */
1853 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
1854 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++)
1855 {
1856 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength;
1857 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR);
1858 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1859 if (!SymbolicName.Buffer)
1860 {
1861 return STATUS_INSUFFICIENT_RESOURCES;
1862 }
1863
1864 RtlCopyMemory(SymbolicName.Buffer,
1865 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset),
1866 SymbolicName.Length);
1867 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1868
1869 /* Create a no drive entry for the drive letters */
1870 if (CreateNoDrive && IsDriveLetter(&SymbolicName))
1871 {
1872 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1873 if (UniqueId)
1874 {
1875 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength;
1876 RtlCopyMemory(UniqueId->UniqueId,
1877 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1878 MountPoints->MountPoints[Link].UniqueIdLength);
1879
1880 CreateNoDriveLetterEntry(UniqueId);
1881 FreePool(UniqueId);
1882 }
1883 }
1884
1885 /* If there are no link any more, and no need to create a no drive entry */
1886 if (Link == 0 && !CreateNoDrive)
1887 {
1888 /* Then, delete everything */
1889 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength);
1890 if (UniqueId)
1891 {
1892 RtlCopyMemory(UniqueId,
1893 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1894 MountPoints->MountPoints[Link].UniqueIdLength);
1895
1896 DeleteNoDriveLetterEntry(UniqueId);
1897 FreePool(UniqueId);
1898 }
1899 }
1900
1901 /* Delete all the information about the mount point */
1902 GlobalDeleteSymbolicLink(&SymbolicName);
1903 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, FALSE);
1904 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer);
1905 FreePool(SymbolicName.Buffer);
1906
1907 /* Notify the change */
1908 DeviceName.Length = DeviceName.MaximumLength =
1909 MountPoints->MountPoints[Link].DeviceNameLength;
1910 DeviceName.Buffer = (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].DeviceNameOffset);
1911 MountMgrNotifyNameChange(DeviceExtension, &DeviceName, TRUE);
1912 }
1913
1914 MountMgrNotify(DeviceExtension);
1915
1916 return Status;
1917 }
1918
1919 /*
1920 * @implemented
1921 */
1922 NTSTATUS
MountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp)1923 MountMgrDeletePointsDbOnly(IN PDEVICE_EXTENSION DeviceExtension,
1924 IN PIRP Irp)
1925 {
1926 ULONG Link;
1927 NTSTATUS Status;
1928 UNICODE_STRING SymbolicName;
1929 PMOUNTDEV_UNIQUE_ID UniqueId;
1930 PMOUNTMGR_MOUNT_POINTS MountPoints;
1931
1932 /* Query points */
1933 Status = MountMgrQueryPoints(DeviceExtension, Irp);
1934 if (!NT_SUCCESS(Status))
1935 {
1936 return Status;
1937 }
1938
1939 MountPoints = (PMOUNTMGR_MOUNT_POINTS)Irp->AssociatedIrp.SystemBuffer;
1940 if (MountPoints->NumberOfMountPoints == 0)
1941 {
1942 return Status;
1943 }
1944
1945 /* For all the mount points */
1946 for (Link = 0; Link < MountPoints->NumberOfMountPoints; Link++)
1947 {
1948 SymbolicName.Length = MountPoints->MountPoints[Link].SymbolicLinkNameLength;
1949 SymbolicName.MaximumLength = SymbolicName.Length + sizeof(WCHAR);
1950 SymbolicName.Buffer = AllocatePool(SymbolicName.MaximumLength);
1951 if (!SymbolicName.Buffer)
1952 {
1953 return STATUS_INSUFFICIENT_RESOURCES;
1954 }
1955
1956 RtlCopyMemory(SymbolicName.Buffer,
1957 (PWSTR)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].SymbolicLinkNameOffset),
1958 SymbolicName.Length);
1959 SymbolicName.Buffer[SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
1960
1961 /* If the only mount point is a drive letter, then create a no letter drive entry */
1962 if (MountPoints->NumberOfMountPoints == 1 && IsDriveLetter(&SymbolicName))
1963 {
1964 UniqueId = AllocatePool(MountPoints->MountPoints[Link].UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1965 if (UniqueId)
1966 {
1967 UniqueId->UniqueIdLength = MountPoints->MountPoints[Link].UniqueIdLength;
1968 RtlCopyMemory(UniqueId->UniqueId,
1969 (PMOUNTDEV_UNIQUE_ID)((ULONG_PTR)MountPoints + MountPoints->MountPoints[Link].UniqueIdOffset),
1970 MountPoints->MountPoints[Link].UniqueIdLength);
1971
1972 CreateNoDriveLetterEntry(UniqueId);
1973 FreePool(UniqueId);
1974 }
1975 }
1976
1977 /* Simply delete mount point from DB */
1978 DeleteSymbolicLinkNameFromMemory(DeviceExtension, &SymbolicName, TRUE);
1979 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, DatabasePath, SymbolicName.Buffer);
1980 FreePool(SymbolicName.Buffer);
1981 }
1982
1983 return Status;
1984 }
1985
1986 /*
1987 * @implemented
1988 */
1989 NTSTATUS
MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp,IN NTSTATUS LockStatus,OUT PUNICODE_STRING SourceDeviceName,OUT PUNICODE_STRING SourceSymbolicName,OUT PUNICODE_STRING TargetVolumeName)1990 MountMgrVolumeMountPointChanged(IN PDEVICE_EXTENSION DeviceExtension,
1991 IN PIRP Irp,
1992 IN NTSTATUS LockStatus,
1993 OUT PUNICODE_STRING SourceDeviceName,
1994 OUT PUNICODE_STRING SourceSymbolicName,
1995 OUT PUNICODE_STRING TargetVolumeName)
1996 {
1997 HANDLE Handle;
1998 NTSTATUS Status;
1999 PFILE_OBJECT FileObject;
2000 PIO_STACK_LOCATION Stack;
2001 ULONG Length, SavedLength;
2002 BOOLEAN FOReferenced = FALSE;
2003 IO_STATUS_BLOCK IoStatusBlock;
2004 OBJECT_ATTRIBUTES ObjectAttributes;
2005 PDEVICE_INFORMATION DeviceInformation;
2006 OBJECT_NAME_INFORMATION ObjectNameInfo;
2007 FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
2008 PFILE_NAME_INFORMATION FileNameInfo = NULL;
2009 PMOUNTMGR_VOLUME_MOUNT_POINT VolumeMountPoint;
2010 POBJECT_NAME_INFORMATION ObjectNameInfoPtr = NULL;
2011 UNICODE_STRING SourceVolumeName, TargetDeviceName;
2012
2013 Stack = IoGetCurrentIrpStackLocation(Irp);
2014
2015 /* Validate input */
2016 if (Stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(MOUNTMGR_VOLUME_MOUNT_POINT))
2017 {
2018 return STATUS_INVALID_PARAMETER;
2019 }
2020
2021 VolumeMountPoint = (PMOUNTMGR_VOLUME_MOUNT_POINT)Irp->AssociatedIrp.SystemBuffer;
2022
2023 if (((ULONG)VolumeMountPoint->SourceVolumeNameLength + VolumeMountPoint->TargetVolumeNameLength) <
2024 Stack->Parameters.DeviceIoControl.InputBufferLength)
2025 {
2026 return STATUS_INVALID_PARAMETER;
2027 }
2028
2029 /* Get source volume name */
2030 SourceVolumeName.Length =
2031 SourceVolumeName.MaximumLength = VolumeMountPoint->SourceVolumeNameLength;
2032 SourceVolumeName.Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->SourceVolumeNameOffset);
2033
2034 InitializeObjectAttributes(&ObjectAttributes,
2035 &SourceVolumeName,
2036 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
2037 NULL,
2038 NULL);
2039
2040 /* Open it */
2041 Status = ZwOpenFile(&Handle,
2042 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
2043 &ObjectAttributes,
2044 &IoStatusBlock,
2045 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2046 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT);
2047 if (!NT_SUCCESS(Status))
2048 {
2049 return Status;
2050 }
2051
2052 TargetDeviceName.Buffer = NULL;
2053
2054 /* Query its attributes */
2055 Status = ZwQueryVolumeInformationFile(Handle,
2056 &IoStatusBlock,
2057 &FsDeviceInfo,
2058 sizeof(FsDeviceInfo),
2059 FileFsDeviceInformation);
2060 if (!NT_SUCCESS(Status))
2061 {
2062 goto Cleanup;
2063 }
2064
2065 if (FsDeviceInfo.DeviceType != FILE_DEVICE_DISK && FsDeviceInfo.DeviceType != FILE_DEVICE_VIRTUAL_DISK)
2066 {
2067 goto Cleanup;
2068 }
2069
2070 if (FsDeviceInfo.Characteristics != (FILE_REMOTE_DEVICE | FILE_REMOVABLE_MEDIA))
2071 {
2072 goto Cleanup;
2073 }
2074
2075 /* Reference it */
2076 Status = ObReferenceObjectByHandle(Handle, 0, *IoFileObjectType, KernelMode, (PVOID *)&FileObject, NULL);
2077 if (!NT_SUCCESS(Status))
2078 {
2079 goto Cleanup;
2080 }
2081 FOReferenced = TRUE;
2082
2083 /* Get file name */
2084 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION));
2085 if (!FileNameInfo)
2086 {
2087 Status = STATUS_INSUFFICIENT_RESOURCES;
2088 goto Cleanup;
2089 }
2090
2091 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo,
2092 sizeof(FILE_NAME_INFORMATION),
2093 FileNameInformation);
2094 if (Status == STATUS_BUFFER_OVERFLOW)
2095 {
2096 /* Now we have real length, use it */
2097 Length = FileNameInfo->FileNameLength;
2098 FreePool(FileNameInfo);
2099
2100 FileNameInfo = AllocatePool(sizeof(FILE_NAME_INFORMATION) + Length);
2101 if (!FileNameInfo)
2102 {
2103 Status = STATUS_INSUFFICIENT_RESOURCES;
2104 goto Cleanup;
2105 }
2106
2107 /* Really query file name */
2108 Status = ZwQueryInformationFile(Handle, &IoStatusBlock, FileNameInfo,
2109 sizeof(FILE_NAME_INFORMATION) + Length,
2110 FileNameInformation);
2111 }
2112
2113 if (!NT_SUCCESS(Status))
2114 {
2115 goto Cleanup;
2116 }
2117
2118 /* Get symbolic name */
2119 ObjectNameInfoPtr = &ObjectNameInfo;
2120 SavedLength = sizeof(OBJECT_NAME_INFORMATION);
2121 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, sizeof(OBJECT_NAME_INFORMATION), &Length);
2122 if (Status == STATUS_INFO_LENGTH_MISMATCH)
2123 {
2124 /* Once again, with proper size, it works better */
2125 ObjectNameInfoPtr = AllocatePool(Length);
2126 if (!ObjectNameInfoPtr)
2127 {
2128 Status = STATUS_INSUFFICIENT_RESOURCES;
2129 goto Cleanup;
2130 }
2131
2132 SavedLength = Length;
2133 Status = ObQueryNameString(FileObject->DeviceObject, ObjectNameInfoPtr, SavedLength, &Length);
2134 }
2135
2136 if (!NT_SUCCESS(Status))
2137 {
2138 goto Cleanup;
2139 }
2140
2141 /* Now, query the device name */
2142 Status = QueryDeviceInformation(&ObjectNameInfoPtr->Name, SourceDeviceName,
2143 NULL, NULL, NULL, NULL, NULL, NULL);
2144 if (!NT_SUCCESS(Status))
2145 {
2146 goto Cleanup;
2147 }
2148
2149 /* For target volume name, use input */
2150 TargetVolumeName->Length =
2151 TargetVolumeName->MaximumLength = VolumeMountPoint->TargetVolumeNameLength;
2152 TargetVolumeName->Buffer = (PWSTR)((ULONG_PTR)VolumeMountPoint + VolumeMountPoint->TargetVolumeNameOffset);
2153
2154 /* Query its device name */
2155 Status = QueryDeviceInformation(TargetVolumeName, &TargetDeviceName,
2156 NULL, NULL, NULL, NULL, NULL, NULL);
2157 if (!NT_SUCCESS(Status))
2158 {
2159 goto Cleanup;
2160 }
2161
2162 /* Return symbolic name */
2163 SourceSymbolicName->Length =
2164 SourceSymbolicName->MaximumLength = (USHORT)FileNameInfo->FileNameLength;
2165 SourceSymbolicName->Buffer = (PWSTR)FileNameInfo;
2166 /* memmove allows memory overlap */
2167 RtlMoveMemory(SourceSymbolicName->Buffer, FileNameInfo->FileName, SourceSymbolicName->Length);
2168 FileNameInfo = NULL;
2169
2170 /* Notify the change */
2171 MountMgrNotify(DeviceExtension);
2172 MountMgrNotifyNameChange(DeviceExtension, &TargetDeviceName, TRUE);
2173
2174 /* If we are locked, sync databases if possible */
2175 if (NT_SUCCESS(LockStatus))
2176 {
2177 Status = FindDeviceInfo(DeviceExtension, SourceDeviceName, FALSE, &DeviceInformation);
2178 if (NT_SUCCESS(Status))
2179 {
2180 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
2181 }
2182 else
2183 {
2184 Status = STATUS_PENDING;
2185 }
2186 }
2187
2188 Cleanup:
2189 if (TargetDeviceName.Buffer)
2190 {
2191 FreePool(TargetDeviceName.Buffer);
2192 }
2193
2194 if (ObjectNameInfoPtr && ObjectNameInfoPtr != &ObjectNameInfo)
2195 {
2196 FreePool(ObjectNameInfoPtr);
2197 }
2198
2199 if (FileNameInfo)
2200 {
2201 FreePool(FileNameInfo);
2202 }
2203
2204 if (FOReferenced)
2205 {
2206 ObDereferenceObject(FileObject);
2207 }
2208
2209 return Status;
2210 }
2211
2212 /*
2213 * @implemented
2214 */
2215 NTSTATUS
MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp,IN NTSTATUS LockStatus)2216 MountMgrVolumeMountPointCreated(IN PDEVICE_EXTENSION DeviceExtension,
2217 IN PIRP Irp,
2218 IN NTSTATUS LockStatus)
2219 {
2220 LONG Offset;
2221 BOOLEAN Found;
2222 NTSTATUS Status;
2223 HANDLE RemoteDatabase;
2224 PMOUNTDEV_UNIQUE_ID UniqueId;
2225 PDATABASE_ENTRY DatabaseEntry;
2226 PASSOCIATED_DEVICE_ENTRY AssociatedEntry;
2227 PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation;
2228 UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName;
2229
2230 /* Initialize string */
2231 LinkTarget.Length = 0;
2232 LinkTarget.MaximumLength = 0xC8;
2233 LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength);
2234 if (LinkTarget.Buffer == NULL)
2235 {
2236 return STATUS_INSUFFICIENT_RESOURCES;
2237 }
2238
2239 /* If the mount point was created, then, it changed!
2240 * Also use it to query some information
2241 */
2242 Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName);
2243 /* Pending means DB are under synchronization, bail out */
2244 if (Status == STATUS_PENDING)
2245 {
2246 FreePool(LinkTarget.Buffer);
2247 FreePool(SourceDeviceName.Buffer);
2248 FreePool(SourceSymbolicName.Buffer);
2249 return STATUS_SUCCESS;
2250 }
2251 else if (!NT_SUCCESS(Status))
2252 {
2253 FreePool(LinkTarget.Buffer);
2254 return Status;
2255 }
2256
2257 /* Query the device information */
2258 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation);
2259 if (!NT_SUCCESS(Status))
2260 {
2261 /* If it failed, first try to get volume name */
2262 Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName);
2263 if (!NT_SUCCESS(Status))
2264 {
2265 /* Then, try to read the symlink */
2266 Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget);
2267 if (!NT_SUCCESS(Status))
2268 {
2269 FreePool(LinkTarget.Buffer);
2270 FreePool(SourceDeviceName.Buffer);
2271 FreePool(SourceSymbolicName.Buffer);
2272 return Status;
2273 }
2274 }
2275 else
2276 {
2277 FreePool(VolumeName.Buffer);
2278 }
2279
2280 FreePool(SourceDeviceName.Buffer);
2281
2282 SourceDeviceName.Length = LinkTarget.Length;
2283 SourceDeviceName.MaximumLength = LinkTarget.MaximumLength;
2284 SourceDeviceName.Buffer = LinkTarget.Buffer;
2285
2286 /* Now that we have the correct source, reattempt to query information */
2287 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation);
2288 if (!NT_SUCCESS(Status))
2289 {
2290 FreePool(SourceDeviceName.Buffer);
2291 FreePool(SourceSymbolicName.Buffer);
2292 return Status;
2293 }
2294 }
2295
2296 FreePool(SourceDeviceName.Buffer);
2297
2298 /* Get information about target device */
2299 Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation);
2300 if (!NT_SUCCESS(Status))
2301 {
2302 FreePool(SourceSymbolicName.Buffer);
2303 return Status;
2304 }
2305
2306 /* Notify if not disabled */
2307 if (!TargetDeviceInformation->SkipNotifications)
2308 {
2309 PostOnlineNotification(DeviceExtension, &TargetDeviceInformation->SymbolicName);
2310 }
2311
2312 /* Open the remote database */
2313 RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE);
2314 if (RemoteDatabase == 0)
2315 {
2316 FreePool(SourceSymbolicName.Buffer);
2317 return STATUS_INSUFFICIENT_RESOURCES;
2318 }
2319
2320 /* Browse all the entries */
2321 Offset = 0;
2322 Found = FALSE;
2323 for (;;)
2324 {
2325 DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset);
2326 if (DatabaseEntry == NULL)
2327 {
2328 break;
2329 }
2330
2331 /* Try to find ourselves */
2332 DbName.MaximumLength = DatabaseEntry->SymbolicNameLength;
2333 DbName.Length = DbName.MaximumLength;
2334 DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
2335 if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE))
2336 {
2337 /* Reference ourselves and update the entry */
2338 ++DatabaseEntry->EntryReferences;
2339 Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry);
2340 FreePool(DatabaseEntry);
2341 Found = TRUE;
2342 break;
2343 }
2344
2345 Offset += DatabaseEntry->EntrySize;
2346 FreePool(DatabaseEntry);
2347 }
2348
2349 /* We couldn't find ourselves, we'll have to add ourselves */
2350 if (!Found)
2351 {
2352 ULONG EntrySize;
2353 PUNIQUE_ID_REPLICATE UniqueIdReplicate;
2354
2355 /* Query the device unique ID */
2356 Status = QueryDeviceInformation(&TargetVolumeName, NULL, &UniqueId, NULL, NULL, NULL, NULL, NULL);
2357 if (!NT_SUCCESS(Status))
2358 {
2359 FreePool(SourceSymbolicName.Buffer);
2360 CloseRemoteDatabase(RemoteDatabase);
2361 return Status;
2362 }
2363
2364 /* Allocate a database entry */
2365 EntrySize = UniqueId->UniqueIdLength + TargetVolumeName.Length + sizeof(DATABASE_ENTRY);
2366 DatabaseEntry = AllocatePool(EntrySize);
2367 if (DatabaseEntry == NULL)
2368 {
2369 FreePool(UniqueId);
2370 FreePool(SourceSymbolicName.Buffer);
2371 CloseRemoteDatabase(RemoteDatabase);
2372 return STATUS_INSUFFICIENT_RESOURCES;
2373 }
2374
2375 /* Fill it in */
2376 DatabaseEntry->EntrySize = EntrySize;
2377 DatabaseEntry->EntryReferences = 1;
2378 DatabaseEntry->SymbolicNameOffset = sizeof(DATABASE_ENTRY);
2379 DatabaseEntry->SymbolicNameLength = TargetVolumeName.Length;
2380 DatabaseEntry->UniqueIdOffset = TargetVolumeName.Length + sizeof(DATABASE_ENTRY);
2381 DatabaseEntry->UniqueIdLength = UniqueId->UniqueIdLength;
2382 RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + sizeof(DATABASE_ENTRY)), TargetVolumeName.Buffer, DatabaseEntry->SymbolicNameLength);
2383 RtlCopyMemory((PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset), UniqueId->UniqueId, UniqueId->UniqueIdLength);
2384
2385 /* And write it down */
2386 Status = AddRemoteDatabaseEntry(RemoteDatabase, DatabaseEntry);
2387 FreePool(DatabaseEntry);
2388 if (!NT_SUCCESS(Status))
2389 {
2390 FreePool(UniqueId);
2391 FreePool(SourceSymbolicName.Buffer);
2392 CloseRemoteDatabase(RemoteDatabase);
2393 return Status;
2394 }
2395
2396 /* And now, allocate an Unique ID item */
2397 UniqueIdReplicate = AllocatePool(sizeof(UNIQUE_ID_REPLICATE));
2398 if (UniqueIdReplicate == NULL)
2399 {
2400 FreePool(UniqueId);
2401 FreePool(SourceSymbolicName.Buffer);
2402 CloseRemoteDatabase(RemoteDatabase);
2403 return Status;
2404 }
2405
2406 /* To associate it with the device */
2407 UniqueIdReplicate->UniqueId = UniqueId;
2408 InsertTailList(&DeviceInformation->ReplicatedUniqueIdsListHead, &UniqueIdReplicate->ReplicatedUniqueIdsListEntry);
2409 }
2410
2411 /* We're done with the remote database */
2412 CloseRemoteDatabase(RemoteDatabase);
2413
2414 /* Check we were find writing the entry */
2415 if (!NT_SUCCESS(Status))
2416 {
2417 FreePool(SourceSymbolicName.Buffer);
2418 return Status;
2419 }
2420
2421 /* This is the end, allocate an associated entry */
2422 AssociatedEntry = AllocatePool(sizeof(ASSOCIATED_DEVICE_ENTRY));
2423 if (AssociatedEntry == NULL)
2424 {
2425 FreePool(SourceSymbolicName.Buffer);
2426 return STATUS_INSUFFICIENT_RESOURCES;
2427 }
2428
2429 /* Initialize its source name string */
2430 AssociatedEntry->String.Length = SourceSymbolicName.Length;
2431 AssociatedEntry->String.MaximumLength = AssociatedEntry->String.Length + sizeof(UNICODE_NULL);
2432 AssociatedEntry->String.Buffer = AllocatePool(AssociatedEntry->String.MaximumLength);
2433 if (AssociatedEntry->String.Buffer == NULL)
2434 {
2435 FreePool(AssociatedEntry);
2436 FreePool(SourceSymbolicName.Buffer);
2437 return STATUS_INSUFFICIENT_RESOURCES;
2438 }
2439
2440 /* Copy data & insert in list */
2441 RtlCopyMemory(AssociatedEntry->String.Buffer, SourceSymbolicName.Buffer, SourceSymbolicName.Length);
2442 AssociatedEntry->String.Buffer[SourceSymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
2443 AssociatedEntry->DeviceInformation = DeviceInformation;
2444 InsertTailList(&TargetDeviceInformation->AssociatedDevicesHead, &AssociatedEntry->AssociatedDevicesEntry);
2445
2446 /* We're done! */
2447 FreePool(SourceSymbolicName.Buffer);
2448 return STATUS_SUCCESS;
2449 }
2450
2451 /*
2452 * @implemented
2453 */
2454 NTSTATUS
MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension,IN PIRP Irp,IN NTSTATUS LockStatus)2455 MountMgrVolumeMountPointDeleted(IN PDEVICE_EXTENSION DeviceExtension,
2456 IN PIRP Irp,
2457 IN NTSTATUS LockStatus)
2458 {
2459 LONG Offset;
2460 NTSTATUS Status;
2461 PLIST_ENTRY Entry;
2462 HANDLE RemoteDatabase;
2463 PDATABASE_ENTRY DatabaseEntry;
2464 PUNIQUE_ID_REPLICATE UniqueIdReplicate;
2465 PASSOCIATED_DEVICE_ENTRY AssociatedEntry;
2466 PDEVICE_INFORMATION DeviceInformation, TargetDeviceInformation;
2467 UNICODE_STRING LinkTarget, SourceDeviceName, SourceSymbolicName, TargetVolumeName, VolumeName, DbName;
2468
2469 /* Initialize string */
2470 LinkTarget.Length = 0;
2471 LinkTarget.MaximumLength = 0xC8;
2472 LinkTarget.Buffer = AllocatePool(LinkTarget.MaximumLength);
2473 if (LinkTarget.Buffer == NULL)
2474 {
2475 return STATUS_INSUFFICIENT_RESOURCES;
2476 }
2477
2478 /* If the mount point was deleted, then, it changed!
2479 * Also use it to query some information
2480 */
2481 Status = MountMgrVolumeMountPointChanged(DeviceExtension, Irp, LockStatus, &SourceDeviceName, &SourceSymbolicName, &TargetVolumeName);
2482 /* Pending means DB are under synchronization, bail out */
2483 if (Status == STATUS_PENDING)
2484 {
2485 FreePool(LinkTarget.Buffer);
2486 FreePool(SourceDeviceName.Buffer);
2487 FreePool(SourceSymbolicName.Buffer);
2488 return STATUS_SUCCESS;
2489 }
2490 else if (!NT_SUCCESS(Status))
2491 {
2492 FreePool(LinkTarget.Buffer);
2493 return Status;
2494 }
2495
2496 /* Query the device information */
2497 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation);
2498 if (!NT_SUCCESS(Status))
2499 {
2500 /* If it failed, first try to get volume name */
2501 Status = QueryVolumeName(0, NULL, &SourceDeviceName, &LinkTarget, &VolumeName);
2502 if (!NT_SUCCESS(Status))
2503 {
2504 /* Then, try to read the symlink */
2505 Status = MountMgrQuerySymbolicLink(&SourceDeviceName, &LinkTarget);
2506 if (!NT_SUCCESS(Status))
2507 {
2508 FreePool(LinkTarget.Buffer);
2509 FreePool(SourceDeviceName.Buffer);
2510 FreePool(SourceSymbolicName.Buffer);
2511 return Status;
2512 }
2513 }
2514 else
2515 {
2516 FreePool(VolumeName.Buffer);
2517 }
2518
2519 FreePool(SourceDeviceName.Buffer);
2520
2521 SourceDeviceName.Length = LinkTarget.Length;
2522 SourceDeviceName.MaximumLength = LinkTarget.MaximumLength;
2523 SourceDeviceName.Buffer = LinkTarget.Buffer;
2524
2525 /* Now that we have the correct source, reattempt to query information */
2526 Status = FindDeviceInfo(DeviceExtension, &SourceDeviceName, FALSE, &DeviceInformation);
2527 if (!NT_SUCCESS(Status))
2528 {
2529 FreePool(SourceDeviceName.Buffer);
2530 FreePool(SourceSymbolicName.Buffer);
2531 return Status;
2532 }
2533 }
2534
2535 FreePool(SourceDeviceName.Buffer);
2536
2537 /* Get information about target device */
2538 Status = FindDeviceInfo(DeviceExtension, &TargetVolumeName, FALSE, &TargetDeviceInformation);
2539 if (!NT_SUCCESS(Status))
2540 {
2541 FreePool(SourceSymbolicName.Buffer);
2542 return Status;
2543 }
2544
2545 /* Open the remote database */
2546 RemoteDatabase = OpenRemoteDatabase(DeviceInformation, TRUE);
2547 if (RemoteDatabase == 0)
2548 {
2549 FreePool(SourceSymbolicName.Buffer);
2550 return STATUS_INSUFFICIENT_RESOURCES;
2551 }
2552
2553 /* Browse all the entries */
2554 Offset = 0;
2555 for (;;)
2556 {
2557 DatabaseEntry = GetRemoteDatabaseEntry(RemoteDatabase, Offset);
2558 if (DatabaseEntry == NULL)
2559 {
2560 /* We didn't find ourselves, that's infortunate! */
2561 FreePool(SourceSymbolicName.Buffer);
2562 CloseRemoteDatabase(RemoteDatabase);
2563 return STATUS_INVALID_PARAMETER;
2564 }
2565
2566 /* Try to find ourselves */
2567 DbName.MaximumLength = DatabaseEntry->SymbolicNameLength;
2568 DbName.Length = DbName.MaximumLength;
2569 DbName.Buffer = (PWSTR)((ULONG_PTR)DatabaseEntry + DatabaseEntry->SymbolicNameOffset);
2570 if (RtlEqualUnicodeString(&TargetVolumeName, &DbName, TRUE))
2571 {
2572 break;
2573 }
2574
2575 Offset += DatabaseEntry->EntrySize;
2576 FreePool(DatabaseEntry);
2577 }
2578
2579 /* Dereference ourselves */
2580 DatabaseEntry->EntryReferences--;
2581 if (DatabaseEntry->EntryReferences == 0)
2582 {
2583 /* If we're still referenced, just update the entry */
2584 Status = WriteRemoteDatabaseEntry(RemoteDatabase, Offset, DatabaseEntry);
2585 }
2586 else
2587 {
2588 /* Otherwise, delete the entry */
2589 Status = DeleteRemoteDatabaseEntry(RemoteDatabase, Offset);
2590 if (!NT_SUCCESS(Status))
2591 {
2592 FreePool(DatabaseEntry);
2593 FreePool(SourceSymbolicName.Buffer);
2594 CloseRemoteDatabase(RemoteDatabase);
2595 return Status;
2596 }
2597
2598 /* Also, delete our unique ID replicated record */
2599 for (Entry = DeviceInformation->ReplicatedUniqueIdsListHead.Flink;
2600 Entry != &DeviceInformation->ReplicatedUniqueIdsListHead;
2601 Entry = Entry->Flink)
2602 {
2603 UniqueIdReplicate = CONTAINING_RECORD(Entry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
2604
2605 if (UniqueIdReplicate->UniqueId->UniqueIdLength == DatabaseEntry->UniqueIdLength &&
2606 RtlCompareMemory(UniqueIdReplicate->UniqueId->UniqueId,
2607 (PVOID)((ULONG_PTR)DatabaseEntry + DatabaseEntry->UniqueIdOffset),
2608 DatabaseEntry->UniqueIdLength) == DatabaseEntry->UniqueIdLength)
2609 {
2610 break;
2611 }
2612 }
2613
2614 /* It has to exist! */
2615 if (Entry == &DeviceInformation->ReplicatedUniqueIdsListHead)
2616 {
2617 FreePool(DatabaseEntry);
2618 FreePool(SourceSymbolicName.Buffer);
2619 CloseRemoteDatabase(RemoteDatabase);
2620 return STATUS_UNSUCCESSFUL;
2621 }
2622
2623 /* Remove it and free it */
2624 RemoveEntryList(&UniqueIdReplicate->ReplicatedUniqueIdsListEntry);
2625 FreePool(UniqueIdReplicate->UniqueId);
2626 FreePool(UniqueIdReplicate);
2627 }
2628
2629 /* We're done with the remote database */
2630 FreePool(DatabaseEntry);
2631 CloseRemoteDatabase(RemoteDatabase);
2632
2633 /* Check write operation succeed */
2634 if (!NT_SUCCESS(Status))
2635 {
2636 FreePool(SourceSymbolicName.Buffer);
2637 return Status;
2638 }
2639
2640 /* Try to find our associated device entry */
2641 for (Entry = TargetDeviceInformation->AssociatedDevicesHead.Flink;
2642 Entry != &TargetDeviceInformation->AssociatedDevicesHead;
2643 Entry = Entry->Flink)
2644 {
2645 AssociatedEntry = CONTAINING_RECORD(Entry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
2646
2647 /* If found, delete it */
2648 if (AssociatedEntry->DeviceInformation == DeviceInformation &&
2649 RtlEqualUnicodeString(&AssociatedEntry->String, &SourceSymbolicName, TRUE))
2650 {
2651 RemoveEntryList(&AssociatedEntry->AssociatedDevicesEntry);
2652 FreePool(AssociatedEntry->String.Buffer);
2653 FreePool(AssociatedEntry);
2654 break;
2655 }
2656 }
2657
2658 /* We're done! */
2659 FreePool(SourceSymbolicName.Buffer);
2660 return STATUS_SUCCESS;
2661 }
2662
2663 /*
2664 * @implemented
2665 */
2666 NTSTATUS
2667 NTAPI
MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)2668 MountMgrDeviceControl(IN PDEVICE_OBJECT DeviceObject,
2669 IN PIRP Irp)
2670 {
2671 PIO_STACK_LOCATION Stack;
2672 NTSTATUS Status, LockStatus;
2673 PDEVICE_EXTENSION DeviceExtension;
2674
2675 Stack = IoGetCurrentIrpStackLocation(Irp);
2676 DeviceExtension = DeviceObject->DeviceExtension;
2677
2678 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
2679
2680 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
2681 {
2682 case IOCTL_MOUNTMGR_CREATE_POINT:
2683 Status = MountMgrCreatePoint(DeviceExtension, Irp);
2684 break;
2685
2686 case IOCTL_MOUNTMGR_DELETE_POINTS:
2687 Status = MountMgrDeletePoints(DeviceExtension, Irp);
2688 break;
2689
2690 case IOCTL_MOUNTMGR_QUERY_POINTS:
2691 Status = MountMgrQueryPoints(DeviceExtension, Irp);
2692 break;
2693
2694 case IOCTL_MOUNTMGR_DELETE_POINTS_DBONLY:
2695 Status = MountMgrDeletePointsDbOnly(DeviceExtension, Irp);
2696 break;
2697
2698 case IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER:
2699 Status = MountMgrNextDriveLetter(DeviceExtension, Irp);
2700 break;
2701
2702 case IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS:
2703 // NOTE: On Win7+, this is handled during driver re-initialization.
2704 DeviceExtension->AutomaticDriveLetter = TRUE;
2705 MountMgrAssignDriveLetters(DeviceExtension);
2706 ReconcileAllDatabasesWithMaster(DeviceExtension);
2707 WaitForOnlinesToComplete(DeviceExtension);
2708 Status = STATUS_SUCCESS;
2709 break;
2710
2711 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED:
2712 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
2713
2714 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension);
2715 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
2716 Status = MountMgrVolumeMountPointCreated(DeviceExtension, Irp, LockStatus);
2717 if (NT_SUCCESS(LockStatus))
2718 {
2719 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
2720 }
2721
2722 break;
2723
2724 case IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED:
2725 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
2726
2727 LockStatus = WaitForRemoteDatabaseSemaphore(DeviceExtension);
2728 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
2729 Status = MountMgrVolumeMountPointDeleted(DeviceExtension, Irp, LockStatus);
2730 if (NT_SUCCESS(LockStatus))
2731 {
2732 ReleaseRemoteDatabaseSemaphore(DeviceExtension);
2733 }
2734
2735 break;
2736
2737 case IOCTL_MOUNTMGR_CHANGE_NOTIFY:
2738 Status = MountMgrChangeNotify(DeviceExtension, Irp);
2739 break;
2740
2741 case IOCTL_MOUNTMGR_KEEP_LINKS_WHEN_OFFLINE:
2742 Status = MountMgrKeepLinksWhenOffline(DeviceExtension, Irp);
2743 break;
2744
2745 case IOCTL_MOUNTMGR_CHECK_UNPROCESSED_VOLUMES:
2746 Status = MountMgrCheckUnprocessedVolumes(DeviceExtension, Irp);
2747 goto Complete;
2748
2749 case IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION:
2750 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
2751 Status = MountMgrVolumeArrivalNotification(DeviceExtension, Irp);
2752 goto Complete;
2753
2754 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATH:
2755 Status = MountMgrQueryDosVolumePath(DeviceExtension, Irp);
2756 break;
2757
2758 case IOCTL_MOUNTMGR_QUERY_DOS_VOLUME_PATHS:
2759 Status = MountMgrQueryDosVolumePaths(DeviceExtension, Irp);
2760 break;
2761
2762 case IOCTL_MOUNTMGR_SCRUB_REGISTRY:
2763 Status = MountMgrScrubRegistry(DeviceExtension);
2764 break;
2765
2766 case IOCTL_MOUNTMGR_QUERY_AUTO_MOUNT:
2767 Status = MountMgrQueryAutoMount(DeviceExtension, Irp);
2768 break;
2769
2770 case IOCTL_MOUNTMGR_SET_AUTO_MOUNT:
2771 Status = MountMgrSetAutoMount(DeviceExtension, Irp);
2772 break;
2773
2774 default:
2775 Status = STATUS_INVALID_DEVICE_REQUEST;
2776 }
2777
2778 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
2779
2780 if (Status != STATUS_PENDING)
2781 {
2782 goto Complete;
2783 }
2784
2785 return Status;
2786
2787 Complete:
2788 Irp->IoStatus.Status = Status;
2789 IoCompleteRequest(Irp, IO_NO_INCREMENT);
2790
2791 return Status;
2792 }
2793