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