1 /* Copyright (c) Mark Harmstone 2016-17
3 * This file is part of WinBtrfs.
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
10 * WinBtrfs 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 Lesser General Public Licence for more details.
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
18 #include "btrfs_drv.h"
32 extern ERESOURCE pdo_list_lock
;
33 extern LIST_ENTRY pdo_list
;
34 extern UNICODE_STRING registry_path
;
35 extern KEVENT mountmgr_thread_event
;
36 extern HANDLE mountmgr_thread_handle
;
37 extern BOOL shutting_down
;
39 typedef void (*pnp_callback
)(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING devpath
);
41 extern PDEVICE_OBJECT master_devobj
;
43 static BOOL
fs_ignored(BTRFS_UUID
* uuid
) {
44 UNICODE_STRING path
, ignoreus
;
47 KEY_VALUE_FULL_INFORMATION
* kvfi
;
48 ULONG dispos
, retlen
, kvfilen
, i
, j
;
52 path
.Length
= path
.MaximumLength
= registry_path
.Length
+ (37 * sizeof(WCHAR
));
54 path
.Buffer
= ExAllocatePoolWithTag(PagedPool
, path
.Length
, ALLOC_TAG
);
56 ERR("out of memory\n");
60 RtlCopyMemory(path
.Buffer
, registry_path
.Buffer
, registry_path
.Length
);
62 i
= registry_path
.Length
/ sizeof(WCHAR
);
64 path
.Buffer
[i
] = '\\';
67 for (j
= 0; j
< 16; j
++) {
68 path
.Buffer
[i
] = hex_digit((uuid
->uuid
[j
] & 0xF0) >> 4);
69 path
.Buffer
[i
+1] = hex_digit(uuid
->uuid
[j
] & 0xF);
73 if (j
== 3 || j
== 5 || j
== 7 || j
== 9) {
79 InitializeObjectAttributes(&oa
, &path
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
81 Status
= ZwCreateKey(&h
, KEY_QUERY_VALUE
, &oa
, 0, NULL
, REG_OPTION_NON_VOLATILE
, &dispos
);
83 if (!NT_SUCCESS(Status
)) {
84 TRACE("ZwCreateKey returned %08x\n", Status
);
85 ExFreePool(path
.Buffer
);
89 RtlInitUnicodeString(&ignoreus
, L
"Ignore");
91 kvfilen
= (ULONG
)offsetof(KEY_VALUE_FULL_INFORMATION
, Name
[0]) + (255 * sizeof(WCHAR
));
92 kvfi
= ExAllocatePoolWithTag(PagedPool
, kvfilen
, ALLOC_TAG
);
94 ERR("out of memory\n");
96 ExFreePool(path
.Buffer
);
100 Status
= ZwQueryValueKey(h
, &ignoreus
, KeyValueFullInformation
, kvfi
, kvfilen
, &retlen
);
101 if (NT_SUCCESS(Status
)) {
102 if (kvfi
->Type
== REG_DWORD
&& kvfi
->DataLength
>= sizeof(UINT32
)) {
103 UINT32
* pr
= (UINT32
*)((UINT8
*)kvfi
+ kvfi
->DataOffset
);
111 ExFreePool(path
.Buffer
);
116 static void test_vol(PDEVICE_OBJECT mountmgr
, PDEVICE_OBJECT DeviceObject
, PUNICODE_STRING devpath
,
117 DWORD disk_num
, DWORD part_num
, UINT64 length
) {
123 TRACE("%.*S\n", devpath
->Length
/ sizeof(WCHAR
), devpath
->Buffer
);
125 sector_size
= DeviceObject
->SectorSize
;
127 if (sector_size
== 0) {
128 DISK_GEOMETRY geometry
;
129 IO_STATUS_BLOCK iosb
;
131 Status
= dev_ioctl(DeviceObject
, IOCTL_DISK_GET_DRIVE_GEOMETRY
, NULL
, 0,
132 &geometry
, sizeof(DISK_GEOMETRY
), TRUE
, &iosb
);
134 if (!NT_SUCCESS(Status
)) {
135 ERR("%.*S had a sector size of 0, and IOCTL_DISK_GET_DRIVE_GEOMETRY returned %08x\n",
136 devpath
->Length
/ sizeof(WCHAR
), devpath
->Buffer
, Status
);
140 if (iosb
.Information
< sizeof(DISK_GEOMETRY
)) {
141 ERR("%.*S: IOCTL_DISK_GET_DRIVE_GEOMETRY returned %u bytes, expected %u\n",
142 devpath
->Length
/ sizeof(WCHAR
), devpath
->Buffer
, iosb
.Information
, sizeof(DISK_GEOMETRY
));
145 sector_size
= geometry
.BytesPerSector
;
147 if (sector_size
== 0) {
148 ERR("%.*S had a sector size of 0\n", devpath
->Length
/ sizeof(WCHAR
), devpath
->Buffer
);
153 toread
= (ULONG
)sector_align(sizeof(superblock
), sector_size
);
154 data
= ExAllocatePoolWithTag(NonPagedPool
, toread
, ALLOC_TAG
);
156 ERR("out of memory\n");
160 Status
= sync_read_phys(DeviceObject
, superblock_addrs
[0], toread
, data
, TRUE
);
162 if (NT_SUCCESS(Status
) && ((superblock
*)data
)->magic
== BTRFS_MAGIC
) {
163 superblock
* sb
= (superblock
*)data
;
164 UINT32 crc32
= ~calc_crc32c(0xffffffff, (UINT8
*)&sb
->uuid
, (ULONG
)sizeof(superblock
) - sizeof(sb
->checksum
));
166 if (crc32
!= *((UINT32
*)sb
->checksum
))
167 ERR("checksum error on superblock\n");
169 TRACE("volume found\n");
171 if (length
>= superblock_addrs
[1] + toread
) {
174 superblock
* sb2
= ExAllocatePoolWithTag(NonPagedPool
, toread
, ALLOC_TAG
);
176 ERR("out of memory\n");
180 while (superblock_addrs
[i
] > 0 && length
>= superblock_addrs
[i
] + toread
) {
181 Status
= sync_read_phys(DeviceObject
, superblock_addrs
[i
], toread
, (PUCHAR
)sb2
, TRUE
);
183 if (NT_SUCCESS(Status
) && sb2
->magic
== BTRFS_MAGIC
) {
184 crc32
= ~calc_crc32c(0xffffffff, (UINT8
*)&sb2
->uuid
, (ULONG
)sizeof(superblock
) - sizeof(sb2
->checksum
));
186 if (crc32
== *((UINT32
*)sb2
->checksum
) && sb2
->generation
> sb
->generation
)
187 RtlCopyMemory(sb
, sb2
, toread
);
196 if (!fs_ignored(&sb
->uuid
)) {
197 DeviceObject
->Flags
&= ~DO_VERIFY_VOLUME
;
198 add_volume_device(sb
, mountmgr
, devpath
, length
, disk_num
, part_num
);
208 NTSTATUS
remove_drive_letter(PDEVICE_OBJECT mountmgr
, PUNICODE_STRING devpath
) {
210 MOUNTMGR_MOUNT_POINT
* mmp
;
212 MOUNTMGR_MOUNT_POINTS mmps1
, *mmps2
;
214 TRACE("removing drive letter\n");
216 mmpsize
= sizeof(MOUNTMGR_MOUNT_POINT
) + devpath
->Length
;
218 mmp
= ExAllocatePoolWithTag(PagedPool
, mmpsize
, ALLOC_TAG
);
220 ERR("out of memory\n");
221 return STATUS_INSUFFICIENT_RESOURCES
;
224 RtlZeroMemory(mmp
, mmpsize
);
226 mmp
->DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINT
);
227 mmp
->DeviceNameLength
= devpath
->Length
;
228 RtlCopyMemory(&mmp
[1], devpath
->Buffer
, devpath
->Length
);
230 Status
= dev_ioctl(mountmgr
, IOCTL_MOUNTMGR_DELETE_POINTS
, mmp
, mmpsize
, &mmps1
, sizeof(MOUNTMGR_MOUNT_POINTS
), FALSE
, NULL
);
232 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
) {
233 ERR("IOCTL_MOUNTMGR_DELETE_POINTS 1 returned %08x\n", Status
);
238 if (Status
!= STATUS_BUFFER_OVERFLOW
|| mmps1
.Size
== 0) {
240 return STATUS_NOT_FOUND
;
243 mmps2
= ExAllocatePoolWithTag(PagedPool
, mmps1
.Size
, ALLOC_TAG
);
245 ERR("out of memory\n");
247 return STATUS_INSUFFICIENT_RESOURCES
;
250 Status
= dev_ioctl(mountmgr
, IOCTL_MOUNTMGR_DELETE_POINTS
, mmp
, mmpsize
, mmps2
, mmps1
.Size
, FALSE
, NULL
);
252 if (!NT_SUCCESS(Status
))
253 ERR("IOCTL_MOUNTMGR_DELETE_POINTS 2 returned %08x\n", Status
);
261 void disk_arrival(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING devpath
) {
262 PFILE_OBJECT FileObject
, mountmgrfo
;
263 PDEVICE_OBJECT devobj
, mountmgr
;
265 STORAGE_DEVICE_NUMBER sdn
;
267 DRIVE_LAYOUT_INFORMATION_EX
* dli
= NULL
;
268 IO_STATUS_BLOCK iosb
;
269 GET_LENGTH_INFORMATION gli
;
270 UNICODE_STRING mmdevpath
;
272 UNUSED(DriverObject
);
274 Status
= IoGetDeviceObjectPointer(devpath
, FILE_READ_ATTRIBUTES
, &FileObject
, &devobj
);
275 if (!NT_SUCCESS(Status
)) {
276 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
280 RtlInitUnicodeString(&mmdevpath
, MOUNTMGR_DEVICE_NAME
);
281 Status
= IoGetDeviceObjectPointer(&mmdevpath
, FILE_READ_ATTRIBUTES
, &mountmgrfo
, &mountmgr
);
282 if (!NT_SUCCESS(Status
)) {
283 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
284 ObDereferenceObject(FileObject
);
296 dli
= ExAllocatePoolWithTag(PagedPool
, dlisize
, ALLOC_TAG
);
298 ERR("out of memory\n");
302 Status
= dev_ioctl(devobj
, IOCTL_DISK_GET_DRIVE_LAYOUT_EX
, NULL
, 0,
303 dli
, dlisize
, TRUE
, &iosb
);
304 } while (Status
== STATUS_BUFFER_TOO_SMALL
);
306 // only consider disk as a potential filesystem if it has no partitions
307 if (NT_SUCCESS(Status
) && dli
->PartitionCount
> 0) {
314 Status
= dev_ioctl(devobj
, IOCTL_DISK_GET_LENGTH_INFO
, NULL
, 0,
315 &gli
, sizeof(gli
), TRUE
, NULL
);
317 if (!NT_SUCCESS(Status
)) {
318 ERR("error reading length information: %08x\n", Status
);
322 Status
= dev_ioctl(devobj
, IOCTL_STORAGE_GET_DEVICE_NUMBER
, NULL
, 0,
323 &sdn
, sizeof(STORAGE_DEVICE_NUMBER
), TRUE
, NULL
);
324 if (!NT_SUCCESS(Status
)) {
325 TRACE("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status
);
326 sdn
.DeviceNumber
= 0xffffffff;
327 sdn
.PartitionNumber
= 0;
329 TRACE("DeviceType = %u, DeviceNumber = %u, PartitionNumber = %u\n", sdn
.DeviceType
, sdn
.DeviceNumber
, sdn
.PartitionNumber
);
331 test_vol(mountmgr
, devobj
, devpath
, sdn
.DeviceNumber
, sdn
.PartitionNumber
, gli
.Length
.QuadPart
);
334 ObDereferenceObject(FileObject
);
335 ObDereferenceObject(mountmgrfo
);
338 void remove_volume_child(_Inout_
_Requires_exclusive_lock_held_(_Curr_
->child_lock
) _Releases_exclusive_lock_(_Curr_
->child_lock
) _In_ volume_device_extension
* vde
,
339 _In_ volume_child
* vc
, _In_ BOOL skip_dev
) {
341 pdo_device_extension
* pdode
= vde
->pdode
;
342 device_extension
* Vcb
= vde
->mounted_device
? vde
->mounted_device
->DeviceExtension
: NULL
;
344 if (vc
->notification_entry
)
346 IoUnregisterPlugPlayNotification(vc
->notification_entry
);
348 IoUnregisterPlugPlayNotificationEx(vc
->notification_entry
);
351 if (vde
->mounted_device
&& (!Vcb
|| !Vcb
->options
.allow_degraded
)) {
352 Status
= pnp_surprise_removal(vde
->mounted_device
, NULL
);
353 if (!NT_SUCCESS(Status
))
354 ERR("pnp_surprise_removal returned %08x\n", Status
);
357 if (!Vcb
|| !Vcb
->options
.allow_degraded
) {
358 Status
= IoSetDeviceInterfaceState(&vde
->bus_name
, FALSE
);
359 if (!NT_SUCCESS(Status
))
360 WARN("IoSetDeviceInterfaceState returned %08x\n", Status
);
363 if (pdode
->children_loaded
> 0) {
364 UNICODE_STRING mmdevpath
;
365 PFILE_OBJECT FileObject
;
366 PDEVICE_OBJECT mountmgr
;
369 if (!Vcb
|| !Vcb
->options
.allow_degraded
) {
370 RtlInitUnicodeString(&mmdevpath
, MOUNTMGR_DEVICE_NAME
);
371 Status
= IoGetDeviceObjectPointer(&mmdevpath
, FILE_READ_ATTRIBUTES
, &FileObject
, &mountmgr
);
372 if (!NT_SUCCESS(Status
))
373 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
375 le
= pdode
->children
.Flink
;
377 while (le
!= &pdode
->children
) {
378 volume_child
* vc2
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
380 if (vc2
->had_drive_letter
) { // re-add entry to mountmgr
383 Status
= dev_ioctl(vc2
->devobj
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
, NULL
, 0, &mdn
, sizeof(MOUNTDEV_NAME
), TRUE
, NULL
);
384 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
)
385 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status
);
388 ULONG mdnsize
= (ULONG
)offsetof(MOUNTDEV_NAME
, Name
[0]) + mdn
.NameLength
;
390 mdn2
= ExAllocatePoolWithTag(PagedPool
, mdnsize
, ALLOC_TAG
);
392 ERR("out of memory\n");
394 Status
= dev_ioctl(vc2
->devobj
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
, NULL
, 0, mdn2
, mdnsize
, TRUE
, NULL
);
395 if (!NT_SUCCESS(Status
))
396 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status
);
400 name
.Buffer
= mdn2
->Name
;
401 name
.Length
= name
.MaximumLength
= mdn2
->NameLength
;
403 Status
= mountmgr_add_drive_letter(mountmgr
, &name
);
404 if (!NT_SUCCESS(Status
))
405 WARN("mountmgr_add_drive_letter returned %08x\n", Status
);
416 ObDereferenceObject(FileObject
);
418 } else if (!skip_dev
) {
419 ExAcquireResourceExclusiveLite(&Vcb
->tree_lock
, TRUE
);
421 le
= Vcb
->devices
.Flink
;
422 while (le
!= &Vcb
->devices
) {
423 device
* dev
= CONTAINING_RECORD(le
, device
, list_entry
);
425 if (dev
->devobj
== vc
->devobj
) {
426 dev
->devobj
= NULL
; // mark as missing
433 ExReleaseResourceLite(&Vcb
->tree_lock
);
436 if (vde
->device
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
437 vde
->device
->Characteristics
&= ~FILE_REMOVABLE_MEDIA
;
439 le
= pdode
->children
.Flink
;
440 while (le
!= &pdode
->children
) {
441 volume_child
* vc2
= CONTAINING_RECORD(le
, volume_child
, list_entry
);
443 if (vc2
!= vc
&& vc2
->devobj
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
444 vde
->device
->Characteristics
|= FILE_REMOVABLE_MEDIA
;
453 ObDereferenceObject(vc
->fileobj
);
454 ExFreePool(vc
->pnp_name
.Buffer
);
455 RemoveEntryList(&vc
->list_entry
);
458 pdode
->children_loaded
--;
460 if (pdode
->children_loaded
== 0) { // remove volume device
463 RemoveEntryList(&pdode
->list_entry
);
465 vde
->removing
= TRUE
;
467 Status
= IoSetDeviceInterfaceState(&vde
->bus_name
, FALSE
);
468 if (!NT_SUCCESS(Status
))
469 WARN("IoSetDeviceInterfaceState returned %08x\n", Status
);
471 if (vde
->pdo
->AttachedDevice
)
472 IoDetachDevice(vde
->pdo
);
474 if (vde
->open_count
== 0)
477 ExReleaseResourceLite(&pdode
->child_lock
);
480 control_device_extension
* cde
= master_devobj
->DeviceExtension
;
482 IoInvalidateDeviceRelations(cde
->buspdo
, BusRelations
);
488 if (vde
->name
.Buffer
)
489 ExFreePool(vde
->name
.Buffer
);
494 ExDeleteResourceLite(&pdode
->child_lock
);
497 IoDeleteDevice(vde
->device
);
503 ExReleaseResourceLite(&pdode
->child_lock
);
506 void volume_arrival(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING devpath
) {
507 STORAGE_DEVICE_NUMBER sdn
;
508 PFILE_OBJECT FileObject
, mountmgrfo
;
509 UNICODE_STRING mmdevpath
;
510 PDEVICE_OBJECT devobj
, mountmgr
;
511 GET_LENGTH_INFORMATION gli
;
514 TRACE("%.*S\n", devpath
->Length
/ sizeof(WCHAR
), devpath
->Buffer
);
516 Status
= IoGetDeviceObjectPointer(devpath
, FILE_READ_ATTRIBUTES
, &FileObject
, &devobj
);
517 if (!NT_SUCCESS(Status
)) {
518 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
522 // make sure we're not processing devices we've created ourselves
524 if (devobj
->DriverObject
== DriverObject
)
527 Status
= dev_ioctl(devobj
, IOCTL_DISK_GET_LENGTH_INFO
, NULL
, 0, &gli
, sizeof(gli
), TRUE
, NULL
);
528 if (!NT_SUCCESS(Status
)) {
529 ERR("IOCTL_DISK_GET_LENGTH_INFO returned %08x\n", Status
);
533 Status
= dev_ioctl(devobj
, IOCTL_STORAGE_GET_DEVICE_NUMBER
, NULL
, 0,
534 &sdn
, sizeof(STORAGE_DEVICE_NUMBER
), TRUE
, NULL
);
535 if (!NT_SUCCESS(Status
)) {
536 TRACE("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status
);
537 sdn
.DeviceNumber
= 0xffffffff;
538 sdn
.PartitionNumber
= 0;
540 TRACE("DeviceType = %u, DeviceNumber = %u, PartitionNumber = %u\n", sdn
.DeviceType
, sdn
.DeviceNumber
, sdn
.PartitionNumber
);
542 // If we've just added a partition to a whole-disk filesystem, unmount it
543 if (sdn
.DeviceNumber
!= 0xffffffff) {
546 ExAcquireResourceExclusiveLite(&pdo_list_lock
, TRUE
);
549 while (le
!= &pdo_list
) {
550 pdo_device_extension
* pdode
= CONTAINING_RECORD(le
, pdo_device_extension
, list_entry
);
552 BOOL changed
= FALSE
;
555 ExAcquireResourceExclusiveLite(&pdode
->child_lock
, TRUE
);
557 le2
= pdode
->children
.Flink
;
558 while (le2
!= &pdode
->children
) {
559 volume_child
* vc
= CONTAINING_RECORD(le2
, volume_child
, list_entry
);
560 LIST_ENTRY
* le3
= le2
->Flink
;
562 if (vc
->disk_num
== sdn
.DeviceNumber
&& vc
->part_num
== 0) {
563 TRACE("removing device\n");
565 remove_volume_child(pdode
->vde
, vc
, FALSE
);
575 ExReleaseResourceLite(&pdode
->child_lock
);
583 ExReleaseResourceLite(&pdo_list_lock
);
586 RtlInitUnicodeString(&mmdevpath
, MOUNTMGR_DEVICE_NAME
);
587 Status
= IoGetDeviceObjectPointer(&mmdevpath
, FILE_READ_ATTRIBUTES
, &mountmgrfo
, &mountmgr
);
588 if (!NT_SUCCESS(Status
)) {
589 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
593 test_vol(mountmgr
, devobj
, devpath
, sdn
.DeviceNumber
, sdn
.PartitionNumber
, gli
.Length
.QuadPart
);
595 ObDereferenceObject(mountmgrfo
);
598 ObDereferenceObject(FileObject
);
601 void volume_removal(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING devpath
) {
603 UNICODE_STRING devpath2
;
605 TRACE("%.*S\n", devpath
->Length
/ sizeof(WCHAR
), devpath
->Buffer
);
607 UNUSED(DriverObject
);
611 if (devpath
->Length
> 4 * sizeof(WCHAR
) && devpath
->Buffer
[0] == '\\' && (devpath
->Buffer
[1] == '\\' || devpath
->Buffer
[1] == '?') &&
612 devpath
->Buffer
[2] == '?' && devpath
->Buffer
[3] == '\\') {
613 devpath2
.Buffer
= &devpath2
.Buffer
[3];
614 devpath2
.Length
-= 3 * sizeof(WCHAR
);
615 devpath2
.MaximumLength
-= 3 * sizeof(WCHAR
);
618 ExAcquireResourceExclusiveLite(&pdo_list_lock
, TRUE
);
621 while (le
!= &pdo_list
) {
622 pdo_device_extension
* pdode
= CONTAINING_RECORD(le
, pdo_device_extension
, list_entry
);
624 BOOL changed
= FALSE
;
627 ExAcquireResourceExclusiveLite(&pdode
->child_lock
, TRUE
);
629 le2
= pdode
->children
.Flink
;
630 while (le2
!= &pdode
->children
) {
631 volume_child
* vc
= CONTAINING_RECORD(le2
, volume_child
, list_entry
);
632 LIST_ENTRY
* le3
= le2
->Flink
;
634 if (vc
->pnp_name
.Length
== devpath2
.Length
&& RtlCompareMemory(vc
->pnp_name
.Buffer
, devpath2
.Buffer
, devpath2
.Length
) == devpath2
.Length
) {
635 TRACE("removing device\n");
637 remove_volume_child(pdode
->vde
, vc
, FALSE
);
647 ExReleaseResourceLite(&pdode
->child_lock
);
655 ExReleaseResourceLite(&pdo_list_lock
);
659 PDRIVER_OBJECT DriverObject
;
662 PIO_WORKITEM work_item
;
663 } pnp_callback_context
;
665 _Function_class_(IO_WORKITEM_ROUTINE
)
667 static void NTAPI
do_pnp_callback(PDEVICE_OBJECT DeviceObject
, PVOID con
) {
669 static void do_pnp_callback(PDEVICE_OBJECT DeviceObject
, PVOID con
) {
671 pnp_callback_context
* context
= con
;
673 UNUSED(DeviceObject
);
675 context
->func(context
->DriverObject
, &context
->name
);
677 if (context
->name
.Buffer
)
678 ExFreePool(context
->name
.Buffer
);
680 IoFreeWorkItem(context
->work_item
);
683 static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING name
, pnp_callback func
) {
684 PIO_WORKITEM work_item
;
685 pnp_callback_context
* context
;
687 work_item
= IoAllocateWorkItem(master_devobj
);
689 context
= ExAllocatePoolWithTag(PagedPool
, sizeof(pnp_callback_context
), ALLOC_TAG
);
692 ERR("out of memory\n");
693 IoFreeWorkItem(work_item
);
697 context
->DriverObject
= DriverObject
;
699 if (name
->Length
> 0) {
700 context
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, name
->Length
, ALLOC_TAG
);
701 if (!context
->name
.Buffer
) {
702 ERR("out of memory\n");
704 IoFreeWorkItem(work_item
);
708 RtlCopyMemory(context
->name
.Buffer
, name
->Buffer
, name
->Length
);
709 context
->name
.Length
= context
->name
.MaximumLength
= name
->Length
;
711 context
->name
.Length
= context
->name
.MaximumLength
= 0;
712 context
->name
.Buffer
= NULL
;
715 context
->func
= func
;
716 context
->work_item
= work_item
;
718 IoQueueWorkItem(work_item
, do_pnp_callback
, DelayedWorkQueue
, context
);
721 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE
)
723 NTSTATUS NTAPI
volume_notification(PVOID NotificationStructure
, PVOID Context
) {
725 NTSTATUS
volume_notification(PVOID NotificationStructure
, PVOID Context
) {
727 DEVICE_INTERFACE_CHANGE_NOTIFICATION
* dicn
= (DEVICE_INTERFACE_CHANGE_NOTIFICATION
*)NotificationStructure
;
728 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Context
;
730 if (RtlCompareMemory(&dicn
->Event
, &GUID_DEVICE_INTERFACE_ARRIVAL
, sizeof(GUID
)) == sizeof(GUID
))
731 enqueue_pnp_callback(DriverObject
, dicn
->SymbolicLinkName
, volume_arrival
);
732 else if (RtlCompareMemory(&dicn
->Event
, &GUID_DEVICE_INTERFACE_REMOVAL
, sizeof(GUID
)) == sizeof(GUID
))
733 enqueue_pnp_callback(DriverObject
, dicn
->SymbolicLinkName
, volume_removal
);
735 return STATUS_SUCCESS
;
738 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE
)
740 NTSTATUS NTAPI
pnp_notification(PVOID NotificationStructure
, PVOID Context
) {
742 NTSTATUS
pnp_notification(PVOID NotificationStructure
, PVOID Context
) {
744 DEVICE_INTERFACE_CHANGE_NOTIFICATION
* dicn
= (DEVICE_INTERFACE_CHANGE_NOTIFICATION
*)NotificationStructure
;
745 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Context
;
747 if (RtlCompareMemory(&dicn
->Event
, &GUID_DEVICE_INTERFACE_ARRIVAL
, sizeof(GUID
)) == sizeof(GUID
))
748 enqueue_pnp_callback(DriverObject
, dicn
->SymbolicLinkName
, disk_arrival
);
749 else if (RtlCompareMemory(&dicn
->Event
, &GUID_DEVICE_INTERFACE_REMOVAL
, sizeof(GUID
)) == sizeof(GUID
))
750 enqueue_pnp_callback(DriverObject
, dicn
->SymbolicLinkName
, volume_removal
);
752 return STATUS_SUCCESS
;
755 static void mountmgr_process_drive(PDEVICE_OBJECT mountmgr
, PUNICODE_STRING device_name
) {
760 ExAcquireResourceSharedLite(&pdo_list_lock
, TRUE
);
763 while (le
!= &pdo_list
) {
764 pdo_device_extension
* pdode
= CONTAINING_RECORD(le
, pdo_device_extension
, list_entry
);
767 ExAcquireResourceSharedLite(&pdode
->child_lock
, TRUE
);
769 le2
= pdode
->children
.Flink
;
771 while (le2
!= &pdode
->children
) {
772 volume_child
* vc
= CONTAINING_RECORD(le2
, volume_child
, list_entry
);
777 Status
= dev_ioctl(vc
->devobj
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
, NULL
, 0, &mdn
, sizeof(MOUNTDEV_NAME
), TRUE
, NULL
);
778 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
)
779 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status
);
782 ULONG mdnsize
= (ULONG
)offsetof(MOUNTDEV_NAME
, Name
[0]) + mdn
.NameLength
;
784 mdn2
= ExAllocatePoolWithTag(NonPagedPool
, mdnsize
, ALLOC_TAG
);
786 ERR("out of memory\n");
788 Status
= dev_ioctl(vc
->devobj
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
, NULL
, 0, mdn2
, mdnsize
, TRUE
, NULL
);
789 if (!NT_SUCCESS(Status
))
790 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status
);
792 if (mdn2
->NameLength
== device_name
->Length
&& RtlCompareMemory(mdn2
->Name
, device_name
->Buffer
, device_name
->Length
) == device_name
->Length
) {
793 Status
= remove_drive_letter(mountmgr
, device_name
);
794 if (!NT_SUCCESS(Status
))
795 ERR("remove_drive_letter returned %08x\n", Status
);
797 vc
->had_drive_letter
= TRUE
;
812 ExReleaseResourceLite(&pdode
->child_lock
);
820 ExReleaseResourceLite(&pdo_list_lock
);
823 static void mountmgr_updated(PDEVICE_OBJECT mountmgr
, MOUNTMGR_MOUNT_POINTS
* mmps
) {
826 static WCHAR pref
[] = L
"\\DosDevices\\";
828 for (i
= 0; i
< mmps
->NumberOfMountPoints
; i
++) {
829 UNICODE_STRING symlink
, device_name
;
831 if (mmps
->MountPoints
[i
].SymbolicLinkNameOffset
!= 0) {
832 symlink
.Buffer
= (WCHAR
*)(((UINT8
*)mmps
) + mmps
->MountPoints
[i
].SymbolicLinkNameOffset
);
833 symlink
.Length
= symlink
.MaximumLength
= mmps
->MountPoints
[i
].SymbolicLinkNameLength
;
835 symlink
.Buffer
= NULL
;
836 symlink
.Length
= symlink
.MaximumLength
= 0;
839 if (mmps
->MountPoints
[i
].DeviceNameOffset
!= 0) {
840 device_name
.Buffer
= (WCHAR
*)(((UINT8
*)mmps
) + mmps
->MountPoints
[i
].DeviceNameOffset
);
841 device_name
.Length
= device_name
.MaximumLength
= mmps
->MountPoints
[i
].DeviceNameLength
;
843 device_name
.Buffer
= NULL
;
844 device_name
.Length
= device_name
.MaximumLength
= 0;
847 if (symlink
.Length
> wcslen(pref
) * sizeof(WCHAR
) &&
848 RtlCompareMemory(symlink
.Buffer
, pref
, wcslen(pref
) * sizeof(WCHAR
)) == wcslen(pref
) * sizeof(WCHAR
))
849 mountmgr_process_drive(mountmgr
, &device_name
);
853 _Function_class_(KSTART_ROUTINE
)
855 void NTAPI
mountmgr_thread(_In_
void* context
) {
857 void mountmgr_thread(_In_
void* context
) {
859 UNICODE_STRING mmdevpath
;
861 PFILE_OBJECT FileObject
;
862 PDEVICE_OBJECT mountmgr
;
863 MOUNTMGR_CHANGE_NOTIFY_INFO mcni
;
867 RtlInitUnicodeString(&mmdevpath
, MOUNTMGR_DEVICE_NAME
);
868 Status
= IoGetDeviceObjectPointer(&mmdevpath
, FILE_READ_ATTRIBUTES
, &FileObject
, &mountmgr
);
869 if (!NT_SUCCESS(Status
)) {
870 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
878 MOUNTMGR_MOUNT_POINT mmp
;
879 MOUNTMGR_MOUNT_POINTS mmps
;
880 IO_STATUS_BLOCK iosb
;
882 KeClearEvent(&mountmgr_thread_event
);
884 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_CHANGE_NOTIFY
, mountmgr
, &mcni
, sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO
),
885 &mcni
, sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO
), FALSE
, &mountmgr_thread_event
, &iosb
);
888 ERR("out of memory\n");
892 Status
= IoCallDriver(mountmgr
, Irp
);
894 if (Status
== STATUS_PENDING
) {
895 KeWaitForSingleObject(&mountmgr_thread_event
, Executive
, KernelMode
, FALSE
, NULL
);
896 Status
= iosb
.Status
;
902 if (!NT_SUCCESS(Status
)) {
903 ERR("IOCTL_MOUNTMGR_CHANGE_NOTIFY returned %08x\n", Status
);
907 TRACE("mountmgr changed\n");
909 RtlZeroMemory(&mmp
, sizeof(MOUNTMGR_MOUNT_POINT
));
911 Status
= dev_ioctl(mountmgr
, IOCTL_MOUNTMGR_QUERY_POINTS
, &mmp
, sizeof(MOUNTMGR_MOUNT_POINT
), &mmps
, sizeof(MOUNTMGR_MOUNT_POINTS
),
914 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
)
915 ERR("IOCTL_MOUNTMGR_QUERY_POINTS 1 returned %08x\n", Status
);
916 else if (mmps
.Size
> 0) {
917 MOUNTMGR_MOUNT_POINTS
* mmps2
;
919 mmps2
= ExAllocatePoolWithTag(NonPagedPool
, mmps
.Size
, ALLOC_TAG
);
921 ERR("out of memory\n");
925 Status
= dev_ioctl(mountmgr
, IOCTL_MOUNTMGR_QUERY_POINTS
, &mmp
, sizeof(MOUNTMGR_MOUNT_POINTS
), mmps2
, mmps
.Size
,
927 if (!NT_SUCCESS(Status
))
928 ERR("IOCTL_MOUNTMGR_QUERY_POINTS returned %08x\n", Status
);
930 mountmgr_updated(mountmgr
, mmps2
);
936 ObDereferenceObject(FileObject
);
938 mountmgr_thread_handle
= NULL
;
940 PsTerminateSystemThread(STATUS_SUCCESS
);