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