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