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