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