0b2fe8e7ba0e6c4fa3f4c9121d1028134825fae3
[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 BOOLEAN IsRemovable;
217 PMOUNTDEV_NAME Name;
218 PMOUNTDEV_UNIQUE_ID Id;
219 PFILE_OBJECT FileObject;
220 PIO_STACK_LOCATION Stack;
221 NTSTATUS Status, IntStatus;
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 if (NT_SUCCESS(Status))
474 {
475 /* Copy back found name to the caller */
476 DeviceName->Length = Name->NameLength;
477 DeviceName->MaximumLength = Name->NameLength + sizeof(WCHAR);
478 DeviceName->Buffer = AllocatePool(DeviceName->MaximumLength);
479 if (!DeviceName->Buffer)
480 {
481 Status = STATUS_INSUFFICIENT_RESOURCES;
482 }
483 else
484 {
485 RtlCopyMemory(DeviceName->Buffer, Name->Name, Name->NameLength);
486 DeviceName->Buffer[Name->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
487 }
488 }
489
490 FreePool(Name);
491 }
492
493 if (!NT_SUCCESS(Status))
494 {
495 ObDereferenceObject(DeviceObject);
496 ObDereferenceObject(FileObject);
497 return Status;
498 }
499
500 /* If caller wants device unique ID */
501 if (UniqueId)
502 {
503 /* Prepare buffer to probe length */
504 Id = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID));
505 if (!Id)
506 {
507 ObDereferenceObject(DeviceObject);
508 ObDereferenceObject(FileObject);
509 return STATUS_INSUFFICIENT_RESOURCES;
510 }
511
512 /* Query unique ID length */
513 KeInitializeEvent(&Event, NotificationEvent, FALSE);
514 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID,
515 DeviceObject,
516 NULL,
517 0,
518 Id,
519 sizeof(MOUNTDEV_UNIQUE_ID),
520 FALSE,
521 &Event,
522 &IoStatusBlock);
523 if (!Irp)
524 {
525 FreePool(Id);
526 ObDereferenceObject(DeviceObject);
527 ObDereferenceObject(FileObject);
528 return STATUS_INSUFFICIENT_RESOURCES;
529 }
530
531 Stack = IoGetNextIrpStackLocation(Irp);
532 Stack->FileObject = FileObject;
533
534 Status = IoCallDriver(DeviceObject, Irp);
535 if (Status == STATUS_PENDING)
536 {
537 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
538 Status = IoStatusBlock.Status;
539 }
540
541 /* Retry with appropriate length */
542 if (Status == STATUS_BUFFER_OVERFLOW)
543 {
544 Size = Id->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID);
545
546 FreePool(Id);
547
548 /* Allocate the correct buffer */
549 Id = AllocatePool(Size);
550 if (!Id)
551 {
552 ObDereferenceObject(DeviceObject);
553 ObDereferenceObject(FileObject);
554 return STATUS_INSUFFICIENT_RESOURCES;
555 }
556
557 /* Query unique ID */
558 KeInitializeEvent(&Event, NotificationEvent, FALSE);
559 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID,
560 DeviceObject,
561 NULL,
562 0,
563 Id,
564 Size,
565 FALSE,
566 &Event,
567 &IoStatusBlock);
568 if (!Irp)
569 {
570 FreePool(Id);
571 ObDereferenceObject(DeviceObject);
572 ObDereferenceObject(FileObject);
573 return STATUS_INSUFFICIENT_RESOURCES;
574 }
575
576 Stack = IoGetNextIrpStackLocation(Irp);
577 Stack->FileObject = FileObject;
578
579 Status = IoCallDriver(DeviceObject, Irp);
580 if (Status == STATUS_PENDING)
581 {
582 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
583 Status = IoStatusBlock.Status;
584 }
585 }
586
587 /* Hands back unique ID */
588 if (NT_SUCCESS(Status))
589 {
590 *UniqueId = Id;
591 }
592 else
593 {
594 /* In case of failure, also free the rest */
595 FreePool(Id);
596 if (DeviceName->Length)
597 {
598 FreePool(DeviceName->Buffer);
599 }
600
601 ObDereferenceObject(DeviceObject);
602 ObDereferenceObject(FileObject);
603
604 return Status;
605 }
606 }
607
608 /* If user wants to know about GUID */
609 if (HasGuid)
610 {
611 /* Query device stable GUID */
612 KeInitializeEvent(&Event, NotificationEvent, FALSE);
613 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID,
614 DeviceObject,
615 NULL,
616 0,
617 StableGuid,
618 sizeof(GUID),
619 FALSE,
620 &Event,
621 &IoStatusBlock);
622 if (!Irp)
623 {
624 ObDereferenceObject(DeviceObject);
625 ObDereferenceObject(FileObject);
626 return STATUS_INSUFFICIENT_RESOURCES;
627 }
628
629 Stack = IoGetNextIrpStackLocation(Irp);
630 Stack->FileObject = FileObject;
631
632 IntStatus = IoCallDriver(DeviceObject, Irp);
633 if (IntStatus == STATUS_PENDING)
634 {
635 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
636 IntStatus = IoStatusBlock.Status;
637 }
638
639 *HasGuid = NT_SUCCESS(IntStatus);
640 }
641
642 ObDereferenceObject(DeviceObject);
643 ObDereferenceObject(FileObject);
644 return Status;
645 }
646
647 /*
648 * @implemented
649 */
650 NTSTATUS
651 FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension,
652 IN PUNICODE_STRING SymbolicName,
653 IN BOOLEAN DeviceNameGiven,
654 OUT PDEVICE_INFORMATION * DeviceInformation)
655 {
656 NTSTATUS Status;
657 PLIST_ENTRY NextEntry;
658 UNICODE_STRING DeviceName;
659 PDEVICE_INFORMATION DeviceInfo = NULL;
660
661 /* If a device name was given, use it */
662 if (DeviceNameGiven)
663 {
664 DeviceName.Length = SymbolicName->Length;
665 DeviceName.Buffer = SymbolicName->Buffer;
666 }
667 else
668 {
669 /* Otherwise, query it */
670 Status = QueryDeviceInformation(SymbolicName,
671 &DeviceName,
672 NULL, NULL,
673 NULL, NULL,
674 NULL, NULL);
675 if (!NT_SUCCESS(Status))
676 {
677 return Status;
678 }
679 }
680
681 /* Look for device information matching devive */
682 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
683 NextEntry != &(DeviceExtension->DeviceListHead);
684 NextEntry = NextEntry->Flink)
685 {
686 DeviceInfo = CONTAINING_RECORD(NextEntry,
687 DEVICE_INFORMATION,
688 DeviceListEntry);
689
690 if (RtlEqualUnicodeString(&DeviceName, &(DeviceInfo->DeviceName), TRUE))
691 {
692 break;
693 }
694 }
695
696 /* Release our buffer if required */
697 if (!DeviceNameGiven)
698 {
699 FreePool(DeviceName.Buffer);
700 }
701
702 /* Return found information */
703 if (NextEntry == &(DeviceExtension->DeviceListHead))
704 {
705 return STATUS_OBJECT_NAME_NOT_FOUND;
706 }
707
708 *DeviceInformation = DeviceInfo;
709 return STATUS_SUCCESS;
710 }
711
712 /*
713 * @implemented
714 */
715 VOID
716 MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation)
717 {
718 FreePool(DeviceInformation->SymbolicName.Buffer);
719 FreePool(DeviceInformation);
720 }
721
722 /*
723 * @implemented
724 */
725 VOID
726 MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation)
727 {
728 PLIST_ENTRY NextEntry;
729 PSYMLINK_INFORMATION SymLink;
730 PUNIQUE_ID_REPLICATE UniqueId;
731 PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
732
733 /* Purge symbolic links list */
734 while (!IsListEmpty(&(DeviceInformation->SymbolicLinksListHead)))
735 {
736 NextEntry = RemoveHeadList(&(DeviceInformation->SymbolicLinksListHead));
737 SymLink = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
738
739 GlobalDeleteSymbolicLink(&(SymLink->Name));
740 FreePool(SymLink->Name.Buffer);
741 }
742
743 /* Purge replicated unique IDs list */
744 while (!IsListEmpty(&(DeviceInformation->ReplicatedUniqueIdsListHead)))
745 {
746 NextEntry = RemoveHeadList(&(DeviceInformation->ReplicatedUniqueIdsListHead));
747 UniqueId = CONTAINING_RECORD(NextEntry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
748
749 FreePool(UniqueId->UniqueId);
750 FreePool(UniqueId);
751 }
752
753 while (!IsListEmpty(&(DeviceInformation->AssociatedDevicesHead)))
754 {
755 NextEntry = RemoveHeadList(&(DeviceInformation->AssociatedDevicesHead));
756 AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
757
758 FreePool(AssociatedDevice->String.Buffer);
759 FreePool(AssociatedDevice);
760 }
761
762 /* Free the rest of the buffers */
763 FreePool(DeviceInformation->SymbolicName.Buffer);
764 if (DeviceInformation->KeepLinks)
765 {
766 FreePool(DeviceInformation->UniqueId);
767 }
768 FreePool(DeviceInformation->DeviceName.Buffer);
769
770 /* Finally, stop waiting for notifications for this device */
771 if (DeviceInformation->TargetDeviceNotificationEntry)
772 {
773 IoUnregisterPlugPlayNotification(DeviceInformation->TargetDeviceNotificationEntry);
774 }
775 }
776
777 /*
778 * @implemented
779 */
780 VOID
781 MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation)
782 {
783 PLIST_ENTRY NextEntry;
784 PSYMLINK_INFORMATION SymlinkInformation;
785
786 /* For all the saved links */
787 while (!IsListEmpty(&(SavedLinkInformation->SymbolicLinksListHead)))
788 {
789 NextEntry = RemoveHeadList(&(SavedLinkInformation->SymbolicLinksListHead));
790 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
791
792 /* Remove from system & free */
793 GlobalDeleteSymbolicLink(&(SymlinkInformation->Name));
794 FreePool(SymlinkInformation->Name.Buffer);
795 FreePool(SymlinkInformation);
796 }
797
798 /* And free unique ID & entry */
799 FreePool(SavedLinkInformation->UniqueId);
800 FreePool(SavedLinkInformation);
801 }
802
803
804 /*
805 * @implemented
806 */
807 VOID
808 NTAPI
809 MountMgrUnload(IN struct _DRIVER_OBJECT *DriverObject)
810 {
811 PLIST_ENTRY NextEntry;
812 PUNIQUE_ID_WORK_ITEM WorkItem;
813 PDEVICE_EXTENSION DeviceExtension;
814 PDEVICE_INFORMATION DeviceInformation;
815 PSAVED_LINK_INFORMATION SavedLinkInformation;
816
817 UNREFERENCED_PARAMETER(DriverObject);
818
819 /* Don't get notification any longer */
820 IoUnregisterShutdownNotification(gdeviceObject);
821
822 /* Free registry buffer */
823 DeviceExtension = gdeviceObject->DeviceExtension;
824 if (DeviceExtension->RegistryPath.Buffer)
825 {
826 FreePool(DeviceExtension->RegistryPath.Buffer);
827 DeviceExtension->RegistryPath.Buffer = NULL;
828 }
829
830 InterlockedExchange(&Unloading, TRUE);
831
832 KeInitializeEvent(&UnloadEvent, NotificationEvent, FALSE);
833
834 /* Wait for workers to finish */
835 if (InterlockedIncrement(&DeviceExtension->WorkerReferences))
836 {
837 KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore),
838 IO_NO_INCREMENT, 1, FALSE);
839
840 KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
841 }
842 else
843 {
844 InterlockedDecrement(&(DeviceExtension->WorkerReferences));
845 }
846
847 /* Don't get any notification any longer² */
848 IoUnregisterPlugPlayNotification(DeviceExtension->NotificationEntry);
849
850 /* Acquire the driver exclusively */
851 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode,
852 FALSE, NULL);
853
854 /* Clear offline devices list */
855 while (!IsListEmpty(&(DeviceExtension->OfflineDeviceListHead)))
856 {
857 NextEntry = RemoveHeadList(&(DeviceExtension->OfflineDeviceListHead));
858 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
859 MountMgrFreeDeadDeviceInfo(DeviceInformation);
860 }
861
862 /* Clear saved links list */
863 while (!IsListEmpty(&(DeviceExtension->SavedLinksListHead)))
864 {
865 NextEntry = RemoveHeadList(&(DeviceExtension->SavedLinksListHead));
866 SavedLinkInformation = CONTAINING_RECORD(NextEntry, SAVED_LINK_INFORMATION, SavedLinksListEntry);
867 MountMgrFreeSavedLink(SavedLinkInformation);
868 }
869
870 /* Clear workers list */
871 while (!IsListEmpty(&(DeviceExtension->UniqueIdWorkerItemListHead)))
872 {
873 NextEntry = RemoveHeadList(&(DeviceExtension->UniqueIdWorkerItemListHead));
874 WorkItem = CONTAINING_RECORD(NextEntry, UNIQUE_ID_WORK_ITEM, UniqueIdWorkerItemListEntry);
875
876 KeClearEvent(&UnloadEvent);
877 WorkItem->Event = &UnloadEvent;
878
879 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT,
880 1, FALSE);
881
882 IoCancelIrp(WorkItem->Irp);
883 KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
884
885 IoFreeIrp(WorkItem->Irp);
886 FreePool(WorkItem->DeviceName.Buffer);
887 FreePool(WorkItem->IrpBuffer);
888 FreePool(WorkItem);
889
890 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode,
891 FALSE, NULL);
892 }
893
894 /* If we have drive letter data, release */
895 if (DeviceExtension->DriveLetterData)
896 {
897 FreePool(DeviceExtension->DriveLetterData);
898 DeviceExtension->DriveLetterData = NULL;
899 }
900
901 /* Release driver & quit */
902 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
903
904 GlobalDeleteSymbolicLink(&DosDevicesMount);
905 IoDeleteDevice(gdeviceObject);
906 }
907
908 /*
909 * @implemented
910 */
911 INIT_FUNCTION
912 BOOLEAN
913 MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath)
914 {
915 NTSTATUS Status;
916 ULONG Result, Default = 0;
917 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
918
919 RtlZeroMemory(QueryTable, sizeof(QueryTable));
920
921 /* Simply read data from register */
922 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
923 QueryTable[0].Name = L"NoAutoMount";
924 QueryTable[0].EntryContext = &Result;
925 QueryTable[0].DefaultType = REG_NONE;
926 QueryTable[0].DefaultData = &Default;
927 QueryTable[0].DefaultLength = sizeof(ULONG);
928
929 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
930 RegistryPath->Buffer,
931 QueryTable,
932 NULL,
933 NULL);
934 if (!NT_SUCCESS(Status))
935 {
936 return (Default != 0);
937 }
938
939 return (Result != 0);
940 }
941
942 /*
943 * @implemented
944 */
945 NTSTATUS
946 MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension,
947 IN PUNICODE_STRING SymbolicName,
948 IN BOOLEAN ManuallyRegistered)
949 {
950 WCHAR Letter;
951 GUID StableGuid;
952 HANDLE LinkHandle;
953 ULONG SymLinkCount, i;
954 PLIST_ENTRY NextEntry;
955 PUNICODE_STRING SymLinks;
956 NTSTATUS Status, IntStatus;
957 OBJECT_ATTRIBUTES ObjectAttributes;
958 PSYMLINK_INFORMATION SymlinkInformation;
959 PMOUNTDEV_UNIQUE_ID UniqueId, NewUniqueId;
960 PSAVED_LINK_INFORMATION SavedLinkInformation;
961 PDEVICE_INFORMATION DeviceInformation, CurrentDevice;
962 WCHAR CSymLinkBuffer[RTL_NUMBER_OF(Cunc)], LinkTargetBuffer[MAX_PATH];
963 UNICODE_STRING TargetDeviceName, SuggestedLinkName, DeviceName, VolumeName, DriveLetter, LinkTarget, CSymLink;
964 BOOLEAN HasGuid, HasGptDriveLetter, Valid, UseOnlyIfThereAreNoOtherLinks, IsDrvLetter, IsOff, IsVolumeName, LinkError;
965
966 /* New device = new structure to represent it */
967 DeviceInformation = AllocatePool(sizeof(DEVICE_INFORMATION));
968 if (!DeviceInformation)
969 {
970 return STATUS_INSUFFICIENT_RESOURCES;
971 }
972
973 /* Initialise device structure */
974 RtlZeroMemory(DeviceInformation, sizeof(DEVICE_INFORMATION));
975 InitializeListHead(&(DeviceInformation->SymbolicLinksListHead));
976 InitializeListHead(&(DeviceInformation->ReplicatedUniqueIdsListHead));
977 InitializeListHead(&(DeviceInformation->AssociatedDevicesHead));
978 DeviceInformation->SymbolicName.Length = SymbolicName->Length;
979 DeviceInformation->SymbolicName.MaximumLength = SymbolicName->Length + sizeof(UNICODE_NULL);
980 DeviceInformation->SymbolicName.Buffer = AllocatePool(DeviceInformation->SymbolicName.MaximumLength);
981 if (!DeviceInformation->SymbolicName.Buffer)
982 {
983 FreePool(DeviceInformation);
984 return STATUS_INSUFFICIENT_RESOURCES;
985 }
986
987 /* Copy symbolic name */
988 RtlCopyMemory(DeviceInformation->SymbolicName.Buffer, SymbolicName->Buffer, SymbolicName->Length);
989 DeviceInformation->SymbolicName.Buffer[DeviceInformation->SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
990 DeviceInformation->ManuallyRegistered = ManuallyRegistered;
991 DeviceInformation->DeviceExtension = DeviceExtension;
992
993 /* Query as much data as possible about device */
994 Status = QueryDeviceInformation(SymbolicName,
995 &TargetDeviceName,
996 &UniqueId,
997 &(DeviceInformation->Removable),
998 &HasGptDriveLetter,
999 &HasGuid,
1000 &StableGuid,
1001 &Valid);
1002 if (!NT_SUCCESS(Status))
1003 {
1004 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1005
1006 for (NextEntry = DeviceExtension->OfflineDeviceListHead.Flink;
1007 NextEntry != &(DeviceExtension->OfflineDeviceListHead);
1008 NextEntry = NextEntry->Flink)
1009 {
1010 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1011
1012 if (RtlEqualUnicodeString(&(DeviceInformation->SymbolicName), &(CurrentDevice->SymbolicName), TRUE))
1013 {
1014 break;
1015 }
1016 }
1017
1018 if (NextEntry != &(DeviceExtension->OfflineDeviceListHead))
1019 {
1020 MountMgrFreeDeadDeviceInfo(DeviceInformation);
1021 }
1022 else
1023 {
1024 InsertTailList(&(DeviceExtension->OfflineDeviceListHead), &(DeviceInformation->DeviceListEntry));
1025 }
1026
1027 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1028
1029 return Status;
1030 }
1031
1032 /* Save gathered data */
1033 DeviceInformation->UniqueId = UniqueId;
1034 DeviceInformation->DeviceName = TargetDeviceName;
1035 DeviceInformation->KeepLinks = FALSE;
1036
1037 /* If we found system partition, mark it */
1038 if (DeviceExtension->DriveLetterData && UniqueId->UniqueIdLength == DeviceExtension->DriveLetterData->UniqueIdLength)
1039 {
1040 if (RtlCompareMemory(UniqueId->UniqueId, DeviceExtension->DriveLetterData->UniqueId, UniqueId->UniqueIdLength)
1041 == UniqueId->UniqueIdLength)
1042 {
1043 IoSetSystemPartition(&TargetDeviceName);
1044 }
1045 }
1046
1047 /* Check suggested link name */
1048 Status = QuerySuggestedLinkName(&(DeviceInformation->SymbolicName),
1049 &SuggestedLinkName,
1050 &UseOnlyIfThereAreNoOtherLinks);
1051 if (!NT_SUCCESS(Status))
1052 {
1053 SuggestedLinkName.Buffer = NULL;
1054 }
1055
1056 /* If it's OK, set it and save its letter (if any) */
1057 if (SuggestedLinkName.Buffer && IsDriveLetter(&SuggestedLinkName))
1058 {
1059 DeviceInformation->SuggestedDriveLetter = (UCHAR)SuggestedLinkName.Buffer[LETTER_POSITION];
1060 }
1061
1062 /* Acquire driver exclusively */
1063 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1064
1065 /* Check if we already have device in to prevent double registration */
1066 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
1067 NextEntry != &(DeviceExtension->DeviceListHead);
1068 NextEntry = NextEntry->Flink)
1069 {
1070 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1071
1072 if (RtlEqualUnicodeString(&(CurrentDevice->DeviceName), &TargetDeviceName, TRUE))
1073 {
1074 break;
1075 }
1076 }
1077
1078 /* If we found it, clear ours, and return success, all correct */
1079 if (NextEntry != &(DeviceExtension->DeviceListHead))
1080 {
1081 if (SuggestedLinkName.Buffer)
1082 {
1083 FreePool(SuggestedLinkName.Buffer);
1084 }
1085
1086 FreePool(UniqueId);
1087 FreePool(TargetDeviceName.Buffer);
1088 FreePool(DeviceInformation->DeviceName.Buffer);
1089 FreePool(DeviceInformation);
1090
1091 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1092
1093 return STATUS_SUCCESS;
1094 }
1095
1096 /* Check if there are symlinks associated with our device in registry */
1097 Status = QuerySymbolicLinkNamesFromStorage(DeviceExtension,
1098 DeviceInformation,
1099 (SuggestedLinkName.Buffer) ? &SuggestedLinkName : NULL,
1100 UseOnlyIfThereAreNoOtherLinks,
1101 &SymLinks,
1102 &SymLinkCount,
1103 HasGuid,
1104 &StableGuid);
1105
1106 /* If our device is a CD-ROM */
1107 if (RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE))
1108 {
1109 LinkTarget.Length = 0;
1110 LinkTarget.MaximumLength = sizeof(LinkTargetBuffer);
1111 LinkTarget.Buffer = LinkTargetBuffer;
1112
1113 RtlCopyMemory(CSymLinkBuffer, Cunc, sizeof(Cunc));
1114 RtlInitUnicodeString(&CSymLink, CSymLinkBuffer);
1115
1116 /* Start checking all letters that could have been associated */
1117 for (Letter = L'D'; Letter <= L'Z'; Letter++)
1118 {
1119 CSymLink.Buffer[LETTER_POSITION] = Letter;
1120
1121 InitializeObjectAttributes(&ObjectAttributes,
1122 &CSymLink,
1123 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
1124 NULL,
1125 NULL);
1126
1127 /* Try to open the associated symlink */
1128 Status = ZwOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
1129 if (!NT_SUCCESS(Status))
1130 {
1131 continue;
1132 }
1133
1134 /* And query its target */
1135 Status = ZwQuerySymbolicLinkObject(LinkHandle, &LinkTarget, NULL);
1136 ZwClose(LinkHandle);
1137
1138 if (!NT_SUCCESS(Status))
1139 {
1140 continue;
1141 }
1142
1143 IntStatus = STATUS_UNSUCCESSFUL;
1144 if (!RtlEqualUnicodeString(&LinkTarget, &DeviceInformation->DeviceName, FALSE))
1145 {
1146 continue;
1147 }
1148
1149 /* This link is matching our device, whereas it's not supposed to have any
1150 * symlink associated.
1151 * Delete it
1152 */
1153 if (!SymLinkCount)
1154 {
1155 IoDeleteSymbolicLink(&CSymLink);
1156 continue;
1157 }
1158
1159 /* Now, for all the symlinks, check for ours */
1160 for (i = 0; i < SymLinkCount; i++)
1161 {
1162 if (IsDriveLetter(&(SymLinks[i])))
1163 {
1164 /* If it exists, that's correct */
1165 if (SymLinks[i].Buffer[LETTER_POSITION] == Letter)
1166 {
1167 IntStatus = STATUS_SUCCESS;
1168 }
1169 }
1170 }
1171
1172 /* Useless link, delete it */
1173 if (IntStatus == STATUS_UNSUCCESSFUL)
1174 {
1175 IoDeleteSymbolicLink(&CSymLink);
1176 }
1177 }
1178 }
1179
1180 /* Suggested name is no longer required */
1181 if (SuggestedLinkName.Buffer)
1182 {
1183 FreePool(SuggestedLinkName.Buffer);
1184 }
1185
1186 /* If if failed, ensure we don't take symlinks into account */
1187 if (!NT_SUCCESS(Status))
1188 {
1189 SymLinks = NULL;
1190 SymLinkCount = 0;
1191 }
1192
1193 /* Now we queried them, remove the symlinks */
1194 SavedLinkInformation = RemoveSavedLinks(DeviceExtension, UniqueId);
1195
1196 IsDrvLetter = FALSE;
1197 IsOff = FALSE;
1198 IsVolumeName = FALSE;
1199 /* For all the symlinks */
1200 for (i = 0; i < SymLinkCount; i++)
1201 {
1202 /* Check if our device is a volume */
1203 if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks[i])))
1204 {
1205 IsVolumeName = TRUE;
1206 }
1207 /* If it has a drive letter */
1208 else if (IsDriveLetter(&(SymLinks[i])))
1209 {
1210 if (IsDrvLetter)
1211 {
1212 DeleteFromLocalDatabase(&(SymLinks[i]), UniqueId);
1213 continue;
1214 }
1215 else
1216 {
1217 IsDrvLetter = TRUE;
1218 }
1219 }
1220
1221 /* And recreate the symlink to our device */
1222 Status = GlobalCreateSymbolicLink(&(SymLinks[i]), &TargetDeviceName);
1223 if (!NT_SUCCESS(Status))
1224 {
1225 LinkError = TRUE;
1226
1227 if ((SavedLinkInformation && !RedirectSavedLink(SavedLinkInformation, &(SymLinks[i]), &TargetDeviceName)) ||
1228 !SavedLinkInformation)
1229 {
1230 Status = QueryDeviceInformation(&(SymLinks[i]), &DeviceName, NULL, NULL, NULL, NULL, NULL, NULL);
1231 if (NT_SUCCESS(Status))
1232 {
1233 LinkError = RtlEqualUnicodeString(&TargetDeviceName, &DeviceName, TRUE);
1234 FreePool(DeviceName.Buffer);
1235 }
1236
1237 if (!LinkError)
1238 {
1239 if (IsDriveLetter(&(SymLinks[i])))
1240 {
1241 IsDrvLetter = FALSE;
1242 DeleteFromLocalDatabase(&(SymLinks[i]), UniqueId);
1243 }
1244
1245 FreePool(SymLinks[i].Buffer);
1246 continue;
1247 }
1248 }
1249 }
1250
1251 /* Check if was offline */
1252 if (IsOffline(&(SymLinks[i])))
1253 {
1254 IsOff = TRUE;
1255 }
1256
1257 /* Finally, associate this symlink with the device */
1258 SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
1259 if (!SymlinkInformation)
1260 {
1261 GlobalDeleteSymbolicLink(&(SymLinks[i]));
1262 FreePool(SymLinks[i].Buffer);
1263 continue;
1264 }
1265
1266 SymlinkInformation->Name = SymLinks[i];
1267 SymlinkInformation->Online = TRUE;
1268
1269 InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
1270 &(SymlinkInformation->SymbolicLinksListEntry));
1271 }
1272
1273 /* Now, for all the recreated symlinks, notify their recreation */
1274 for (NextEntry = DeviceInformation->SymbolicLinksListHead.Flink;
1275 NextEntry != &(DeviceInformation->SymbolicLinksListHead);
1276 NextEntry = NextEntry->Flink)
1277 {
1278 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
1279
1280 SendLinkCreated(&(SymlinkInformation->Name));
1281 }
1282
1283 /* If we had saved links, it's time to free them */
1284 if (SavedLinkInformation)
1285 {
1286 MountMgrFreeSavedLink(SavedLinkInformation);
1287 }
1288
1289 /* If our device doesn't have a volume name */
1290 if (!IsVolumeName)
1291 {
1292 /* It's time to create one */
1293 Status = CreateNewVolumeName(&VolumeName, NULL);
1294 if (NT_SUCCESS(Status))
1295 {
1296 /* Write it to global database */
1297 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
1298 DatabasePath,
1299 VolumeName.Buffer,
1300 REG_BINARY,
1301 UniqueId->UniqueId,
1302 UniqueId->UniqueIdLength);
1303
1304 /* And create the symlink */
1305 GlobalCreateSymbolicLink(&VolumeName, &TargetDeviceName);
1306
1307 SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
1308 if (!SymlinkInformation)
1309 {
1310 FreePool(VolumeName.Buffer);
1311 }
1312 /* Finally, associate it with the device and notify creation */
1313 else
1314 {
1315 SymlinkInformation->Name = VolumeName;
1316 SymlinkInformation->Online = TRUE;
1317 InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
1318 &(SymlinkInformation->SymbolicLinksListEntry));
1319
1320 SendLinkCreated(&VolumeName);
1321 }
1322 }
1323 }
1324
1325 /* If we found a drive letter, then, ignore the suggested one */
1326 if (IsDrvLetter)
1327 {
1328 DeviceInformation->SuggestedDriveLetter = 0;
1329 }
1330 /* Else, it's time to set up one */
1331 else if ((DeviceExtension->NoAutoMount || DeviceInformation->Removable) &&
1332 DeviceExtension->AutomaticDriveLetter &&
1333 (HasGptDriveLetter || DeviceInformation->SuggestedDriveLetter) &&
1334 !HasNoDriveLetterEntry(UniqueId))
1335 {
1336 /* Create a new drive letter */
1337 Status = CreateNewDriveLetterName(&DriveLetter, &TargetDeviceName,
1338 DeviceInformation->SuggestedDriveLetter,
1339 NULL);
1340 if (!NT_SUCCESS(Status))
1341 {
1342 CreateNoDriveLetterEntry(UniqueId);
1343 }
1344 else
1345 {
1346 /* Save it to global database */
1347 RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
1348 DatabasePath,
1349 DriveLetter.Buffer,
1350 REG_BINARY,
1351 UniqueId->UniqueId,
1352 UniqueId->UniqueIdLength);
1353
1354 /* Associate it with the device and notify creation */
1355 SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
1356 if (!SymlinkInformation)
1357 {
1358 FreePool(DriveLetter.Buffer);
1359 }
1360 else
1361 {
1362 SymlinkInformation->Name = DriveLetter;
1363 SymlinkInformation->Online = TRUE;
1364 InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
1365 &(SymlinkInformation->SymbolicLinksListEntry));
1366
1367 SendLinkCreated(&DriveLetter);
1368 }
1369 }
1370 }
1371
1372 /* If that's a PnP device, register for notifications */
1373 if (!ManuallyRegistered)
1374 {
1375 RegisterForTargetDeviceNotification(DeviceExtension, DeviceInformation);
1376 }
1377
1378 /* Finally, insert the device into our devices list */
1379 InsertTailList(&(DeviceExtension->DeviceListHead), &(DeviceInformation->DeviceListEntry));
1380
1381 /* Copy device unique ID */
1382 NewUniqueId = AllocatePool(UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
1383 if (NewUniqueId)
1384 {
1385 NewUniqueId->UniqueIdLength = UniqueId->UniqueIdLength;
1386 RtlCopyMemory(NewUniqueId->UniqueId, UniqueId->UniqueId, UniqueId->UniqueIdLength);
1387 }
1388
1389 /* If device's offline or valid, skip its notifications */
1390 if (IsOff || Valid)
1391 {
1392 DeviceInformation->SkipNotifications = TRUE;
1393 }
1394
1395 /* In case device is valid and is set to no automount,
1396 * set it offline.
1397 */
1398 if (DeviceExtension->NoAutoMount || IsDrvLetter)
1399 {
1400 IsOff = !DeviceInformation->SkipNotifications;
1401 }
1402 else
1403 {
1404 IsOff = FALSE;
1405 }
1406
1407 /* Finally, release the exclusive lock */
1408 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1409
1410 /* If device is not offline, notify its arrival */
1411 if (!IsOff)
1412 {
1413 SendOnlineNotification(SymbolicName);
1414 }
1415
1416 /* If we had symlinks (from storage), free them */
1417 if (SymLinks)
1418 {
1419 FreePool(SymLinks);
1420 }
1421
1422 /* Notify about unique id change */
1423 if (NewUniqueId)
1424 {
1425 IssueUniqueIdChangeNotify(DeviceExtension, SymbolicName, NewUniqueId);
1426 FreePool(NewUniqueId);
1427 }
1428
1429 /* If this drive was set to have a drive letter automatically
1430 * Now it's back, local databases sync will be required
1431 */
1432 if (DeviceExtension->AutomaticDriveLetter)
1433 {
1434 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1435
1436 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
1437
1438 NextEntry = DeviceExtension->DeviceListHead.Flink;
1439 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1440 while (CurrentDevice != DeviceInformation)
1441 {
1442 if (!CurrentDevice->NoDatabase)
1443 {
1444 ReconcileThisDatabaseWithMaster(DeviceExtension, CurrentDevice);
1445 }
1446
1447 NextEntry = NextEntry->Flink;
1448 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1449 }
1450
1451 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1452 }
1453
1454 return STATUS_SUCCESS;
1455 }
1456
1457 /*
1458 * @implemented
1459 */
1460 VOID
1461 MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension,
1462 IN PUNICODE_STRING DeviceName)
1463 {
1464 PLIST_ENTRY NextEntry, DeviceEntry;
1465 PUNIQUE_ID_REPLICATE UniqueIdReplicate;
1466 PSYMLINK_INFORMATION SymlinkInformation;
1467 PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
1468 PSAVED_LINK_INFORMATION SavedLinkInformation = NULL;
1469 PDEVICE_INFORMATION DeviceInformation, CurrentDevice;
1470
1471 /* Acquire device exclusively */
1472 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
1473
1474 /* Look for the leaving device */
1475 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
1476 NextEntry != &(DeviceExtension->DeviceListHead);
1477 NextEntry = NextEntry->Flink)
1478 {
1479 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1480
1481 if (!RtlCompareUnicodeString(&(DeviceInformation->SymbolicName), DeviceName, TRUE))
1482 {
1483 break;
1484 }
1485 }
1486
1487 /* If we found it */
1488 if (NextEntry != &(DeviceExtension->DeviceListHead))
1489 {
1490 /* If it's asked to keep links, then, prepare to save them */
1491 if (DeviceInformation->KeepLinks)
1492 {
1493 SavedLinkInformation = AllocatePool(sizeof(SAVED_LINK_INFORMATION));
1494 if (!SavedLinkInformation)
1495 {
1496 DeviceInformation->KeepLinks = FALSE;
1497 }
1498 }
1499
1500 /* If it's possible (and asked), start to save them */
1501 if (DeviceInformation->KeepLinks)
1502 {
1503 InsertTailList(&(DeviceExtension->SavedLinksListHead), &(SavedLinkInformation->SavedLinksListEntry));
1504 InitializeListHead(&(SavedLinkInformation->SymbolicLinksListHead));
1505 SavedLinkInformation->UniqueId = DeviceInformation->UniqueId;
1506 }
1507
1508 /* For all the symlinks */
1509 while (!IsListEmpty(&(DeviceInformation->SymbolicLinksListHead)))
1510 {
1511 NextEntry = RemoveHeadList(&(DeviceInformation->SymbolicLinksListHead));
1512 SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
1513
1514 /* If we have to, save the link */
1515 if (DeviceInformation->KeepLinks)
1516 {
1517 InsertTailList(&(SavedLinkInformation->SymbolicLinksListHead), &(SymlinkInformation->SymbolicLinksListEntry));
1518 }
1519 /* Otherwise, just release it */
1520 else
1521 {
1522 GlobalDeleteSymbolicLink(&(SymlinkInformation->Name));
1523 FreePool(SymlinkInformation->Name.Buffer);
1524 FreePool(SymlinkInformation);
1525 }
1526 }
1527
1528 /* Free all the replicated unique IDs */
1529 while (!IsListEmpty(&(DeviceInformation->ReplicatedUniqueIdsListHead)))
1530 {
1531 NextEntry = RemoveHeadList(&(DeviceInformation->ReplicatedUniqueIdsListHead));
1532 UniqueIdReplicate = CONTAINING_RECORD(NextEntry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
1533
1534
1535 FreePool(UniqueIdReplicate->UniqueId);
1536 FreePool(UniqueIdReplicate);
1537 }
1538
1539 while (!IsListEmpty(&(DeviceInformation->AssociatedDevicesHead)))
1540 {
1541 NextEntry = RemoveHeadList(&(DeviceInformation->AssociatedDevicesHead));
1542 AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
1543
1544 DeviceInformation->NoDatabase = TRUE;
1545 FreePool(AssociatedDevice->String.Buffer);
1546 FreePool(AssociatedDevice);
1547 }
1548
1549 /* Remove device from the device list */
1550 RemoveEntryList(&(DeviceInformation->DeviceListEntry));
1551
1552 /* If there are still devices, check if some were associated with ours */
1553 if (!IsListEmpty(&(DeviceInformation->DeviceListEntry)))
1554 {
1555 for (NextEntry = DeviceExtension->DeviceListHead.Flink;
1556 NextEntry != &(DeviceExtension->DeviceListHead);
1557 NextEntry = NextEntry->Flink)
1558 {
1559 CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1560
1561 /* And then, remove them */
1562 DeviceEntry = CurrentDevice->AssociatedDevicesHead.Flink;
1563 while (DeviceEntry != &(CurrentDevice->AssociatedDevicesHead))
1564 {
1565 AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
1566 DeviceEntry = DeviceEntry->Flink;
1567
1568 if (AssociatedDevice->DeviceInformation != DeviceInformation)
1569 {
1570 continue;
1571 }
1572
1573 RemoveEntryList(&(AssociatedDevice->AssociatedDevicesEntry));
1574 FreePool(AssociatedDevice->String.Buffer);
1575 FreePool(AssociatedDevice);
1576 }
1577 }
1578 }
1579
1580 /* Finally, clean up device name, symbolic name */
1581 FreePool(DeviceInformation->SymbolicName.Buffer);
1582 if (!DeviceInformation->KeepLinks)
1583 {
1584 FreePool(DeviceInformation->UniqueId);
1585 }
1586 FreePool(DeviceInformation->DeviceName.Buffer);
1587
1588 /* Unregister notifications */
1589 if (DeviceInformation->TargetDeviceNotificationEntry)
1590 {
1591 IoUnregisterPlugPlayNotification(DeviceInformation->TargetDeviceNotificationEntry);
1592 }
1593
1594 /* And leave */
1595 FreePool(DeviceInformation);
1596 }
1597 else
1598 {
1599 /* We didn't find device, perhaps because it was offline */
1600 for (NextEntry = DeviceExtension->OfflineDeviceListHead.Flink;
1601 NextEntry != &(DeviceExtension->OfflineDeviceListHead);
1602 NextEntry = NextEntry->Flink)
1603 {
1604 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
1605
1606 /* It was, remove it */
1607 if (RtlCompareUnicodeString(&(DeviceInformation->SymbolicName), DeviceName, TRUE) == 0)
1608 {
1609 RemoveEntryList(&(DeviceInformation->DeviceListEntry));
1610 MountMgrFreeDeadDeviceInfo(DeviceInformation);
1611 break;
1612 }
1613 }
1614 }
1615
1616 /* Release driver */
1617 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
1618 }
1619
1620 /*
1621 * @implemented
1622 */
1623 NTSTATUS
1624 NTAPI
1625 MountMgrMountedDeviceNotification(IN PVOID NotificationStructure,
1626 IN PVOID Context)
1627 {
1628 BOOLEAN OldState;
1629 PDEVICE_EXTENSION DeviceExtension;
1630 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification;
1631
1632 /* Notification for a device arrived */
1633 /* Disable hard errors */
1634 OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
1635 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
1636
1637 DeviceExtension = Context;
1638 Notification = NotificationStructure;
1639
1640 /* Dispatch according to the event */
1641 if (IsEqualGUID(&(Notification->Event), &GUID_DEVICE_INTERFACE_ARRIVAL))
1642 {
1643 MountMgrMountedDeviceArrival(DeviceExtension, Notification->SymbolicLinkName, FALSE);
1644 }
1645 else if (IsEqualGUID(&(Notification->Event), &GUID_DEVICE_INTERFACE_REMOVAL))
1646 {
1647 MountMgrMountedDeviceRemoval(DeviceExtension, Notification->SymbolicLinkName);
1648 }
1649
1650 /* Reset hard errors */
1651 PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
1652
1653 return STATUS_SUCCESS;
1654 }
1655
1656 /*
1657 * @implemented
1658 */
1659 NTSTATUS
1660 NTAPI
1661 MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject,
1662 IN PIRP Irp)
1663 {
1664 PIO_STACK_LOCATION Stack;
1665 NTSTATUS Status = STATUS_SUCCESS;
1666
1667 UNREFERENCED_PARAMETER(DeviceObject);
1668
1669 Stack = IoGetCurrentIrpStackLocation(Irp);
1670
1671 /* Allow driver opening for communication
1672 * as long as it's not taken for a directory
1673 */
1674 if (Stack->MajorFunction == IRP_MJ_CREATE &&
1675 Stack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
1676 {
1677 Status = STATUS_NOT_A_DIRECTORY;
1678 }
1679
1680 Irp->IoStatus.Status = Status;
1681 Irp->IoStatus.Information = 0;
1682 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1683 return Status;
1684 }
1685
1686 /*
1687 * @implemented
1688 */
1689 VOID
1690 NTAPI
1691 MountMgrCancel(IN PDEVICE_OBJECT DeviceObject,
1692 IN PIRP Irp)
1693 {
1694 UNREFERENCED_PARAMETER(DeviceObject);
1695
1696 RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
1697
1698 IoReleaseCancelSpinLock(Irp->CancelIrql);
1699
1700 Irp->IoStatus.Information = 0;
1701 Irp->IoStatus.Status = STATUS_CANCELLED;
1702 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1703 }
1704
1705 /*
1706 * @implemented
1707 */
1708 NTSTATUS
1709 NTAPI
1710 MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject,
1711 IN PIRP Irp)
1712 {
1713 PIRP ListIrp;
1714 KIRQL OldIrql;
1715 PLIST_ENTRY NextEntry;
1716 PFILE_OBJECT FileObject;
1717 PIO_STACK_LOCATION Stack;
1718 PDEVICE_EXTENSION DeviceExtension;
1719
1720 DeviceExtension = DeviceObject->DeviceExtension;
1721 Stack = IoGetCurrentIrpStackLocation(Irp);
1722 FileObject = Stack->FileObject;
1723
1724 IoAcquireCancelSpinLock(&OldIrql);
1725
1726 /* If IRP list if empty, it's OK */
1727 if (IsListEmpty(&(DeviceExtension->IrpListHead)))
1728 {
1729 IoReleaseCancelSpinLock(OldIrql);
1730
1731 Irp->IoStatus.Status = STATUS_SUCCESS;
1732 Irp->IoStatus.Information = 0;
1733 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1734
1735 return STATUS_SUCCESS;
1736 }
1737
1738 /* Otherwise, cancel all the IRPs */
1739 NextEntry = &(DeviceExtension->IrpListHead);
1740 do
1741 {
1742 ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
1743 if (IoGetCurrentIrpStackLocation(ListIrp)->FileObject == FileObject)
1744 {
1745 ListIrp->Cancel = TRUE;
1746 ListIrp->CancelIrql = OldIrql;
1747 ListIrp->CancelRoutine = NULL;
1748 MountMgrCancel(DeviceObject, ListIrp);
1749
1750 IoAcquireCancelSpinLock(&OldIrql);
1751 }
1752
1753 NextEntry = NextEntry->Flink;
1754 }
1755 while (NextEntry != &(DeviceExtension->IrpListHead));
1756
1757 IoReleaseCancelSpinLock(OldIrql);
1758
1759 Irp->IoStatus.Status = STATUS_SUCCESS;
1760 Irp->IoStatus.Information = 0;
1761 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1762
1763 return STATUS_SUCCESS;
1764 }
1765
1766 /*
1767 * @implemented
1768 */
1769 NTSTATUS
1770 NTAPI
1771 MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject,
1772 IN PIRP Irp)
1773 {
1774 PDEVICE_EXTENSION DeviceExtension;
1775
1776 DeviceExtension = DeviceObject->DeviceExtension;
1777
1778 InterlockedExchange(&Unloading, TRUE);
1779
1780 KeInitializeEvent(&UnloadEvent, NotificationEvent, FALSE);
1781
1782 /* Wait for workers */
1783 if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)))
1784 {
1785 KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore),
1786 IO_NO_INCREMENT,
1787 1,
1788 FALSE);
1789 KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
1790 }
1791 else
1792 {
1793 InterlockedDecrement(&(DeviceExtension->WorkerReferences));
1794 }
1795
1796 Irp->IoStatus.Status = STATUS_SUCCESS;
1797 Irp->IoStatus.Information = 0;
1798 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1799
1800 return STATUS_SUCCESS;
1801 }
1802
1803 /* FUNCTIONS ****************************************************************/
1804
1805 INIT_FUNCTION
1806 NTSTATUS
1807 NTAPI
1808 DriverEntry(IN PDRIVER_OBJECT DriverObject,
1809 IN PUNICODE_STRING RegistryPath)
1810 {
1811 NTSTATUS Status;
1812 PDEVICE_OBJECT DeviceObject;
1813 PDEVICE_EXTENSION DeviceExtension;
1814
1815 RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, DatabasePath);
1816
1817 Status = IoCreateDevice(DriverObject,
1818 sizeof(DEVICE_EXTENSION),
1819 &DeviceMount,
1820 FILE_DEVICE_NETWORK,
1821 FILE_DEVICE_SECURE_OPEN,
1822 FALSE,
1823 &DeviceObject);
1824 if (!NT_SUCCESS(Status))
1825 {
1826 return Status;
1827 }
1828
1829 DriverObject->DriverUnload = MountMgrUnload;
1830
1831 DeviceExtension = DeviceObject->DeviceExtension;
1832 RtlZeroMemory(DeviceExtension, sizeof(DEVICE_EXTENSION));
1833 DeviceExtension->DeviceObject = DeviceObject;
1834 DeviceExtension->DriverObject = DriverObject;
1835
1836 InitializeListHead(&(DeviceExtension->DeviceListHead));
1837 InitializeListHead(&(DeviceExtension->OfflineDeviceListHead));
1838
1839 KeInitializeSemaphore(&(DeviceExtension->DeviceLock), 1, 1);
1840 KeInitializeSemaphore(&(DeviceExtension->RemoteDatabaseLock), 1, 1);
1841
1842 InitializeListHead(&(DeviceExtension->IrpListHead));
1843 DeviceExtension->EpicNumber = 1;
1844
1845 InitializeListHead(&(DeviceExtension->SavedLinksListHead));
1846
1847 InitializeListHead(&(DeviceExtension->WorkerQueueListHead));
1848 KeInitializeSemaphore(&(DeviceExtension->WorkerSemaphore), 0, MAXLONG);
1849 DeviceExtension->WorkerReferences = -1;
1850 KeInitializeSpinLock(&(DeviceExtension->WorkerLock));
1851
1852 InitializeListHead(&(DeviceExtension->UniqueIdWorkerItemListHead));
1853 InitializeListHead(&(DeviceExtension->OnlineNotificationListHead));
1854 DeviceExtension->OnlineNotificationCount = 1;
1855
1856 DeviceExtension->RegistryPath.Length = RegistryPath->Length;
1857 DeviceExtension->RegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
1858 DeviceExtension->RegistryPath.Buffer = AllocatePool(DeviceExtension->RegistryPath.MaximumLength);
1859 if (!DeviceExtension->RegistryPath.Buffer)
1860 {
1861 IoDeleteDevice(DeviceObject);
1862 return STATUS_INSUFFICIENT_RESOURCES;
1863 }
1864
1865 RtlCopyUnicodeString(&(DeviceExtension->RegistryPath), RegistryPath);
1866
1867 DeviceExtension->NoAutoMount = MountmgrReadNoAutoMount(&(DeviceExtension->RegistryPath));
1868
1869 GlobalCreateSymbolicLink(&DosDevicesMount, &DeviceMount);
1870
1871 /* Register for device arrival & removal. Ask to be notified for already
1872 * present devices
1873 */
1874 Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
1875 PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
1876 &MountedDevicesGuid,
1877 DriverObject,
1878 MountMgrMountedDeviceNotification,
1879 DeviceExtension,
1880 &(DeviceExtension->NotificationEntry));
1881
1882 if (!NT_SUCCESS(Status))
1883 {
1884 IoDeleteDevice(DeviceObject);
1885 return Status;
1886 }
1887
1888 DriverObject->MajorFunction[IRP_MJ_CREATE] =
1889 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MountMgrCreateClose;
1890 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MountMgrDeviceControl;
1891 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = MountMgrCleanup;
1892 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = MountMgrShutdown;
1893
1894 gdeviceObject = DeviceObject;
1895
1896 Status = IoRegisterShutdownNotification(DeviceObject);
1897 if (!NT_SUCCESS(Status))
1898 {
1899 IoDeleteDevice(DeviceObject);
1900 }
1901
1902 return Status;
1903 }