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