[NTOS] Remove forgotten assert, see CORE-14128.
[reactos.git] / drivers / filters / mountmgr / mountmgr.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2011 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/mountmgr.c
22 * PURPOSE: Mount Manager
23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org)
24 * Alex Ionescu (alex.ionescu@reactos.org)
25 */
26
27 #include "mntmgr.h"
28
29 #define NDEBUG
30 #include <debug.h>
31
32 #if defined(ALLOC_PRAGMA)
33 #pragma alloc_text(INIT, MountmgrReadNoAutoMount)
34 #pragma alloc_text(INIT, DriverEntry)
35 #endif
36
37 /* FIXME */
38 GUID MountedDevicesGuid = {0x53F5630D, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}};
39
40 PDEVICE_OBJECT gdeviceObject;
41 KEVENT UnloadEvent;
42 LONG Unloading;
43
44 static const WCHAR Cunc[] = L"\\??\\C:";
45
46 /*
47 * @implemented
48 */
49 BOOLEAN
50 IsOffline(PUNICODE_STRING SymbolicName)
51 {
52 NTSTATUS Status;
53 ULONG IsOffline, Default;
54 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
55
56 /* Prepare to look in the registry to see if
57 * given volume is offline
58 */
59 RtlZeroMemory(QueryTable, sizeof(QueryTable));
60 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
61 QueryTable[0].Name = SymbolicName->Buffer;
62 QueryTable[0].EntryContext = &IsOffline;
63 QueryTable[0].DefaultType = REG_DWORD;
64 QueryTable[0].DefaultLength = sizeof(ULONG);
65 QueryTable[0].DefaultData = &Default;
66
67 Default = 0;
68
69 /* Query status */
70 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
71 OfflinePath,
72 QueryTable,
73 NULL,
74 NULL);
75 if (!NT_SUCCESS(Status))
76 {
77 IsOffline = 0;
78 }
79
80 return (IsOffline != 0);
81 }
82
83 /*
84 * @implemented
85 */
86 BOOLEAN
87 HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation)
88 {
89 PLIST_ENTRY NextEntry;
90 PSYMLINK_INFORMATION SymlinkInfo;
91
92 /* To have a drive letter, a device must have symbolic links */
93 if (IsListEmpty(&(DeviceInformation->SymbolicLinksListHead)))
94 {
95 return FALSE;
96 }
97
98 /* Browse all the links untill a drive letter is found */
99 NextEntry = &(DeviceInformation->SymbolicLinksListHead);
100 do
101 {
102 SymlinkInfo = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
103
104 if (SymlinkInfo->Online)
105 {
106 if (IsDriveLetter(&(SymlinkInfo->Name)))
107 {
108 return TRUE;
109 }
110 }
111
112 NextEntry = NextEntry->Flink;
113 } while (NextEntry != &(DeviceInformation->SymbolicLinksListHead));
114
115 return FALSE;
116 }
117
118 /*
119 * @implemented
120 */
121 NTSTATUS
122 CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter,
123 IN PUNICODE_STRING DeviceName,
124 IN UCHAR Letter,
125 IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL)
126 {
127 NTSTATUS Status = STATUS_UNSUCCESSFUL;
128
129 /* Allocate a big enough buffer to contain the symbolic link */
130 DriveLetter->MaximumLength = DosDevices.Length + 3 * sizeof(WCHAR);
131 DriveLetter->Buffer = AllocatePool(DriveLetter->MaximumLength);
132 if (!DriveLetter->Buffer)
133 {
134 return STATUS_INSUFFICIENT_RESOURCES;
135 }
136
137 /* Copy prefix */
138 RtlCopyUnicodeString(DriveLetter, &DosDevices);
139
140 /* Update string to reflect real contents */
141 DriveLetter->Length = DosDevices.Length + 2 * sizeof(WCHAR);
142 DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR) + 2] = UNICODE_NULL;
143 DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR) + 1] = L':';
144
145 /* If caller wants a no drive entry */
146 if (Letter == (UCHAR)-1)
147 {
148 /* Then, create a no letter entry */
149 CreateNoDriveLetterEntry(UniqueId);
150 FreePool(DriveLetter->Buffer);
151 return STATUS_UNSUCCESSFUL;
152 }
153 else if (Letter)
154 {
155 /* Use the letter given by the caller */
156 DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR)] = (WCHAR)Letter;
157 Status = GlobalCreateSymbolicLink(DriveLetter, DeviceName);
158 if (NT_SUCCESS(Status))
159 {
160 return Status;
161 }
162 }
163
164 /* If caller didn't provide a letter, let's find one for him */
165
166 if (RtlPrefixUnicodeString(&DeviceFloppy, DeviceName, TRUE))
167 {
168 /* If the device is a floppy, start with letter A */
169 Letter = 'A';
170 }
171 else if (RtlPrefixUnicodeString(&DeviceCdRom, DeviceName, TRUE))
172 {
173 /* If the device is a CD-ROM, start with letter D */
174 Letter = 'D';
175 }
176 else
177 {
178 /* Finally, if it's a disk, use C */
179 Letter = 'C';
180 }
181
182 /* Try to affect a letter (up to Z, ofc) until it's possible */
183 for (; Letter <= 'Z'; Letter++)
184 {
185 DriveLetter->Buffer[DosDevices.Length / sizeof(WCHAR)] = (WCHAR)Letter;
186 Status = GlobalCreateSymbolicLink(DriveLetter, DeviceName);
187 if (NT_SUCCESS(Status))
188 {
189 DPRINT("Assigned drive %c: to %wZ\n", Letter, DeviceName);
190 return Status;
191 }
192 }
193
194 /* We failed to allocate a letter */
195 FreePool(DriveLetter->Buffer);
196 DPRINT("Failed to create a drive letter for %wZ\n", DeviceName);
197 return Status;
198 }
199
200 /*
201 * @implemented
202 */
203 NTSTATUS
204 QueryDeviceInformation(IN PUNICODE_STRING SymbolicName,
205 OUT PUNICODE_STRING DeviceName OPTIONAL,
206 OUT PMOUNTDEV_UNIQUE_ID * UniqueId OPTIONAL,
207 OUT PBOOLEAN Removable OPTIONAL,
208 OUT PBOOLEAN GptDriveLetter OPTIONAL,
209 OUT PBOOLEAN HasGuid OPTIONAL,
210 IN OUT LPGUID StableGuid OPTIONAL,
211 OUT PBOOLEAN Valid OPTIONAL)
212 {
213 PIRP Irp;
214 USHORT Size;
215 KEVENT Event;
216 NTSTATUS Status;
217 BOOLEAN IsRemovable;
218 PMOUNTDEV_NAME Name;
219 PMOUNTDEV_UNIQUE_ID Id;
220 PFILE_OBJECT FileObject;
221 PIO_STACK_LOCATION Stack;
222 PDEVICE_OBJECT DeviceObject;
223 IO_STATUS_BLOCK IoStatusBlock;
224 PARTITION_INFORMATION_EX PartitionInfo;
225 STORAGE_DEVICE_NUMBER StorageDeviceNumber;
226 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes;
227
228 /* Get device associated with the symbolic name */
229 Status = IoGetDeviceObjectPointer(SymbolicName,
230 FILE_READ_ATTRIBUTES,
231 &FileObject,
232 &DeviceObject);
233 if (!NT_SUCCESS(Status))
234 {
235 return Status;
236 }
237
238 /* The associate FO can't have a file name */
239 if (FileObject->FileName.Length)
240 {
241 ObDereferenceObject(FileObject);
242 return STATUS_OBJECT_NAME_NOT_FOUND;
243 }
244
245 /* Check if it's removable & return to the user (if asked to) */
246 IsRemovable = (FileObject->DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA);
247 if (Removable)
248 {
249 *Removable = IsRemovable;
250 }
251
252 /* Get the attached device */
253 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
254
255 /* If we've been asked for a GPT drive letter */
256 if (GptDriveLetter)
257 {
258 /* Consider it has one */
259 *GptDriveLetter = TRUE;
260
261 if (!IsRemovable)
262 {
263 /* Query the GPT attributes */
264 KeInitializeEvent(&Event, NotificationEvent, FALSE);
265 Irp = IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES,
266 DeviceObject,
267 NULL,
268 0,
269 &GptAttributes,
270 sizeof(GptAttributes),
271 FALSE,
272 &Event,
273 &IoStatusBlock);
274 if (!Irp)
275 {
276 ObDereferenceObject(DeviceObject);
277 ObDereferenceObject(FileObject);
278 return STATUS_INSUFFICIENT_RESOURCES;
279 }
280
281 Status = IoCallDriver(DeviceObject, Irp);
282 if (Status == STATUS_PENDING)
283 {
284 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
285 Status = IoStatusBlock.Status;
286 }
287
288 /* In case of failure, don't fail, that's no vital */
289 if (!NT_SUCCESS(Status))
290 {
291 Status = STATUS_SUCCESS;
292 }
293 /* Check if it has a drive letter */
294 else if (!(GptAttributes.GptAttributes &
295 GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER))
296 {
297 *GptDriveLetter = FALSE;
298 }
299 }
300 }
301
302 /* If caller wants to know if there's valid contents */
303 if (Valid)
304 {
305 /* Suppose it's not OK */
306 *Valid = FALSE;
307
308 if (!IsRemovable)
309 {
310 /* Query partitions information */
311 KeInitializeEvent(&Event, NotificationEvent, FALSE);
312 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX,
313 DeviceObject,
314 NULL,
315 0,
316 &PartitionInfo,
317 sizeof(PartitionInfo),
318 FALSE,
319 &Event,
320 &IoStatusBlock);
321 if (!Irp)
322 {
323 ObDereferenceObject(DeviceObject);
324 ObDereferenceObject(FileObject);
325 return STATUS_INSUFFICIENT_RESOURCES;
326 }
327
328 Status = IoCallDriver(DeviceObject, Irp);
329 if (Status == STATUS_PENDING)
330 {
331 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
332 Status = IoStatusBlock.Status;
333 }
334
335 /* Once again here, failure isn't major */
336 if (!NT_SUCCESS(Status))
337 {
338 Status = STATUS_SUCCESS;
339 }
340 /* Verify we know something in */
341 else if (PartitionInfo.PartitionStyle == PARTITION_STYLE_MBR &&
342 IsRecognizedPartition(PartitionInfo.Mbr.PartitionType))
343 {
344 *Valid = TRUE;
345 }
346
347 /* It looks correct, ensure it is & query device number */
348 if (*Valid)
349 {
350 KeInitializeEvent(&Event, NotificationEvent, FALSE);
351 Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
352 DeviceObject,
353 NULL,
354 0,
355 &StorageDeviceNumber,
356 sizeof(StorageDeviceNumber),
357 FALSE,
358 &Event,
359 &IoStatusBlock);
360 if (!Irp)
361 {
362 ObDereferenceObject(DeviceObject);
363 ObDereferenceObject(FileObject);
364 return STATUS_INSUFFICIENT_RESOURCES;
365 }
366
367 Status = IoCallDriver(DeviceObject, Irp);
368 if (Status == STATUS_PENDING)
369 {
370 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
371 Status = IoStatusBlock.Status;
372 }
373
374 if (!NT_SUCCESS(Status))
375 {
376 Status = STATUS_SUCCESS;
377 }
378 else
379 {
380 *Valid = FALSE;
381 }
382 }
383 }
384 }
385
386 /* If caller needs device name */
387 if (DeviceName)
388 {
389 /* Allocate a buffer just to request length */
390 Name = AllocatePool(sizeof(MOUNTDEV_NAME));
391 if (!Name)
392 {
393 ObDereferenceObject(DeviceObject);
394 ObDereferenceObject(FileObject);
395 return STATUS_INSUFFICIENT_RESOURCES;
396 }
397
398 /* Query device name */
399 KeInitializeEvent(&Event, NotificationEvent, FALSE);
400 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
401 DeviceObject,
402 NULL,
403 0,
404 Name,
405 sizeof(MOUNTDEV_NAME),
406 FALSE,
407 &Event,
408 &IoStatusBlock);
409 if (!Irp)
410 {
411 FreePool(Name);
412 ObDereferenceObject(DeviceObject);
413 ObDereferenceObject(FileObject);
414 return STATUS_INSUFFICIENT_RESOURCES;
415 }
416
417 Stack = IoGetNextIrpStackLocation(Irp);
418 Stack->FileObject = FileObject;
419
420 Status = IoCallDriver(DeviceObject, Irp);
421 if (Status == STATUS_PENDING)
422 {
423 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
424 Status = IoStatusBlock.Status;
425 }
426
427 /* Now, we've got the correct length */
428 if (Status == STATUS_BUFFER_OVERFLOW)
429 {
430 Size = Name->NameLength + sizeof(MOUNTDEV_NAME);
431
432 FreePool(Name);
433
434 /* Allocate proper size */
435 Name = AllocatePool(Size);
436 if (!Name)
437 {
438 ObDereferenceObject(DeviceObject);
439 ObDereferenceObject(FileObject);
440 return STATUS_INSUFFICIENT_RESOURCES;
441 }
442
443 /* And query name (for real that time) */
444 KeInitializeEvent(&Event, NotificationEvent, FALSE);
445 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
446 DeviceObject,
447 NULL,
448 0,
449 Name,
450 Size,
451 FALSE,
452 &Event,
453 &IoStatusBlock);
454 if (!Irp)
455 {
456 FreePool(Name);
457 ObDereferenceObject(DeviceObject);
458 ObDereferenceObject(FileObject);
459 return STATUS_INSUFFICIENT_RESOURCES;
460 }
461
462 Stack = IoGetNextIrpStackLocation(Irp);
463 Stack->FileObject = FileObject;
464
465 Status = IoCallDriver(DeviceObject, Irp);
466 if (Status == STATUS_PENDING)
467 {
468 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
469 Status = IoStatusBlock.Status;
470 }
471 }
472
473 /* Here we can't fail and assume default value */
474 if (!NT_SUCCESS(Status))
475 {
476 FreePool(Name);
477 ObDereferenceObject(DeviceObject);
478 ObDereferenceObject(FileObject);
479 return Status;
480 }
481
482 /* Copy back found name to the caller */
483 DeviceName->Length = Name->NameLength;
484 DeviceName->MaximumLength = Name->NameLength + sizeof(WCHAR);
485 DeviceName->Buffer = AllocatePool(DeviceName->MaximumLength);
486 if (!DeviceName->Buffer)
487 {
488 FreePool(Name);
489 ObDereferenceObject(DeviceObject);
490 ObDereferenceObject(FileObject);
491 return STATUS_INSUFFICIENT_RESOURCES;
492 }
493
494 RtlCopyMemory(DeviceName->Buffer, Name->Name, Name->NameLength);
495 DeviceName->Buffer[Name->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
496 FreePool(Name);
497 }
498
499 /* If caller wants device unique ID */
500 if (UniqueId)
501 {
502 /* Prepare buffer to probe length */
503 Id = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID));
504 if (!Id)
505 {
506 ObDereferenceObject(DeviceObject);
507 ObDereferenceObject(FileObject);
508 return STATUS_INSUFFICIENT_RESOURCES;
509 }
510
511 /* Query unique ID length */
512 KeInitializeEvent(&Event, NotificationEvent, FALSE);
513 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID,
514 DeviceObject,
515 NULL,
516 0,
517 Id,
518 sizeof(MOUNTDEV_UNIQUE_ID),
519 FALSE,
520 &Event,
521 &IoStatusBlock);
522 if (!Irp)
523 {
524 FreePool(Id);
525 ObDereferenceObject(DeviceObject);
526 ObDereferenceObject(FileObject);
527 return STATUS_INSUFFICIENT_RESOURCES;
528 }
529
530 Stack = IoGetNextIrpStackLocation(Irp);
531 Stack->FileObject = FileObject;
532
533 Status = IoCallDriver(DeviceObject, Irp);
534 if (Status == STATUS_PENDING)
535 {
536 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
537 Status = IoStatusBlock.Status;
538 }
539
540 /* Retry with appropriate length */
541 if (Status == STATUS_BUFFER_OVERFLOW)
542 {
543 Size = Id->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID);
544
545 FreePool(Id);
546
547 /* Allocate the correct buffer */
548 Id = AllocatePool(Size);
549 if (!Id)
550 {
551 ObDereferenceObject(DeviceObject);
552 ObDereferenceObject(FileObject);
553 return STATUS_INSUFFICIENT_RESOURCES;
554 }
555
556 /* Query unique ID */
557 KeInitializeEvent(&Event, NotificationEvent, FALSE);
558 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID,
559 DeviceObject,
560 NULL,
561 0,
562 Id,
563 Size,
564 FALSE,
565 &Event,
566 &IoStatusBlock);
567 if (!Irp)
568 {
569 FreePool(Id);
570 ObDereferenceObject(DeviceObject);
571 ObDereferenceObject(FileObject);
572 return STATUS_INSUFFICIENT_RESOURCES;
573 }
574
575 Stack = IoGetNextIrpStackLocation(Irp);
576 Stack->FileObject = FileObject;
577
578 Status = IoCallDriver(DeviceObject, Irp);
579 if (Status == STATUS_PENDING)
580 {
581 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
582 Status = IoStatusBlock.Status;
583 }
584 }
585
586 /* Hands back unique ID */
587 if (NT_SUCCESS(Status))
588 {
589 *UniqueId = Id;
590 }
591 else
592 {
593 /* In case of failure, also free the rest */
594 FreePool(Id);
595 if (DeviceName->Length)
596 {
597 FreePool(DeviceName->Buffer);
598 }
599
600 ObDereferenceObject(DeviceObject);
601 ObDereferenceObject(FileObject);
602
603 return Status;
604 }
605 }
606
607 /* If user wants to know about GUID */
608 if (HasGuid)
609 {
610 /* Query device stable GUID */
611 KeInitializeEvent(&Event, NotificationEvent, FALSE);
612 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID,
613 DeviceObject,
614 NULL,
615 0,
616 StableGuid,
617 sizeof(GUID),
618 FALSE,
619 &Event,
620 &IoStatusBlock);
621 if (!Irp)
622 {
623 ObDereferenceObject(DeviceObject);
624 ObDereferenceObject(FileObject);
625 return STATUS_INSUFFICIENT_RESOURCES;
626 }
627
628 Stack = IoGetNextIrpStackLocation(Irp);
629 Stack->FileObject = FileObject;
630
631 Status = IoCallDriver(DeviceObject, Irp);
632 if (Status == STATUS_PENDING)
633 {
634 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
635 Status = IoStatusBlock.Status;
636 }
637
638 *HasGuid = NT_SUCCESS(Status);
639 }
640
641 ObDereferenceObject(DeviceObject);
642 ObDereferenceObject(FileObject);
643 return Status;
644 }
645
646 /*
647 * @implemented
648 */
649 NTSTATUS
650 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension,
651 IN PUNICODE_STRING SymbolicName,
652 IN BOOLEAN DeviceNameGiven,
653 OUT PDEVICE_INFORMATION * DeviceInformation)
654 {
655 NTSTATUS Status;
656 PLIST_ENTRY NextEntry;
657 UNICODE_STRING DeviceName;
658 PDEVICE_INFORMATION DeviceInfo = NULL;
659
660 /* If a device name was given, use it */
661 if (DeviceNameGiven)
662 {
663 DeviceName.Length = SymbolicName->Length;
664 DeviceName.Buffer = SymbolicName->Buffer;
665 }
666 else
667 {
668 /* Otherwise, query it */
669 Status = QueryDeviceInformation(SymbolicName,
670 &DeviceName,
671 NULL, NULL,
672 NULL, NULL,
673 NULL, NULL);
674 if (!NT_SUCCESS(Status))
675 {
676 return Status;
677 }
678 }
679
680 /* Look for device information matching devive */
681 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
682 NextEntry != &(DeviceExtension->DeviceListHead);
683 NextEntry = NextEntry->Flink)
684 {
685 DeviceInfo = CONTAINING_RECORD(NextEntry,
686 DEVICE_INFORMATION,
687 DeviceListEntry);
688
689 if (RtlEqualUnicodeString(&DeviceName, &(DeviceInfo->DeviceName), TRUE))
690 {
691 break;
692 }
693 }
694
695 /* Release our buffer if required */
696 if (!DeviceNameGiven)
697 {
698 FreePool(DeviceName.Buffer);
699 }
700
701 /* Return found information */
702 if (NextEntry == &(DeviceExtension->DeviceListHead))
703 {
704 return STATUS_OBJECT_NAME_NOT_FOUND;
705 }
706
707 *DeviceInformation = DeviceInfo;
708 return STATUS_SUCCESS;
709 }
710
711 /*
712 * @implemented
713 */
714 VOID
715 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation)
716 {
717 FreePool(DeviceInformation->SymbolicName.Buffer);
718 FreePool(DeviceInformation);
719 }
720
721 /*
722 * @implemented
723 */
724 VOID
725 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation)
726 {
727 PLIST_ENTRY NextEntry;
728 PSYMLINK_INFORMATION SymLink;
729 PUNIQUE_ID_REPLICATE UniqueId;
730 PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
731
732 /* Purge symbolic links list */
733 while (!IsListEmpty(&(DeviceInformation->SymbolicLinksListHead)))
734 {
735 NextEntry = RemoveHeadList(&(DeviceInformation->SymbolicLinksListHead));
736 SymLink = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
737
738 GlobalDeleteSymbolicLink(&(SymLink->Name));
739 FreePool(SymLink->Name.Buffer);
740 }
741
742 /* Purge replicated unique IDs list */
743 while (!IsListEmpty(&(DeviceInformation->ReplicatedUniqueIdsListHead)))
744 {
745 NextEntry = RemoveHeadList(&(DeviceInformation->ReplicatedUniqueIdsListHead));
746 UniqueId = CONTAINING_RECORD(NextEntry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
747
748 FreePool(UniqueId->UniqueId);
749 FreePool(UniqueId);
750 }
751
752 while (!IsListEmpty(&(DeviceInformation->AssociatedDevicesHead)))
753 {
754 NextEntry = RemoveHeadList(&(DeviceInformation->AssociatedDevicesHead));
755 AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
756
757 FreePool(AssociatedDevice->String.Buffer);
758 FreePool(AssociatedDevice);
759 }
760
761 /* Free the rest of the buffers */
762 FreePool(DeviceInformation->SymbolicName.Buffer);
763 if (DeviceInformation->KeepLinks)
764 {
765 FreePool(DeviceInformation->UniqueId);
766 }
767 FreePool(DeviceInformation->DeviceName.Buffer);
768
769 /* Finally, stop waiting for notifications for this device */
770 if (DeviceInformation->TargetDeviceNotificationEntry)
771 {
772 IoUnregisterPlugPlayNotification(DeviceInformation->TargetDeviceNotificationEntry);
773 }
774 }
775
776 /*
777 * @implemented
778 */
779 VOID
780 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation)
781 {
782 PLIST_ENTRY NextEntry;
783 PSYMLINK_INFORMATION SymlinkInformation;
784
785 /* For all the saved links */
786 while (!IsListEmpty(&(SavedLinkInformation->SymbolicLinksListHead)))
787 {
788 NextEntry = RemoveHeadList(&(SavedLinkInformation->SymbolicLinksListHead));
789 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
790
791 /* Remove from system & free */
792 GlobalDeleteSymbolicLink(&(SymlinkInformation->Name));
793 FreePool(SymlinkInformation->Name.Buffer);
794 FreePool(SymlinkInformation);
795 }
796
797 /* And free unique ID & entry */
798 FreePool(SavedLinkInformation->UniqueId);
799 FreePool(SavedLinkInformation);
800 }
801
802
803 /*
804 * @implemented
805 */
806 VOID
807 NTAPI
808 MountMgrUnload(IN struct _DRIVER_OBJECT *DriverObject)
809 {
810 PLIST_ENTRY NextEntry;
811 PUNIQUE_ID_WORK_ITEM WorkItem;
812 PDEVICE_EXTENSION DeviceExtension;
813 PDEVICE_INFORMATION DeviceInformation;
814 PSAVED_LINK_INFORMATION SavedLinkInformation;
815
816 UNREFERENCED_PARAMETER(DriverObject);
817
818 /* Don't get notification any longer */
819 IoUnregisterShutdownNotification(gdeviceObject);
820
821 /* Free registry buffer */
822 DeviceExtension = gdeviceObject->DeviceExtension;
823 if (DeviceExtension->RegistryPath.Buffer)
824 {
825 FreePool(DeviceExtension->RegistryPath.Buffer);
826 DeviceExtension->RegistryPath.Buffer = NULL;
827 }
828
829 InterlockedExchange(&Unloading, TRUE);
830
831 KeInitializeEvent(&UnloadEvent, NotificationEvent, FALSE);
832
833 /* Wait for workers to finish */
834 if (InterlockedIncrement(&DeviceExtension->WorkerReferences))
835 {
836 KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore),
837 IO_NO_INCREMENT, 1, FALSE);
838
839 KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
840 }
841 else
842 {
843 InterlockedDecrement(&(DeviceExtension->WorkerReferences));
844 }
845
846 /* Don't get any notification any longer² */
847 IoUnregisterPlugPlayNotification(DeviceExtension->NotificationEntry);
848
849 /* Acquire the driver exclusively */
850 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode,
851 FALSE, NULL);
852
853 /* Clear offline devices list */
854 while (!IsListEmpty(&(DeviceExtension->OfflineDeviceListHead)))
855 {
856 NextEntry = RemoveHeadList(&(DeviceExtension->OfflineDeviceListHead));
857 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
858 MountMgrFreeDeadDeviceInfo(DeviceInformation);
859 }
860
861 /* Clear saved links list */
862 while (!IsListEmpty(&(DeviceExtension->SavedLinksListHead)))
863 {
864 NextEntry = RemoveHeadList(&(DeviceExtension->SavedLinksListHead));
865 SavedLinkInformation = CONTAINING_RECORD(NextEntry, SAVED_LINK_INFORMATION, SavedLinksListEntry);
866 MountMgrFreeSavedLink(SavedLinkInformation);
867 }
868
869 /* Clear workers list */
870 while (!IsListEmpty(&(DeviceExtension->UniqueIdWorkerItemListHead)))
871 {
872 NextEntry = RemoveHeadList(&(DeviceExtension->UniqueIdWorkerItemListHead));
873 WorkItem = CONTAINING_RECORD(NextEntry, UNIQUE_ID_WORK_ITEM, UniqueIdWorkerItemListEntry);
874
875 KeResetEvent(&UnloadEvent);
876 WorkItem->Event = &UnloadEvent;
877
878 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT,
879 1, FALSE);
880
881 IoCancelIrp(WorkItem->Irp);
882 KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
883
884 IoFreeIrp(WorkItem->Irp);
885 FreePool(WorkItem->DeviceName.Buffer);
886 FreePool(WorkItem->IrpBuffer);
887 FreePool(WorkItem);
888
889 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode,
890 FALSE, NULL);
891 }
892
893 /* If we have drive letter data, release */
894 if (DeviceExtension->DriveLetterData)
895 {
896 FreePool(DeviceExtension->DriveLetterData);
897 DeviceExtension->DriveLetterData = NULL;
898 }
899
900 /* Release driver & quit */
901 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
902
903 GlobalDeleteSymbolicLink(&DosDevicesMount);
904 IoDeleteDevice(gdeviceObject);
905 }
906
907 /*
908 * @implemented
909 */
910 INIT_SECTION
911 BOOLEAN
912 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath)
913 {
914 NTSTATUS Status;
915 ULONG Result, Default = 0;
916 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
917
918 RtlZeroMemory(QueryTable, sizeof(QueryTable));
919
920 /* Simply read data from register */
921 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
922 QueryTable[0].Name = L"NoAutoMount";
923 QueryTable[0].EntryContext = &Result;
924 QueryTable[0].DefaultType = REG_NONE;
925 QueryTable[0].DefaultData = &Default;
926 QueryTable[0].DefaultLength = sizeof(ULONG);
927
928 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
929 RegistryPath->Buffer,
930 QueryTable,
931 NULL,
932 NULL);
933 if (!NT_SUCCESS(Status))
934 {
935 return (Default != 0);
936 }
937
938 return (Result != 0);
939 }
940
941 /*
942 * @implemented
943 */
944 NTSTATUS
945 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension,
946 IN PUNICODE_STRING SymbolicName,
947 IN BOOLEAN ManuallyRegistered)
948 {
949 WCHAR Letter;
950 GUID StableGuid;
951 HANDLE LinkHandle;
952 ULONG SymLinkCount, i;
953 PLIST_ENTRY NextEntry;
954 PUNICODE_STRING SymLinks;
955 NTSTATUS Status, IntStatus;
956 OBJECT_ATTRIBUTES ObjectAttributes;
957 PSYMLINK_INFORMATION SymlinkInformation;
958 PMOUNTDEV_UNIQUE_ID UniqueId, NewUniqueId;
959 PSAVED_LINK_INFORMATION SavedLinkInformation;
960 PDEVICE_INFORMATION DeviceInformation, CurrentDevice;
961 WCHAR CSymLinkBuffer[RTL_NUMBER_OF(Cunc)], LinkTargetBuffer[MAX_PATH];
962 UNICODE_STRING TargetDeviceName, SuggestedLinkName, DeviceName, VolumeName, DriveLetter, LinkTarget, CSymLink;
963 BOOLEAN HasGuid, HasGptDriveLetter, Valid, UseOnlyIfThereAreNoOtherLinks, IsDrvLetter, IsOff, IsVolumeName, LinkError;
964
965 /* New device = new structure to represent it */
966 DeviceInformation = AllocatePool(sizeof(DEVICE_INFORMATION));
967 if (!DeviceInformation)
968 {
969 return STATUS_INSUFFICIENT_RESOURCES;
970 }
971
972 /* Initialise device structure */
973 RtlZeroMemory(DeviceInformation, sizeof(DEVICE_INFORMATION));
974 InitializeListHead(&(DeviceInformation->SymbolicLinksListHead));
975 InitializeListHead(&(DeviceInformation->ReplicatedUniqueIdsListHead));
976 InitializeListHead(&(DeviceInformation->AssociatedDevicesHead));
977 DeviceInformation->SymbolicName.Length = SymbolicName->Length;
978 DeviceInformation->SymbolicName.MaximumLength = SymbolicName->Length + sizeof(UNICODE_NULL);
979 DeviceInformation->SymbolicName.Buffer = AllocatePool(DeviceInformation->SymbolicName.MaximumLength);
980 if (!DeviceInformation->SymbolicName.Buffer)
981 {
982 FreePool(DeviceInformation);
983 return STATUS_INSUFFICIENT_RESOURCES;
984 }
985
986 /* Copy symbolic name */
987 RtlCopyMemory(DeviceInformation->SymbolicName.Buffer, SymbolicName->Buffer, SymbolicName->Length);
988 DeviceInformation->SymbolicName.Buffer[DeviceInformation->SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
989 DeviceInformation->ManuallyRegistered = ManuallyRegistered;
990 DeviceInformation->DeviceExtension = DeviceExtension;
991
992 /* Query as much data as possible about device */
993 Status = QueryDeviceInformation(SymbolicName,
994 &TargetDeviceName,
995 &UniqueId,
996 &(DeviceInformation->Removable),
997 &HasGptDriveLetter,
998 &HasGuid,
999 &StableGuid,
1000 &Valid);
1001 if (!NT_SUCCESS(Status))
1002 {
1003 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1004
1005 for (NextEntry = DeviceExtension->OfflineDeviceListHead.Flink;
1006 NextEntry != &(DeviceExtension->OfflineDeviceListHead);
1007 NextEntry = NextEntry->Flink)
1008 {
1009 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1010
1011 if (RtlEqualUnicodeString(&(DeviceInformation->SymbolicName), &(CurrentDevice->SymbolicName), TRUE))
1012 {
1013 break;
1014 }
1015 }
1016
1017 if (NextEntry != &(DeviceExtension->OfflineDeviceListHead))
1018 {
1019 MountMgrFreeDeadDeviceInfo(DeviceInformation);
1020 }
1021 else
1022 {
1023 InsertTailList(&(DeviceExtension->OfflineDeviceListHead), &(DeviceInformation->DeviceListEntry));
1024 }
1025
1026 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1027
1028 return Status;
1029 }
1030
1031 /* Save gathered data */
1032 DeviceInformation->UniqueId = UniqueId;
1033 DeviceInformation->DeviceName = TargetDeviceName;
1034 DeviceInformation->KeepLinks = FALSE;
1035
1036 /* If we found system partition, mark it */
1037 if (DeviceExtension->DriveLetterData && UniqueId->UniqueIdLength == DeviceExtension->DriveLetterData->UniqueIdLength)
1038 {
1039 if (RtlCompareMemory(UniqueId->UniqueId, DeviceExtension->DriveLetterData->UniqueId, UniqueId->UniqueIdLength)
1040 == UniqueId->UniqueIdLength)
1041 {
1042 IoSetSystemPartition(&TargetDeviceName);
1043 }
1044 }
1045
1046 /* Check suggested link name */
1047 Status = QuerySuggestedLinkName(&(DeviceInformation->SymbolicName),
1048 &SuggestedLinkName,
1049 &UseOnlyIfThereAreNoOtherLinks);
1050 if (!NT_SUCCESS(Status))
1051 {
1052 SuggestedLinkName.Buffer = NULL;
1053 }
1054
1055 /* If it's OK, set it and save its letter (if any) */
1056 if (SuggestedLinkName.Buffer && IsDriveLetter(&SuggestedLinkName))
1057 {
1058 DeviceInformation->SuggestedDriveLetter = (UCHAR)SuggestedLinkName.Buffer[LETTER_POSITION];
1059 }
1060
1061 /* Acquire driver exclusively */
1062 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1063
1064 /* Check if we already have device in to prevent double registration */
1065 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
1066 NextEntry != &(DeviceExtension->DeviceListHead);
1067 NextEntry = NextEntry->Flink)
1068 {
1069 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1070
1071 if (RtlEqualUnicodeString(&(CurrentDevice->DeviceName), &TargetDeviceName, TRUE))
1072 {
1073 break;
1074 }
1075 }
1076
1077 /* If we found it, clear ours, and return success, all correct */
1078 if (NextEntry != &(DeviceExtension->DeviceListHead))
1079 {
1080 if (SuggestedLinkName.Buffer)
1081 {
1082 FreePool(SuggestedLinkName.Buffer);
1083 }
1084
1085 FreePool(UniqueId);
1086 FreePool(TargetDeviceName.Buffer);
1087 FreePool(DeviceInformation->DeviceName.Buffer);
1088 FreePool(DeviceInformation);
1089
1090 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1091
1092 return STATUS_SUCCESS;
1093 }
1094
1095 /* Check if there are symlinks associated with our device in registry */
1096 Status = QuerySymbolicLinkNamesFromStorage(DeviceExtension,
1097 DeviceInformation,
1098 (SuggestedLinkName.Buffer) ? &SuggestedLinkName : NULL,
1099 UseOnlyIfThereAreNoOtherLinks,
1100 &SymLinks,
1101 &SymLinkCount,
1102 HasGuid,
1103 &StableGuid);
1104
1105 /* If our device is a CD-ROM */
1106 if (RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE))
1107 {
1108 LinkTarget.Length = 0;
1109 LinkTarget.MaximumLength = sizeof(LinkTargetBuffer);
1110 LinkTarget.Buffer = LinkTargetBuffer;
1111
1112 RtlCopyMemory(CSymLinkBuffer, Cunc, sizeof(Cunc));
1113 RtlInitUnicodeString(&CSymLink, CSymLinkBuffer);
1114
1115 /* Start checking all letters that could have been associated */
1116 for (Letter = L'D'; Letter <= L'Z'; Letter++)
1117 {
1118 CSymLink.Buffer[LETTER_POSITION] = Letter;
1119
1120 InitializeObjectAttributes(&ObjectAttributes,
1121 &CSymLink,
1122 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
1123 NULL,
1124 NULL);
1125
1126 /* Try to open the associated symlink */
1127 Status = ZwOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
1128 if (!NT_SUCCESS(Status))
1129 {
1130 continue;
1131 }
1132
1133 /* And query its target */
1134 Status = ZwQuerySymbolicLinkObject(LinkHandle, &LinkTarget, NULL);
1135 ZwClose(LinkHandle);
1136
1137 if (!NT_SUCCESS(Status))
1138 {
1139 continue;
1140 }
1141
1142 IntStatus = STATUS_UNSUCCESSFUL;
1143 if (!RtlEqualUnicodeString(&LinkTarget, &DeviceInformation->DeviceName, FALSE))
1144 {
1145 continue;
1146 }
1147
1148 /* This link is matching our device, whereas it's not supposed to have any
1149 * symlink associated.
1150 * Delete it
1151 */
1152 if (!SymLinkCount)
1153 {
1154 IoDeleteSymbolicLink(&CSymLink);
1155 continue;
1156 }
1157
1158 /* Now, for all the symlinks, check for ours */
1159 for (i = 0; i < SymLinkCount; i++)
1160 {
1161 if (IsDriveLetter(&(SymLinks[i])))
1162 {
1163 /* If it exists, that's correct */
1164 if (SymLinks[i].Buffer[LETTER_POSITION] == Letter)
1165 {
1166 IntStatus = STATUS_SUCCESS;
1167 }
1168 }
1169 }
1170
1171 /* Useless link, delete it */
1172 if (IntStatus == STATUS_UNSUCCESSFUL)
1173 {
1174 IoDeleteSymbolicLink(&CSymLink);
1175 }
1176 }
1177 }
1178
1179 /* Suggested name is no longer required */
1180 if (SuggestedLinkName.Buffer)
1181 {
1182 FreePool(SuggestedLinkName.Buffer);
1183 }
1184
1185 /* If if failed, ensure we don't take symlinks into account */
1186 if (!NT_SUCCESS(Status))
1187 {
1188 SymLinks = NULL;
1189 SymLinkCount = 0;
1190 }
1191
1192 /* Now we queried them, remove the symlinks */
1193 SavedLinkInformation = RemoveSavedLinks(DeviceExtension, UniqueId);
1194
1195 IsDrvLetter = FALSE;
1196 IsOff = FALSE;
1197 IsVolumeName = FALSE;
1198 /* For all the symlinks */
1199 for (i = 0; i < SymLinkCount; i++)
1200 {
1201 /* Check if our device is a volume */
1202 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks[i])))
1203 {
1204 IsVolumeName = TRUE;
1205 }
1206 /* If it has a drive letter */
1207 else if (IsDriveLetter(&(SymLinks[i])))
1208 {
1209 if (IsDrvLetter)
1210 {
1211 DeleteFromLocalDatabase(&(SymLinks[i]), UniqueId);
1212 continue;
1213 }
1214 else
1215 {
1216 IsDrvLetter = TRUE;
1217 }
1218 }
1219
1220 /* And recreate the symlink to our device */
1221 Status = GlobalCreateSymbolicLink(&(SymLinks[i]), &TargetDeviceName);
1222 if (!NT_SUCCESS(Status))
1223 {
1224 LinkError = TRUE;
1225
1226 if ((SavedLinkInformation && !RedirectSavedLink(SavedLinkInformation, &(SymLinks[i]), &TargetDeviceName)) ||
1227 !SavedLinkInformation)
1228 {
1229 Status = QueryDeviceInformation(&(SymLinks[i]), &DeviceName, NULL, NULL, NULL, NULL, NULL, NULL);
1230 if (NT_SUCCESS(Status))
1231 {
1232 LinkError = RtlEqualUnicodeString(&TargetDeviceName, &DeviceName, TRUE);
1233 FreePool(DeviceName.Buffer);
1234 }
1235
1236 if (!LinkError)
1237 {
1238 if (IsDriveLetter(&(SymLinks[i])))
1239 {
1240 IsDrvLetter = FALSE;
1241 DeleteFromLocalDatabase(&(SymLinks[i]), UniqueId);
1242 }
1243
1244 FreePool(SymLinks[i].Buffer);
1245 continue;
1246 }
1247 }
1248 }
1249
1250 /* Check if was offline */
1251 if (IsOffline(&(SymLinks[i])))
1252 {
1253 IsOff = TRUE;
1254 }
1255
1256 /* Finally, associate this symlink with the device */
1257 SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
1258 if (!SymlinkInformation)
1259 {
1260 GlobalDeleteSymbolicLink(&(SymLinks[i]));
1261 FreePool(SymLinks[i].Buffer);
1262 continue;
1263 }
1264
1265 SymlinkInformation->Name = SymLinks[i];
1266 SymlinkInformation->Online = TRUE;
1267
1268 InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
1269 &(SymlinkInformation->SymbolicLinksListEntry));
1270 }
1271
1272 /* Now, for all the recreated symlinks, notify their recreation */
1273 for (NextEntry = DeviceInformation->SymbolicLinksListHead.Flink;
1274 NextEntry != &(DeviceInformation->SymbolicLinksListHead);
1275 NextEntry = NextEntry->Flink)
1276 {
1277 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
1278
1279 SendLinkCreated(&(SymlinkInformation->Name));
1280 }
1281
1282 /* If we had saved links, it's time to free them */
1283 if (SavedLinkInformation)
1284 {
1285 MountMgrFreeSavedLink(SavedLinkInformation);
1286 }
1287
1288 /* If our device doesn't have a volume name */
1289 if (!IsVolumeName)
1290 {
1291 /* It's time to create one */
1292 Status = CreateNewVolumeName(&VolumeName, NULL);
1293 if (NT_SUCCESS(Status))
1294 {
1295 /* Write it to global database */
1296 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
1297 DatabasePath,
1298 VolumeName.Buffer,
1299 REG_BINARY,
1300 UniqueId->UniqueId,
1301 UniqueId->UniqueIdLength);
1302
1303 /* And create the symlink */
1304 GlobalCreateSymbolicLink(&VolumeName, &TargetDeviceName);
1305
1306 SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
1307 if (!SymlinkInformation)
1308 {
1309 FreePool(VolumeName.Buffer);
1310 }
1311 /* Finally, associate it with the device and notify creation */
1312 else
1313 {
1314 SymlinkInformation->Name = VolumeName;
1315 SymlinkInformation->Online = TRUE;
1316 InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
1317 &(SymlinkInformation->SymbolicLinksListEntry));
1318
1319 SendLinkCreated(&VolumeName);
1320 }
1321 }
1322 }
1323
1324 /* If we found a drive letter, then, ignore the suggested one */
1325 if (IsDrvLetter)
1326 {
1327 DeviceInformation->SuggestedDriveLetter = 0;
1328 }
1329 /* Else, it's time to set up one */
1330 else if ((DeviceExtension->NoAutoMount || DeviceInformation->Removable) &&
1331 DeviceExtension->AutomaticDriveLetter &&
1332 (HasGptDriveLetter || DeviceInformation->SuggestedDriveLetter) &&
1333 !HasNoDriveLetterEntry(UniqueId))
1334 {
1335 /* Create a new drive letter */
1336 Status = CreateNewDriveLetterName(&DriveLetter, &TargetDeviceName,
1337 DeviceInformation->SuggestedDriveLetter,
1338 NULL);
1339 if (!NT_SUCCESS(Status))
1340 {
1341 CreateNoDriveLetterEntry(UniqueId);
1342 }
1343 else
1344 {
1345 /* Save it to global database */
1346 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
1347 DatabasePath,
1348 DriveLetter.Buffer,
1349 REG_BINARY,
1350 UniqueId->UniqueId,
1351 UniqueId->UniqueIdLength);
1352
1353 /* Associate it with the device and notify creation */
1354 SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
1355 if (!SymlinkInformation)
1356 {
1357 FreePool(DriveLetter.Buffer);
1358 }
1359 else
1360 {
1361 SymlinkInformation->Name = DriveLetter;
1362 SymlinkInformation->Online = TRUE;
1363 InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
1364 &(SymlinkInformation->SymbolicLinksListEntry));
1365
1366 SendLinkCreated(&DriveLetter);
1367 }
1368 }
1369 }
1370
1371 /* If that's a PnP device, register for notifications */
1372 if (!ManuallyRegistered)
1373 {
1374 RegisterForTargetDeviceNotification(DeviceExtension, DeviceInformation);
1375 }
1376
1377 /* Finally, insert the device into our devices list */
1378 InsertTailList(&(DeviceExtension->DeviceListHead), &(DeviceInformation->DeviceListEntry));
1379
1380 /* Copy device unique ID */
1381 NewUniqueId = AllocatePool(UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1382 if (NewUniqueId)
1383 {
1384 NewUniqueId->UniqueIdLength = UniqueId->UniqueIdLength;
1385 RtlCopyMemory(NewUniqueId->UniqueId, UniqueId->UniqueId, UniqueId->UniqueIdLength);
1386 }
1387
1388 /* If device's offline or valid, skip its notifications */
1389 if (IsOff || Valid)
1390 {
1391 DeviceInformation->SkipNotifications = TRUE;
1392 }
1393
1394 /* In case device is valid and is set to no automount,
1395 * set it offline.
1396 */
1397 if (DeviceExtension->NoAutoMount || IsDrvLetter)
1398 {
1399 IsOff = !DeviceInformation->SkipNotifications;
1400 }
1401 else
1402 {
1403 IsOff = FALSE;
1404 }
1405
1406 /* Finally, release the exclusive lock */
1407 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1408
1409 /* If device is not offline, notify its arrival */
1410 if (!IsOff)
1411 {
1412 SendOnlineNotification(SymbolicName);
1413 }
1414
1415 /* If we had symlinks (from storage), free them */
1416 if (SymLinks)
1417 {
1418 FreePool(SymLinks);
1419 }
1420
1421 /* Notify about unique id change */
1422 if (NewUniqueId)
1423 {
1424 IssueUniqueIdChangeNotify(DeviceExtension, SymbolicName, NewUniqueId);
1425 FreePool(NewUniqueId);
1426 }
1427
1428 /* If this drive was set to have a drive letter automatically
1429 * Now it's back, local databases sync will be required
1430 */
1431 if (DeviceExtension->AutomaticDriveLetter)
1432 {
1433 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1434
1435 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
1436
1437 NextEntry = DeviceExtension->DeviceListHead.Flink;
1438 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1439 while (CurrentDevice != DeviceInformation)
1440 {
1441 if (!CurrentDevice->NoDatabase)
1442 {
1443 ReconcileThisDatabaseWithMaster(DeviceExtension, CurrentDevice);
1444 }
1445
1446 NextEntry = NextEntry->Flink;
1447 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1448 }
1449
1450 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1451 }
1452
1453 return STATUS_SUCCESS;
1454 }
1455
1456 /*
1457 * @implemented
1458 */
1459 VOID
1460 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension,
1461 IN PUNICODE_STRING DeviceName)
1462 {
1463 PLIST_ENTRY NextEntry, DeviceEntry;
1464 PUNIQUE_ID_REPLICATE UniqueIdReplicate;
1465 PSYMLINK_INFORMATION SymlinkInformation;
1466 PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
1467 PSAVED_LINK_INFORMATION SavedLinkInformation = NULL;
1468 PDEVICE_INFORMATION DeviceInformation, CurrentDevice;
1469
1470 /* Acquire device exclusively */
1471 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1472
1473 /* Look for the leaving device */
1474 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
1475 NextEntry != &(DeviceExtension->DeviceListHead);
1476 NextEntry = NextEntry->Flink)
1477 {
1478 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1479
1480 if (!RtlCompareUnicodeString(&(DeviceInformation->SymbolicName), DeviceName, TRUE))
1481 {
1482 break;
1483 }
1484 }
1485
1486 /* If we found it */
1487 if (NextEntry != &(DeviceExtension->DeviceListHead))
1488 {
1489 /* If it's asked to keep links, then, prepare to save them */
1490 if (DeviceInformation->KeepLinks)
1491 {
1492 SavedLinkInformation = AllocatePool(sizeof(SAVED_LINK_INFORMATION));
1493 if (!SavedLinkInformation)
1494 {
1495 DeviceInformation->KeepLinks = FALSE;
1496 }
1497 }
1498
1499 /* If it's possible (and asked), start to save them */
1500 if (DeviceInformation->KeepLinks)
1501 {
1502 InsertTailList(&(DeviceExtension->SavedLinksListHead), &(SavedLinkInformation->SavedLinksListEntry));
1503 InitializeListHead(&(SavedLinkInformation->SymbolicLinksListHead));
1504 SavedLinkInformation->UniqueId = DeviceInformation->UniqueId;
1505 }
1506
1507 /* For all the symlinks */
1508 while (!IsListEmpty(&(DeviceInformation->SymbolicLinksListHead)))
1509 {
1510 NextEntry = RemoveHeadList(&(DeviceInformation->SymbolicLinksListHead));
1511 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
1512
1513 /* If we have to, save the link */
1514 if (DeviceInformation->KeepLinks)
1515 {
1516 InsertTailList(&(SavedLinkInformation->SymbolicLinksListHead), &(SymlinkInformation->SymbolicLinksListEntry));
1517 }
1518 /* Otherwise, just release it */
1519 else
1520 {
1521 GlobalDeleteSymbolicLink(&(SymlinkInformation->Name));
1522 FreePool(SymlinkInformation->Name.Buffer);
1523 FreePool(SymlinkInformation);
1524 }
1525 }
1526
1527 /* Free all the replicated unique IDs */
1528 while (!IsListEmpty(&(DeviceInformation->ReplicatedUniqueIdsListHead)))
1529 {
1530 NextEntry = RemoveHeadList(&(DeviceInformation->ReplicatedUniqueIdsListHead));
1531 UniqueIdReplicate = CONTAINING_RECORD(NextEntry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
1532
1533
1534 FreePool(UniqueIdReplicate->UniqueId);
1535 FreePool(UniqueIdReplicate);
1536 }
1537
1538 while (!IsListEmpty(&(DeviceInformation->AssociatedDevicesHead)))
1539 {
1540 NextEntry = RemoveHeadList(&(DeviceInformation->AssociatedDevicesHead));
1541 AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
1542
1543 DeviceInformation->NoDatabase = TRUE;
1544 FreePool(AssociatedDevice->String.Buffer);
1545 FreePool(AssociatedDevice);
1546 }
1547
1548 /* Remove device from the device list */
1549 RemoveEntryList(&(DeviceInformation->DeviceListEntry));
1550
1551 /* If there are still devices, check if some were associated with ours */
1552 if (!IsListEmpty(&(DeviceInformation->DeviceListEntry)))
1553 {
1554 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
1555 NextEntry != &(DeviceExtension->DeviceListHead);
1556 NextEntry = NextEntry->Flink)
1557 {
1558 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1559
1560 /* And then, remove them */
1561 DeviceEntry = CurrentDevice->AssociatedDevicesHead.Flink;
1562 while (DeviceEntry != &(CurrentDevice->AssociatedDevicesHead))
1563 {
1564 AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
1565 DeviceEntry = DeviceEntry->Flink;
1566
1567 if (AssociatedDevice->DeviceInformation != DeviceInformation)
1568 {
1569 continue;
1570 }
1571
1572 RemoveEntryList(&(AssociatedDevice->AssociatedDevicesEntry));
1573 FreePool(AssociatedDevice->String.Buffer);
1574 FreePool(AssociatedDevice);
1575 }
1576 }
1577 }
1578
1579 /* Finally, clean up device name, symbolic name */
1580 FreePool(DeviceInformation->SymbolicName.Buffer);
1581 if (!DeviceInformation->KeepLinks)
1582 {
1583 FreePool(DeviceInformation->UniqueId);
1584 }
1585 FreePool(DeviceInformation->DeviceName.Buffer);
1586
1587 /* Unregister notifications */
1588 if (DeviceInformation->TargetDeviceNotificationEntry)
1589 {
1590 IoUnregisterPlugPlayNotification(DeviceInformation->TargetDeviceNotificationEntry);
1591 }
1592
1593 /* And leave */
1594 FreePool(DeviceInformation);
1595 }
1596 else
1597 {
1598 /* We didn't find device, perhaps because it was offline */
1599 for (NextEntry = DeviceExtension->OfflineDeviceListHead.Flink;
1600 NextEntry != &(DeviceExtension->OfflineDeviceListHead);
1601 NextEntry = NextEntry->Flink)
1602 {
1603 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1604
1605 /* It was, remove it */
1606 if (RtlCompareUnicodeString(&(DeviceInformation->SymbolicName), DeviceName, TRUE) == 0)
1607 {
1608 RemoveEntryList(&(DeviceInformation->DeviceListEntry));
1609 MountMgrFreeDeadDeviceInfo(DeviceInformation);
1610 break;
1611 }
1612 }
1613 }
1614
1615 /* Release driver */
1616 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1617 }
1618
1619 /*
1620 * @implemented
1621 */
1622 NTSTATUS
1623 NTAPI
1624 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure,
1625 IN PVOID Context)
1626 {
1627 BOOLEAN OldState;
1628 PDEVICE_EXTENSION DeviceExtension;
1629 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification;
1630
1631 /* Notification for a device arrived */
1632 /* Disable hard errors */
1633 OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1634 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
1635
1636 DeviceExtension = Context;
1637 Notification = NotificationStructure;
1638
1639 /* Dispatch according to the event */
1640 if (IsEqualGUID(&(Notification->Event), &GUID_DEVICE_INTERFACE_ARRIVAL))
1641 {
1642 MountMgrMountedDeviceArrival(DeviceExtension, Notification->SymbolicLinkName, FALSE);
1643 }
1644 else if (IsEqualGUID(&(Notification->Event), &GUID_DEVICE_INTERFACE_REMOVAL))
1645 {
1646 MountMgrMountedDeviceRemoval(DeviceExtension, Notification->SymbolicLinkName);
1647 }
1648
1649 /* Reset hard errors */
1650 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
1651
1652 return STATUS_SUCCESS;
1653 }
1654
1655 /*
1656 * @implemented
1657 */
1658 NTSTATUS
1659 NTAPI
1660 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject,
1661 IN PIRP Irp)
1662 {
1663 PIO_STACK_LOCATION Stack;
1664 NTSTATUS Status = STATUS_SUCCESS;
1665
1666 UNREFERENCED_PARAMETER(DeviceObject);
1667
1668 Stack = IoGetCurrentIrpStackLocation(Irp);
1669
1670 /* Allow driver opening for communication
1671 * as long as it's not taken for a directory
1672 */
1673 if (Stack->MajorFunction == IRP_MJ_CREATE &&
1674 Stack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
1675 {
1676 Status = STATUS_NOT_A_DIRECTORY;
1677 }
1678
1679 Irp->IoStatus.Status = Status;
1680 Irp->IoStatus.Information = 0;
1681 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1682 return Status;
1683 }
1684
1685 /*
1686 * @implemented
1687 */
1688 VOID
1689 NTAPI
1690 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject,
1691 IN PIRP Irp)
1692 {
1693 UNREFERENCED_PARAMETER(DeviceObject);
1694
1695 RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
1696
1697 IoReleaseCancelSpinLock(Irp->CancelIrql);
1698
1699 Irp->IoStatus.Information = 0;
1700 Irp->IoStatus.Status = STATUS_CANCELLED;
1701 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1702 }
1703
1704 /*
1705 * @implemented
1706 */
1707 NTSTATUS
1708 NTAPI
1709 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject,
1710 IN PIRP Irp)
1711 {
1712 PIRP ListIrp;
1713 KIRQL OldIrql;
1714 PLIST_ENTRY NextEntry;
1715 PFILE_OBJECT FileObject;
1716 PIO_STACK_LOCATION Stack;
1717 PDEVICE_EXTENSION DeviceExtension;
1718
1719 DeviceExtension = DeviceObject->DeviceExtension;
1720 Stack = IoGetCurrentIrpStackLocation(Irp);
1721 FileObject = Stack->FileObject;
1722
1723 IoAcquireCancelSpinLock(&OldIrql);
1724
1725 /* If IRP list if empty, it's OK */
1726 if (IsListEmpty(&(DeviceExtension->IrpListHead)))
1727 {
1728 IoReleaseCancelSpinLock(OldIrql);
1729
1730 Irp->IoStatus.Status = STATUS_SUCCESS;
1731 Irp->IoStatus.Information = 0;
1732 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1733
1734 return STATUS_SUCCESS;
1735 }
1736
1737 /* Otherwise, cancel all the IRPs */
1738 NextEntry = &(DeviceExtension->IrpListHead);
1739 do
1740 {
1741 ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
1742 if (IoGetCurrentIrpStackLocation(ListIrp)->FileObject == FileObject)
1743 {
1744 ListIrp->Cancel = TRUE;
1745 ListIrp->CancelIrql = OldIrql;
1746 ListIrp->CancelRoutine = NULL;
1747 MountMgrCancel(DeviceObject, ListIrp);
1748
1749 IoAcquireCancelSpinLock(&OldIrql);
1750 }
1751
1752 NextEntry = NextEntry->Flink;
1753 }
1754 while (NextEntry != &(DeviceExtension->IrpListHead));
1755
1756 IoReleaseCancelSpinLock(OldIrql);
1757
1758 Irp->IoStatus.Status = STATUS_SUCCESS;
1759 Irp->IoStatus.Information = 0;
1760 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1761
1762 return STATUS_SUCCESS;
1763 }
1764
1765 /*
1766 * @implemented
1767 */
1768 NTSTATUS
1769 NTAPI
1770 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject,
1771 IN PIRP Irp)
1772 {
1773 PDEVICE_EXTENSION DeviceExtension;
1774
1775 DeviceExtension = DeviceObject->DeviceExtension;
1776
1777 InterlockedExchange(&Unloading, TRUE);
1778
1779 KeInitializeEvent(&UnloadEvent, NotificationEvent, FALSE);
1780
1781 /* Wait for workers */
1782 if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)))
1783 {
1784 KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore),
1785 IO_NO_INCREMENT,
1786 1,
1787 FALSE);
1788 KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
1789 }
1790 else
1791 {
1792 InterlockedDecrement(&(DeviceExtension->WorkerReferences));
1793 }
1794
1795 Irp->IoStatus.Status = STATUS_SUCCESS;
1796 Irp->IoStatus.Information = 0;
1797 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1798
1799 return STATUS_SUCCESS;
1800 }
1801
1802 /* FUNCTIONS ****************************************************************/
1803
1804 INIT_SECTION
1805 NTSTATUS
1806 NTAPI
1807 DriverEntry(IN PDRIVER_OBJECT DriverObject,
1808 IN PUNICODE_STRING RegistryPath)
1809 {
1810 NTSTATUS Status;
1811 PDEVICE_OBJECT DeviceObject;
1812 PDEVICE_EXTENSION DeviceExtension;
1813
1814 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, DatabasePath);
1815
1816 Status = IoCreateDevice(DriverObject,
1817 sizeof(DEVICE_EXTENSION),
1818 &DeviceMount,
1819 FILE_DEVICE_NETWORK,
1820 FILE_DEVICE_SECURE_OPEN,
1821 FALSE,
1822 &DeviceObject);
1823 if (!NT_SUCCESS(Status))
1824 {
1825 return Status;
1826 }
1827
1828 DriverObject->DriverUnload = MountMgrUnload;
1829
1830 DeviceExtension = DeviceObject->DeviceExtension;
1831 RtlZeroMemory(DeviceExtension, sizeof(DEVICE_EXTENSION));
1832 DeviceExtension->DeviceObject = DeviceObject;
1833 DeviceExtension->DriverObject = DriverObject;
1834
1835 InitializeListHead(&(DeviceExtension->DeviceListHead));
1836 InitializeListHead(&(DeviceExtension->OfflineDeviceListHead));
1837
1838 KeInitializeSemaphore(&(DeviceExtension->DeviceLock), 1, 1);
1839 KeInitializeSemaphore(&(DeviceExtension->RemoteDatabaseLock), 1, 1);
1840
1841 InitializeListHead(&(DeviceExtension->IrpListHead));
1842 DeviceExtension->EpicNumber = 1;
1843
1844 InitializeListHead(&(DeviceExtension->SavedLinksListHead));
1845
1846 InitializeListHead(&(DeviceExtension->WorkerQueueListHead));
1847 KeInitializeSemaphore(&(DeviceExtension->WorkerSemaphore), 0, MAXLONG);
1848 DeviceExtension->WorkerReferences = -1;
1849 KeInitializeSpinLock(&(DeviceExtension->WorkerLock));
1850
1851 InitializeListHead(&(DeviceExtension->UniqueIdWorkerItemListHead));
1852 InitializeListHead(&(DeviceExtension->OnlineNotificationListHead));
1853 DeviceExtension->OnlineNotificationCount = 1;
1854
1855 DeviceExtension->RegistryPath.Length = RegistryPath->Length;
1856 DeviceExtension->RegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
1857 DeviceExtension->RegistryPath.Buffer = AllocatePool(DeviceExtension->RegistryPath.MaximumLength);
1858 if (!DeviceExtension->RegistryPath.Buffer)
1859 {
1860 IoDeleteDevice(DeviceObject);
1861 return STATUS_INSUFFICIENT_RESOURCES;
1862 }
1863
1864 RtlCopyUnicodeString(&(DeviceExtension->RegistryPath), RegistryPath);
1865
1866 DeviceExtension->NoAutoMount = MountmgrReadNoAutoMount(&(DeviceExtension->RegistryPath));
1867
1868 GlobalCreateSymbolicLink(&DosDevicesMount, &DeviceMount);
1869
1870 /* Register for device arrival & removal. Ask to be notified for already
1871 * present devices
1872 */
1873 Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
1874 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
1875 &MountedDevicesGuid,
1876 DriverObject,
1877 MountMgrMountedDeviceNotification,
1878 DeviceExtension,
1879 &(DeviceExtension->NotificationEntry));
1880
1881 if (!NT_SUCCESS(Status))
1882 {
1883 IoDeleteDevice(DeviceObject);
1884 return Status;
1885 }
1886
1887 DriverObject->MajorFunction[IRP_MJ_CREATE] =
1888 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MountMgrCreateClose;
1889 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MountMgrDeviceControl;
1890 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MountMgrCleanup;
1891 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = MountMgrShutdown;
1892
1893 gdeviceObject = DeviceObject;
1894
1895 Status = IoRegisterShutdownNotification(DeviceObject);
1896 if (!NT_SUCCESS(Status))
1897 {
1898 IoDeleteDevice(DeviceObject);
1899 }
1900
1901 return Status;
1902 }