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