1 /* Copyright (c) Mark Harmstone 2016
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"
33 extern LIST_ENTRY volumes
;
34 extern ERESOURCE volumes_lock
;
35 extern LIST_ENTRY pnp_disks
;
37 static NTSTATUS
create_part0(PDRIVER_OBJECT DriverObject
, PDEVICE_OBJECT DeviceObject
, PUNICODE_STRING devpath
,
38 PUNICODE_STRING nameus
, BTRFS_UUID
* uuid
) {
39 PDEVICE_OBJECT newdevobj
;
42 part0_device_extension
* p0de
;
44 static const WCHAR part0_suffix
[] = L
"Btrfs";
46 name
.Length
= name
.MaximumLength
= devpath
->Length
+ (wcslen(part0_suffix
) * sizeof(WCHAR
));
47 name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, name
.Length
, ALLOC_TAG
);
49 ERR("out of memory\n");
50 return STATUS_INSUFFICIENT_RESOURCES
;
53 RtlCopyMemory(name
.Buffer
, devpath
->Buffer
, devpath
->Length
);
54 RtlCopyMemory(&name
.Buffer
[devpath
->Length
/ sizeof(WCHAR
)], part0_suffix
, wcslen(part0_suffix
) * sizeof(WCHAR
));
56 Status
= IoCreateDevice(DriverObject
, sizeof(part0_device_extension
), &name
, FILE_DEVICE_DISK
, FILE_DEVICE_SECURE_OPEN
, FALSE
, &newdevobj
);
57 if (!NT_SUCCESS(Status
)) {
58 ERR("IoCreateDevice returned %08x\n", Status
);
59 ExFreePool(name
.Buffer
);
63 p0de
= newdevobj
->DeviceExtension
;
64 p0de
->type
= VCB_TYPE_PARTITION0
;
65 p0de
->devobj
= DeviceObject
;
66 RtlCopyMemory(&p0de
->uuid
, uuid
, sizeof(BTRFS_UUID
));
68 p0de
->name
.Length
= name
.Length
;
69 p0de
->name
.MaximumLength
= name
.MaximumLength
;
70 p0de
->name
.Buffer
= ExAllocatePoolWithTag(PagedPool
, p0de
->name
.MaximumLength
, ALLOC_TAG
);
72 if (!p0de
->name
.Buffer
) {
73 ERR("out of memory\b");
74 ExFreePool(name
.Buffer
);
75 ExFreePool(p0de
->name
.Buffer
);
76 IoDeleteDevice(newdevobj
);
77 return STATUS_INSUFFICIENT_RESOURCES
;
80 RtlCopyMemory(p0de
->name
.Buffer
, name
.Buffer
, name
.Length
);
82 ObReferenceObject(DeviceObject
);
84 newdevobj
->StackSize
= DeviceObject
->StackSize
+ 1;
85 newdevobj
->SectorSize
= DeviceObject
->SectorSize
;
87 newdevobj
->Flags
|= DO_DIRECT_IO
;
88 newdevobj
->Flags
&= ~DO_DEVICE_INITIALIZING
;
92 return STATUS_SUCCESS
;
95 void add_volume(PDEVICE_OBJECT mountmgr
, PUNICODE_STRING us
) {
97 MOUNTMGR_TARGET_NAME
* tn
;
99 IO_STATUS_BLOCK IoStatusBlock
;
103 MOUNTMGR_DRIVE_LETTER_TARGET
* mmdlt
;
104 MOUNTMGR_DRIVE_LETTER_INFORMATION mmdli
;
106 TRACE("found BTRFS volume\n");
108 tnsize
= sizeof(MOUNTMGR_TARGET_NAME
) - sizeof(WCHAR
) + us
->Length
;
109 tn
= ExAllocatePoolWithTag(NonPagedPool
, tnsize
, ALLOC_TAG
);
111 ERR("out of memory\n");
115 tn
->DeviceNameLength
= us
->Length
;
116 RtlCopyMemory(tn
->DeviceName
, us
->Buffer
, tn
->DeviceNameLength
);
118 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
119 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION
,
120 mountmgr
, tn
, tnsize
,
121 NULL
, 0, FALSE
, &Event
, &IoStatusBlock
);
123 ERR("%.*S: IoBuildDeviceIoControlRequest 1 failed\n", us
->Length
/ sizeof(WCHAR
), us
->Buffer
);
128 Status
= IoCallDriver(mountmgr
, Irp
);
129 if (Status
== STATUS_PENDING
) {
130 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
131 Status
= IoStatusBlock
.Status
;
134 if (!NT_SUCCESS(Status
)) {
135 ERR("%.*S: IoCallDriver 1 returned %08x\n", us
->Length
/ sizeof(WCHAR
), us
->Buffer
, Status
);
141 mmdltsize
= offsetof(MOUNTMGR_DRIVE_LETTER_TARGET
, DeviceName
[0]) + us
->Length
;
143 mmdlt
= ExAllocatePoolWithTag(NonPagedPool
, mmdltsize
, ALLOC_TAG
);
145 ERR("out of memory\n");
149 mmdlt
->DeviceNameLength
= us
->Length
;
150 RtlCopyMemory(&mmdlt
->DeviceName
, us
->Buffer
, us
->Length
);
151 TRACE("mmdlt = %.*S\n", mmdlt
->DeviceNameLength
/ sizeof(WCHAR
), mmdlt
->DeviceName
);
153 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
154 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER
,
155 mountmgr
, mmdlt
, mmdltsize
,
156 &mmdli
, sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION
), FALSE
, &Event
, &IoStatusBlock
);
158 ERR("%.*S: IoBuildDeviceIoControlRequest 2 failed\n", us
->Length
/ sizeof(WCHAR
), us
->Buffer
);
162 Status
= IoCallDriver(mountmgr
, Irp
);
163 if (Status
== STATUS_PENDING
) {
164 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
165 Status
= IoStatusBlock
.Status
;
168 if (!NT_SUCCESS(Status
)) {
169 ERR("%.*S: IoCallDriver 2 returned %08x\n", us
->Length
/ sizeof(WCHAR
), us
->Buffer
, Status
);
171 TRACE("DriveLetterWasAssigned = %u, CurrentDriveLetter = %c\n", mmdli
.DriveLetterWasAssigned
, mmdli
.CurrentDriveLetter
);
176 static void STDCALL
test_vol(PDRIVER_OBJECT DriverObject
, PDEVICE_OBJECT mountmgr
, PUNICODE_STRING devpath
, DWORD disk_num
, DWORD part_num
, LIST_ENTRY
* volumes
) {
179 IO_STATUS_BLOCK IoStatusBlock
;
181 PFILE_OBJECT FileObject
;
182 PDEVICE_OBJECT DeviceObject
;
183 LARGE_INTEGER Offset
;
188 TRACE("%.*S\n", devpath
->Length
/ sizeof(WCHAR
), devpath
->Buffer
);
190 Status
= IoGetDeviceObjectPointer(devpath
, FILE_READ_ATTRIBUTES
, &FileObject
, &DeviceObject
);
191 if (!NT_SUCCESS(Status
)) {
192 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
196 sector_size
= DeviceObject
->SectorSize
;
198 if (sector_size
== 0) {
199 DISK_GEOMETRY geometry
;
200 IO_STATUS_BLOCK iosb
;
202 Status
= dev_ioctl(DeviceObject
, IOCTL_DISK_GET_DRIVE_GEOMETRY
, NULL
, 0,
203 &geometry
, sizeof(DISK_GEOMETRY
), TRUE
, &iosb
);
205 if (!NT_SUCCESS(Status
)) {
206 ERR("%.*S had a sector size of 0, and IOCTL_DISK_GET_DRIVE_GEOMETRY returned %08x\n",
207 devpath
->Length
/ sizeof(WCHAR
), devpath
->Buffer
, Status
);
211 if (iosb
.Information
< sizeof(DISK_GEOMETRY
)) {
212 ERR("%.*S: IOCTL_DISK_GET_DRIVE_GEOMETRY returned %u bytes, expected %u\n",
213 devpath
->Length
/ sizeof(WCHAR
), devpath
->Buffer
, iosb
.Information
, sizeof(DISK_GEOMETRY
));
216 sector_size
= geometry
.BytesPerSector
;
218 if (sector_size
== 0) {
219 ERR("%.*S had a sector size of 0\n", devpath
->Length
/ sizeof(WCHAR
), devpath
->Buffer
);
224 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
226 Offset
.QuadPart
= superblock_addrs
[0];
228 toread
= sector_align(sizeof(superblock
), sector_size
);
229 data
= ExAllocatePoolWithTag(NonPagedPool
, toread
, ALLOC_TAG
);
231 ERR("out of memory\n");
235 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
, DeviceObject
, data
, toread
, &Offset
, &Event
, &IoStatusBlock
);
238 ERR("IoBuildSynchronousFsdRequest failed\n");
242 Status
= IoCallDriver(DeviceObject
, Irp
);
244 if (Status
== STATUS_PENDING
) {
245 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
246 Status
= IoStatusBlock
.Status
;
249 if (NT_SUCCESS(Status
) && IoStatusBlock
.Information
> 0 && ((superblock
*)data
)->magic
== BTRFS_MAGIC
) {
251 GET_LENGTH_INFORMATION gli
;
252 superblock
* sb
= (superblock
*)data
;
253 volume
* v
= ExAllocatePoolWithTag(PagedPool
, sizeof(volume
), ALLOC_TAG
);
256 ERR("out of memory\n");
260 Status
= dev_ioctl(DeviceObject
, IOCTL_DISK_GET_LENGTH_INFO
, NULL
, 0,
261 &gli
, sizeof(gli
), TRUE
, NULL
);
262 if (!NT_SUCCESS(Status
)) {
263 ERR("error reading length information: %08x\n", Status
);
271 Status
= create_part0(DriverObject
, DeviceObject
, devpath
, &us3
, &sb
->dev_item
.device_uuid
);
273 if (!NT_SUCCESS(Status
)) {
274 ERR("create_part0 returned %08x\n", Status
);
281 v
->devpath
.Length
= v
->devpath
.MaximumLength
= devpath
->Length
;
282 v
->devpath
.Buffer
= ExAllocatePoolWithTag(PagedPool
, v
->devpath
.Length
, ALLOC_TAG
);
284 if (!v
->devpath
.Buffer
) {
285 ERR("out of memory\n");
290 RtlCopyMemory(v
->devpath
.Buffer
, devpath
->Buffer
, v
->devpath
.Length
);
293 RtlCopyMemory(&v
->fsuuid
, &sb
->uuid
, sizeof(BTRFS_UUID
));
294 RtlCopyMemory(&v
->devuuid
, &sb
->dev_item
.device_uuid
, sizeof(BTRFS_UUID
));
295 v
->devnum
= sb
->dev_item
.dev_id
;
296 v
->processed
= FALSE
;
297 v
->length
= gli
.Length
.QuadPart
;
298 v
->gen1
= sb
->generation
;
300 v
->seeding
= sb
->flags
& BTRFS_SUPERBLOCK_FLAGS_SEEDING
? TRUE
: FALSE
;
301 v
->disk_num
= disk_num
;
302 v
->part_num
= part_num
;
304 ExAcquireResourceExclusiveLite(&volumes_lock
, TRUE
);
305 InsertTailList(volumes
, &v
->list_entry
);
306 ExReleaseResourceLite(&volumes_lock
);
309 while (superblock_addrs
[i
] != 0 && superblock_addrs
[i
] + toread
<= v
->length
) {
310 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
312 Offset
.QuadPart
= superblock_addrs
[i
];
314 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
, DeviceObject
, data
, toread
, &Offset
, &Event
, &IoStatusBlock
);
317 ERR("IoBuildSynchronousFsdRequest failed\n");
321 Status
= IoCallDriver(DeviceObject
, Irp
);
323 if (Status
== STATUS_PENDING
) {
324 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
325 Status
= IoStatusBlock
.Status
;
328 if (NT_SUCCESS(Status
)) {
329 UINT32 crc32
= ~calc_crc32c(0xffffffff, (UINT8
*)&sb
->uuid
, (ULONG
)sizeof(superblock
) - sizeof(sb
->checksum
));
331 if (crc32
!= *((UINT32
*)sb
->checksum
))
332 WARN("superblock %u CRC error\n", i
);
333 else if (sb
->generation
> v
->gen1
) {
335 v
->gen1
= sb
->generation
;
338 ERR("got error %08x while reading superblock %u\n", Status
, i
);
344 TRACE("volume found\n");
345 TRACE("gen1 = %llx, gen2 = %llx\n", v
->gen1
, v
->gen2
);
346 TRACE("FS uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
347 v
->fsuuid
.uuid
[0], v
->fsuuid
.uuid
[1], v
->fsuuid
.uuid
[2], v
->fsuuid
.uuid
[3], v
->fsuuid
.uuid
[4], v
->fsuuid
.uuid
[5], v
->fsuuid
.uuid
[6], v
->fsuuid
.uuid
[7],
348 v
->fsuuid
.uuid
[8], v
->fsuuid
.uuid
[9], v
->fsuuid
.uuid
[10], v
->fsuuid
.uuid
[11], v
->fsuuid
.uuid
[12], v
->fsuuid
.uuid
[13], v
->fsuuid
.uuid
[14], v
->fsuuid
.uuid
[15]);
349 TRACE("device uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
350 v
->devuuid
.uuid
[0], v
->devuuid
.uuid
[1], v
->devuuid
.uuid
[2], v
->devuuid
.uuid
[3], v
->devuuid
.uuid
[4], v
->devuuid
.uuid
[5], v
->devuuid
.uuid
[6], v
->devuuid
.uuid
[7],
351 v
->devuuid
.uuid
[8], v
->devuuid
.uuid
[9], v
->devuuid
.uuid
[10], v
->devuuid
.uuid
[11], v
->devuuid
.uuid
[12], v
->devuuid
.uuid
[13], v
->devuuid
.uuid
[14], v
->devuuid
.uuid
[15]);
352 TRACE("device number %llx\n", v
->devnum
);
359 ObDereferenceObject(FileObject
);
362 void remove_drive_letter(PDEVICE_OBJECT mountmgr
, volume
* v
) {
366 MOUNTMGR_MOUNT_POINT
* mmp
;
368 MOUNTMGR_MOUNT_POINTS mmps1
, *mmps2
;
369 IO_STATUS_BLOCK IoStatusBlock
;
371 mmpsize
= sizeof(MOUNTMGR_MOUNT_POINT
) + v
->devpath
.Length
;
373 mmp
= ExAllocatePoolWithTag(PagedPool
, mmpsize
, ALLOC_TAG
);
375 ERR("out of memory\n");
379 RtlZeroMemory(mmp
, mmpsize
);
381 mmp
->DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINT
);
382 mmp
->DeviceNameLength
= v
->devpath
.Length
;
383 RtlCopyMemory(&mmp
[1], v
->devpath
.Buffer
, v
->devpath
.Length
);
385 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
386 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS
,
387 mountmgr
, mmp
, mmpsize
,
388 &mmps1
, sizeof(MOUNTMGR_MOUNT_POINTS
), FALSE
, &Event
, &IoStatusBlock
);
390 ERR("%.*S: IoBuildDeviceIoControlRequest 1 failed\n", v
->devpath
.Length
/ sizeof(WCHAR
), v
->devpath
.Buffer
);
395 Status
= IoCallDriver(mountmgr
, Irp
);
396 if (Status
== STATUS_PENDING
) {
397 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
398 Status
= IoStatusBlock
.Status
;
401 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
) {
402 ERR("%.*S: IoCallDriver 1 returned %08x\n", v
->devpath
.Length
/ sizeof(WCHAR
), v
->devpath
.Buffer
, Status
);
407 if (Status
!= STATUS_BUFFER_OVERFLOW
|| mmps1
.Size
== 0) {
412 mmps2
= ExAllocatePoolWithTag(PagedPool
, mmps1
.Size
, ALLOC_TAG
);
414 ERR("out of memory\n");
419 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
420 Irp
= IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS
,
421 mountmgr
, mmp
, mmpsize
,
422 mmps2
, mmps1
.Size
, FALSE
, &Event
, &IoStatusBlock
);
424 ERR("%.*S: IoBuildDeviceIoControlRequest 2 failed\n", v
->devpath
.Length
/ sizeof(WCHAR
), v
->devpath
.Buffer
);
430 Status
= IoCallDriver(mountmgr
, Irp
);
431 if (Status
== STATUS_PENDING
) {
432 KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, NULL
);
433 Status
= IoStatusBlock
.Status
;
436 if (!NT_SUCCESS(Status
)) {
437 ERR("%.*S: IoCallDriver 2 returned %08x\n", v
->devpath
.Length
/ sizeof(WCHAR
), v
->devpath
.Buffer
, Status
);
447 static void refresh_mountmgr(PDEVICE_OBJECT mountmgr
, LIST_ENTRY
* volumes
) {
450 ExAcquireResourceExclusiveLite(&volumes_lock
, TRUE
);
453 while (le
!= volumes
) {
454 volume
* v
= CONTAINING_RECORD(le
, volume
, list_entry
);
457 LIST_ENTRY
* le2
= le
;
458 volume
* mountvol
= v
;
460 while (le2
!= volumes
) {
461 volume
* v2
= CONTAINING_RECORD(le2
, volume
, list_entry
);
463 if (RtlCompareMemory(&v2
->fsuuid
, &v
->fsuuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
464 v2
->processed
= TRUE
;
466 if (v2
->devnum
< mountvol
->devnum
) {
467 remove_drive_letter(mountmgr
, mountvol
);
469 } else if (v2
->devnum
> mountvol
->devnum
)
470 remove_drive_letter(mountmgr
, v2
);
476 add_volume(mountmgr
, &mountvol
->devpath
);
482 ExReleaseResourceLite(&volumes_lock
);
485 static void add_pnp_disk(ULONG disk_num
, PUNICODE_STRING devpath
) {
489 le
= pnp_disks
.Flink
;
490 while (le
!= &pnp_disks
) {
491 disk
= CONTAINING_RECORD(le
, pnp_disk
, list_entry
);
493 if (disk
->devpath
.Length
== devpath
->Length
&&
494 RtlCompareMemory(disk
->devpath
.Buffer
, devpath
->Buffer
, devpath
->Length
) == devpath
->Length
)
500 disk
= ExAllocatePoolWithTag(PagedPool
, sizeof(pnp_disk
), ALLOC_TAG
);
502 ERR("out of memory\n");
506 disk
->devpath
.Length
= disk
->devpath
.MaximumLength
= devpath
->Length
;
507 disk
->devpath
.Buffer
= ExAllocatePoolWithTag(PagedPool
, devpath
->Length
, ALLOC_TAG
);
509 if (!disk
->devpath
.Buffer
) {
510 ERR("out of memory\n");
515 RtlCopyMemory(disk
->devpath
.Buffer
, devpath
->Buffer
, devpath
->Length
);
517 disk
->disk_num
= disk_num
;
519 InsertTailList(&pnp_disks
, &disk
->list_entry
);
522 static void disk_arrival(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING devpath
) {
523 PFILE_OBJECT FileObject
, FileObject2
;
524 PDEVICE_OBJECT devobj
, mountmgr
;
526 STORAGE_DEVICE_NUMBER sdn
;
528 DRIVE_LAYOUT_INFORMATION_EX
* dli
;
529 IO_STATUS_BLOCK iosb
;
530 int i
, num_parts
= 0;
531 UNICODE_STRING devname
, num
, bspus
, mmdevpath
;
532 WCHAR devnamew
[255], numw
[20];
535 static WCHAR device_harddisk
[] = L
"\\Device\\Harddisk";
536 static WCHAR bs_partition
[] = L
"\\Partition";
538 // FIXME - work with CD-ROMs and floppies(?)
540 Status
= IoGetDeviceObjectPointer(devpath
, FILE_READ_ATTRIBUTES
, &FileObject
, &devobj
);
541 if (!NT_SUCCESS(Status
)) {
542 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
546 RtlInitUnicodeString(&mmdevpath
, MOUNTMGR_DEVICE_NAME
);
547 Status
= IoGetDeviceObjectPointer(&mmdevpath
, FILE_READ_ATTRIBUTES
, &FileObject2
, &mountmgr
);
548 if (!NT_SUCCESS(Status
)) {
549 ERR("IoGetDeviceObjectPointer returned %08x\n", Status
);
550 ObDereferenceObject(FileObject
);
554 Status
= dev_ioctl(devobj
, IOCTL_STORAGE_GET_DEVICE_NUMBER
, NULL
, 0,
555 &sdn
, sizeof(STORAGE_DEVICE_NUMBER
), TRUE
, &iosb
);
556 if (!NT_SUCCESS(Status
)) {
557 ERR("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status
);
561 ExAcquireResourceExclusiveLite(&volumes_lock
, TRUE
);
562 add_pnp_disk(sdn
.DeviceNumber
, devpath
);
563 ExReleaseResourceLite(&volumes_lock
);
569 dli
= ExAllocatePoolWithTag(PagedPool
, dlisize
, ALLOC_TAG
);
571 Status
= dev_ioctl(devobj
, IOCTL_DISK_GET_DRIVE_LAYOUT_EX
, NULL
, 0,
572 dli
, dlisize
, TRUE
, &iosb
);
573 } while (Status
== STATUS_BUFFER_TOO_SMALL
);
575 if (!NT_SUCCESS(Status
)) {
580 wcscpy(devnamew
, device_harddisk
);
581 devname
.Buffer
= devnamew
;
582 devname
.MaximumLength
= sizeof(devnamew
);
583 devname
.Length
= wcslen(device_harddisk
) * sizeof(WCHAR
);
586 num
.MaximumLength
= sizeof(numw
);
587 RtlIntegerToUnicodeString(sdn
.DeviceNumber
, 10, &num
);
588 RtlAppendUnicodeStringToString(&devname
, &num
);
590 bspus
.Buffer
= bs_partition
;
591 bspus
.Length
= bspus
.MaximumLength
= wcslen(bs_partition
) * sizeof(WCHAR
);
592 RtlAppendUnicodeStringToString(&devname
, &bspus
);
594 preflen
= devname
.Length
;
596 for (i
= 0; i
< dli
->PartitionCount
; i
++) {
597 if (dli
->PartitionEntry
[i
].PartitionLength
.QuadPart
!= 0 && dli
->PartitionEntry
[i
].PartitionNumber
!= 0) {
598 devname
.Length
= preflen
;
599 RtlIntegerToUnicodeString(dli
->PartitionEntry
[i
].PartitionNumber
, 10, &num
);
600 RtlAppendUnicodeStringToString(&devname
, &num
);
602 test_vol(DriverObject
, mountmgr
, &devname
, sdn
.DeviceNumber
, dli
->PartitionEntry
[i
].PartitionNumber
, &volumes
);
611 if (num_parts
== 0) {
612 devname
.Length
= preflen
;
613 devname
.Buffer
[devname
.Length
/ sizeof(WCHAR
)] = '0';
614 devname
.Length
+= sizeof(WCHAR
);
616 test_vol(DriverObject
, mountmgr
, &devname
, sdn
.DeviceNumber
, 0, &volumes
);
620 refresh_mountmgr(mountmgr
, &volumes
);
622 ObDereferenceObject(FileObject
);
623 ObDereferenceObject(FileObject2
);
626 static void disk_removal(PDRIVER_OBJECT DriverObject
, PUNICODE_STRING devpath
) {
628 pnp_disk
* disk
= NULL
;
630 // FIXME - remove Partition0Btrfs devices and unlink from mountmgr
631 // FIXME - emergency unmount of RAIDed volumes
633 ExAcquireResourceExclusiveLite(&volumes_lock
, TRUE
);
635 le
= pnp_disks
.Flink
;
636 while (le
!= &pnp_disks
) {
637 pnp_disk
* disk2
= CONTAINING_RECORD(le
, pnp_disk
, list_entry
);
639 if (disk2
->devpath
.Length
== devpath
->Length
&&
640 RtlCompareMemory(disk2
->devpath
.Buffer
, devpath
->Buffer
, devpath
->Length
) == devpath
->Length
) {
649 ExReleaseResourceLite(&volumes_lock
);
654 while (le
!= &volumes
) {
655 volume
* v
= CONTAINING_RECORD(le
, volume
, list_entry
);
656 LIST_ENTRY
* le2
= le
->Flink
;
658 if (v
->disk_num
== disk
->disk_num
) {
659 if (v
->devpath
.Buffer
)
660 ExFreePool(v
->devpath
.Buffer
);
662 RemoveEntryList(&v
->list_entry
);
670 ExReleaseResourceLite(&volumes_lock
);
672 ExFreePool(disk
->devpath
.Buffer
);
674 RemoveEntryList(&disk
->list_entry
);
680 NTSTATUS NTAPI
pnp_notification(PVOID NotificationStructure
, PVOID Context
) {
682 NTSTATUS
pnp_notification(PVOID NotificationStructure
, PVOID Context
) {
684 DEVICE_INTERFACE_CHANGE_NOTIFICATION
* dicn
= (DEVICE_INTERFACE_CHANGE_NOTIFICATION
*)NotificationStructure
;
685 PDRIVER_OBJECT DriverObject
= (PDRIVER_OBJECT
)Context
;
687 if (RtlCompareMemory(&dicn
->Event
, &GUID_DEVICE_INTERFACE_ARRIVAL
, sizeof(GUID
)) == sizeof(GUID
))
688 disk_arrival(DriverObject
, dicn
->SymbolicLinkName
);
689 else if (RtlCompareMemory(&dicn
->Event
, &GUID_DEVICE_INTERFACE_REMOVAL
, sizeof(GUID
)) == sizeof(GUID
))
690 disk_removal(DriverObject
, dicn
->SymbolicLinkName
);
692 return STATUS_SUCCESS
;