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