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