1 /* Copyright (c) Mark Harmstone 2016-17 2 * 3 * This file is part of WinBtrfs. 4 * 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. 9 * 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. 14 * 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/>. */ 17 18 #include "btrfs_drv.h" 19 20 #ifndef __REACTOS__ 21 #include <ntddk.h> 22 #include <ntifs.h> 23 #include <mountmgr.h> 24 #include <windef.h> 25 #endif 26 #include <ntddstor.h> 27 #include <ntdddisk.h> 28 29 #include <initguid.h> 30 #include <wdmguid.h> 31 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; 38 39 typedef void (*pnp_callback)(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath); 40 41 extern PDEVICE_OBJECT master_devobj; 42 43 static BOOL fs_ignored(BTRFS_UUID* uuid) { 44 UNICODE_STRING path, ignoreus; 45 NTSTATUS Status; 46 OBJECT_ATTRIBUTES oa; 47 KEY_VALUE_FULL_INFORMATION* kvfi; 48 ULONG dispos, retlen, kvfilen, i, j; 49 HANDLE h; 50 BOOL ret = FALSE; 51 52 path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR)); 53 54 path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG); 55 if (!path.Buffer) { 56 ERR("out of memory\n"); 57 return FALSE; 58 } 59 60 RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length); 61 62 i = registry_path.Length / sizeof(WCHAR); 63 64 path.Buffer[i] = '\\'; 65 i++; 66 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); 70 71 i += 2; 72 73 if (j == 3 || j == 5 || j == 7 || j == 9) { 74 path.Buffer[i] = '-'; 75 i++; 76 } 77 } 78 79 InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); 80 81 Status = ZwCreateKey(&h, KEY_QUERY_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos); 82 83 if (!NT_SUCCESS(Status)) { 84 TRACE("ZwCreateKey returned %08x\n", Status); 85 ExFreePool(path.Buffer); 86 return FALSE; 87 } 88 89 RtlInitUnicodeString(&ignoreus, L"Ignore"); 90 91 kvfilen = (ULONG)offsetof(KEY_VALUE_FULL_INFORMATION, Name[0]) + (255 * sizeof(WCHAR)); 92 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG); 93 if (!kvfi) { 94 ERR("out of memory\n"); 95 ZwClose(h); 96 ExFreePool(path.Buffer); 97 return FALSE; 98 } 99 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); 104 105 ret = *pr; 106 } 107 } 108 109 ZwClose(h); 110 ExFreePool(kvfi); 111 ExFreePool(path.Buffer); 112 113 return ret; 114 } 115 116 static void test_vol(PDEVICE_OBJECT mountmgr, PDEVICE_OBJECT DeviceObject, PUNICODE_STRING devpath, 117 DWORD disk_num, DWORD part_num, UINT64 length) { 118 NTSTATUS Status; 119 ULONG toread; 120 UINT8* data = NULL; 121 UINT32 sector_size; 122 123 TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer); 124 125 sector_size = DeviceObject->SectorSize; 126 127 if (sector_size == 0) { 128 DISK_GEOMETRY geometry; 129 IO_STATUS_BLOCK iosb; 130 131 Status = dev_ioctl(DeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, 132 &geometry, sizeof(DISK_GEOMETRY), TRUE, &iosb); 133 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); 137 goto deref; 138 } 139 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)); 143 } 144 145 sector_size = geometry.BytesPerSector; 146 147 if (sector_size == 0) { 148 ERR("%.*S had a sector size of 0\n", devpath->Length / sizeof(WCHAR), devpath->Buffer); 149 goto deref; 150 } 151 } 152 153 toread = (ULONG)sector_align(sizeof(superblock), sector_size); 154 data = ExAllocatePoolWithTag(NonPagedPool, toread, ALLOC_TAG); 155 if (!data) { 156 ERR("out of memory\n"); 157 goto deref; 158 } 159 160 Status = sync_read_phys(DeviceObject, superblock_addrs[0], toread, data, TRUE); 161 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)); 165 166 if (crc32 != *((UINT32*)sb->checksum)) 167 ERR("checksum error on superblock\n"); 168 else { 169 TRACE("volume found\n"); 170 171 if (length >= superblock_addrs[1] + toread) { 172 ULONG i = 1; 173 174 superblock* sb2 = ExAllocatePoolWithTag(NonPagedPool, toread, ALLOC_TAG); 175 if (!sb2) { 176 ERR("out of memory\n"); 177 goto deref; 178 } 179 180 while (superblock_addrs[i] > 0 && length >= superblock_addrs[i] + toread) { 181 Status = sync_read_phys(DeviceObject, superblock_addrs[i], toread, (PUCHAR)sb2, TRUE); 182 183 if (NT_SUCCESS(Status) && sb2->magic == BTRFS_MAGIC) { 184 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb2->uuid, (ULONG)sizeof(superblock) - sizeof(sb2->checksum)); 185 186 if (crc32 == *((UINT32*)sb2->checksum) && sb2->generation > sb->generation) 187 RtlCopyMemory(sb, sb2, toread); 188 } 189 190 i++; 191 } 192 193 ExFreePool(sb2); 194 } 195 196 if (!fs_ignored(&sb->uuid)) { 197 DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 198 add_volume_device(sb, mountmgr, devpath, length, disk_num, part_num); 199 } 200 } 201 } 202 203 deref: 204 if (data) 205 ExFreePool(data); 206 } 207 208 NTSTATUS remove_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath) { 209 NTSTATUS Status; 210 MOUNTMGR_MOUNT_POINT* mmp; 211 ULONG mmpsize; 212 MOUNTMGR_MOUNT_POINTS mmps1, *mmps2; 213 214 TRACE("removing drive letter\n"); 215 216 mmpsize = sizeof(MOUNTMGR_MOUNT_POINT) + devpath->Length; 217 218 mmp = ExAllocatePoolWithTag(PagedPool, mmpsize, ALLOC_TAG); 219 if (!mmp) { 220 ERR("out of memory\n"); 221 return STATUS_INSUFFICIENT_RESOURCES; 222 } 223 224 RtlZeroMemory(mmp, mmpsize); 225 226 mmp->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); 227 mmp->DeviceNameLength = devpath->Length; 228 RtlCopyMemory(&mmp[1], devpath->Buffer, devpath->Length); 229 230 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_DELETE_POINTS, mmp, mmpsize, &mmps1, sizeof(MOUNTMGR_MOUNT_POINTS), FALSE, NULL); 231 232 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { 233 ERR("IOCTL_MOUNTMGR_DELETE_POINTS 1 returned %08x\n", Status); 234 ExFreePool(mmp); 235 return Status; 236 } 237 238 if (Status != STATUS_BUFFER_OVERFLOW || mmps1.Size == 0) { 239 ExFreePool(mmp); 240 return STATUS_NOT_FOUND; 241 } 242 243 mmps2 = ExAllocatePoolWithTag(PagedPool, mmps1.Size, ALLOC_TAG); 244 if (!mmps2) { 245 ERR("out of memory\n"); 246 ExFreePool(mmp); 247 return STATUS_INSUFFICIENT_RESOURCES; 248 } 249 250 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_DELETE_POINTS, mmp, mmpsize, mmps2, mmps1.Size, FALSE, NULL); 251 252 if (!NT_SUCCESS(Status)) 253 ERR("IOCTL_MOUNTMGR_DELETE_POINTS 2 returned %08x\n", Status); 254 255 ExFreePool(mmps2); 256 ExFreePool(mmp); 257 258 return Status; 259 } 260 261 void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { 262 PFILE_OBJECT FileObject, mountmgrfo; 263 PDEVICE_OBJECT devobj, mountmgr; 264 NTSTATUS Status; 265 STORAGE_DEVICE_NUMBER sdn; 266 ULONG dlisize; 267 DRIVE_LAYOUT_INFORMATION_EX* dli = NULL; 268 IO_STATUS_BLOCK iosb; 269 GET_LENGTH_INFORMATION gli; 270 UNICODE_STRING mmdevpath; 271 272 UNUSED(DriverObject); 273 274 Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &devobj); 275 if (!NT_SUCCESS(Status)) { 276 ERR("IoGetDeviceObjectPointer returned %08x\n", Status); 277 return; 278 } 279 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); 285 return; 286 } 287 288 dlisize = 0; 289 290 do { 291 dlisize += 1024; 292 293 if (dli) 294 ExFreePool(dli); 295 296 dli = ExAllocatePoolWithTag(PagedPool, dlisize, ALLOC_TAG); 297 if (!dli) { 298 ERR("out of memory\n"); 299 goto end; 300 } 301 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); 305 306 // only consider disk as a potential filesystem if it has no partitions 307 if (NT_SUCCESS(Status) && dli->PartitionCount > 0) { 308 ExFreePool(dli); 309 goto end; 310 } 311 312 ExFreePool(dli); 313 314 Status = dev_ioctl(devobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, 315 &gli, sizeof(gli), TRUE, NULL); 316 317 if (!NT_SUCCESS(Status)) { 318 ERR("error reading length information: %08x\n", Status); 319 goto end; 320 } 321 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; 328 } else 329 TRACE("DeviceType = %u, DeviceNumber = %u, PartitionNumber = %u\n", sdn.DeviceType, sdn.DeviceNumber, sdn.PartitionNumber); 330 331 test_vol(mountmgr, devobj, devpath, sdn.DeviceNumber, sdn.PartitionNumber, gli.Length.QuadPart); 332 333 end: 334 ObDereferenceObject(FileObject); 335 ObDereferenceObject(mountmgrfo); 336 } 337 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) { 340 NTSTATUS Status; 341 pdo_device_extension* pdode = vde->pdode; 342 device_extension* Vcb = vde->mounted_device ? vde->mounted_device->DeviceExtension : NULL; 343 344 if (vc->notification_entry) 345 #ifdef __REACTOS__ 346 IoUnregisterPlugPlayNotification(vc->notification_entry); 347 #else 348 IoUnregisterPlugPlayNotificationEx(vc->notification_entry); 349 #endif 350 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); 355 } 356 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); 361 } 362 363 if (pdode->children_loaded > 0) { 364 UNICODE_STRING mmdevpath; 365 PFILE_OBJECT FileObject; 366 PDEVICE_OBJECT mountmgr; 367 LIST_ENTRY* le; 368 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); 374 else { 375 le = pdode->children.Flink; 376 377 while (le != &pdode->children) { 378 volume_child* vc2 = CONTAINING_RECORD(le, volume_child, list_entry); 379 380 if (vc2->had_drive_letter) { // re-add entry to mountmgr 381 MOUNTDEV_NAME mdn; 382 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); 386 else { 387 MOUNTDEV_NAME* mdn2; 388 ULONG mdnsize = (ULONG)offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength; 389 390 mdn2 = ExAllocatePoolWithTag(PagedPool, mdnsize, ALLOC_TAG); 391 if (!mdn2) 392 ERR("out of memory\n"); 393 else { 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); 397 else { 398 UNICODE_STRING name; 399 400 name.Buffer = mdn2->Name; 401 name.Length = name.MaximumLength = mdn2->NameLength; 402 403 Status = mountmgr_add_drive_letter(mountmgr, &name); 404 if (!NT_SUCCESS(Status)) 405 WARN("mountmgr_add_drive_letter returned %08x\n", Status); 406 } 407 408 ExFreePool(mdn2); 409 } 410 } 411 } 412 413 le = le->Flink; 414 } 415 416 ObDereferenceObject(FileObject); 417 } 418 } else if (!skip_dev) { 419 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 420 421 le = Vcb->devices.Flink; 422 while (le != &Vcb->devices) { 423 device* dev = CONTAINING_RECORD(le, device, list_entry); 424 425 if (dev->devobj == vc->devobj) { 426 dev->devobj = NULL; // mark as missing 427 break; 428 } 429 430 le = le->Flink; 431 } 432 433 ExReleaseResourceLite(&Vcb->tree_lock); 434 } 435 436 if (vde->device->Characteristics & FILE_REMOVABLE_MEDIA) { 437 vde->device->Characteristics &= ~FILE_REMOVABLE_MEDIA; 438 439 le = pdode->children.Flink; 440 while (le != &pdode->children) { 441 volume_child* vc2 = CONTAINING_RECORD(le, volume_child, list_entry); 442 443 if (vc2 != vc && vc2->devobj->Characteristics & FILE_REMOVABLE_MEDIA) { 444 vde->device->Characteristics |= FILE_REMOVABLE_MEDIA; 445 break; 446 } 447 448 le = le->Flink; 449 } 450 } 451 } 452 453 ObDereferenceObject(vc->fileobj); 454 ExFreePool(vc->pnp_name.Buffer); 455 RemoveEntryList(&vc->list_entry); 456 ExFreePool(vc); 457 458 pdode->children_loaded--; 459 460 if (pdode->children_loaded == 0) { // remove volume device 461 BOOL remove = FALSE; 462 463 RemoveEntryList(&pdode->list_entry); 464 465 vde->removing = TRUE; 466 467 Status = IoSetDeviceInterfaceState(&vde->bus_name, FALSE); 468 if (!NT_SUCCESS(Status)) 469 WARN("IoSetDeviceInterfaceState returned %08x\n", Status); 470 471 if (vde->pdo->AttachedDevice) 472 IoDetachDevice(vde->pdo); 473 474 if (vde->open_count == 0) 475 remove = TRUE; 476 477 ExReleaseResourceLite(&pdode->child_lock); 478 479 if (!no_pnp) { 480 control_device_extension* cde = master_devobj->DeviceExtension; 481 482 IoInvalidateDeviceRelations(cde->buspdo, BusRelations); 483 } 484 485 if (remove) { 486 PDEVICE_OBJECT pdo; 487 488 if (vde->name.Buffer) 489 ExFreePool(vde->name.Buffer); 490 491 if (Vcb) 492 Vcb->vde = NULL; 493 494 ExDeleteResourceLite(&pdode->child_lock); 495 496 pdo = vde->pdo; 497 IoDeleteDevice(vde->device); 498 499 if (no_pnp) 500 IoDeleteDevice(pdo); 501 } 502 } else 503 ExReleaseResourceLite(&pdode->child_lock); 504 } 505 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; 512 NTSTATUS Status; 513 514 TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer); 515 516 Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &devobj); 517 if (!NT_SUCCESS(Status)) { 518 ERR("IoGetDeviceObjectPointer returned %08x\n", Status); 519 return; 520 } 521 522 // make sure we're not processing devices we've created ourselves 523 524 if (devobj->DriverObject == DriverObject) 525 goto end; 526 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); 530 goto end; 531 } 532 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; 539 } else 540 TRACE("DeviceType = %u, DeviceNumber = %u, PartitionNumber = %u\n", sdn.DeviceType, sdn.DeviceNumber, sdn.PartitionNumber); 541 542 // If we've just added a partition to a whole-disk filesystem, unmount it 543 if (sdn.DeviceNumber != 0xffffffff) { 544 LIST_ENTRY* le; 545 546 ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE); 547 548 le = pdo_list.Flink; 549 while (le != &pdo_list) { 550 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 551 LIST_ENTRY* le2; 552 BOOL changed = FALSE; 553 554 if (pdode->vde) { 555 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); 556 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; 561 562 if (vc->disk_num == sdn.DeviceNumber && vc->part_num == 0) { 563 TRACE("removing device\n"); 564 565 remove_volume_child(pdode->vde, vc, FALSE); 566 changed = TRUE; 567 568 break; 569 } 570 571 le2 = le3; 572 } 573 574 if (!changed) 575 ExReleaseResourceLite(&pdode->child_lock); 576 else 577 break; 578 } 579 580 le = le->Flink; 581 } 582 583 ExReleaseResourceLite(&pdo_list_lock); 584 } 585 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); 590 goto end; 591 } 592 593 test_vol(mountmgr, devobj, devpath, sdn.DeviceNumber, sdn.PartitionNumber, gli.Length.QuadPart); 594 595 ObDereferenceObject(mountmgrfo); 596 597 end: 598 ObDereferenceObject(FileObject); 599 } 600 601 void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { 602 LIST_ENTRY* le; 603 UNICODE_STRING devpath2; 604 605 TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer); 606 607 UNUSED(DriverObject); 608 609 devpath2 = *devpath; 610 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); 616 } 617 618 ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE); 619 620 le = pdo_list.Flink; 621 while (le != &pdo_list) { 622 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 623 LIST_ENTRY* le2; 624 BOOL changed = FALSE; 625 626 if (pdode->vde) { 627 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); 628 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; 633 634 if (vc->pnp_name.Length == devpath2.Length && RtlCompareMemory(vc->pnp_name.Buffer, devpath2.Buffer, devpath2.Length) == devpath2.Length) { 635 TRACE("removing device\n"); 636 637 remove_volume_child(pdode->vde, vc, FALSE); 638 changed = TRUE; 639 640 break; 641 } 642 643 le2 = le3; 644 } 645 646 if (!changed) 647 ExReleaseResourceLite(&pdode->child_lock); 648 else 649 break; 650 } 651 652 le = le->Flink; 653 } 654 655 ExReleaseResourceLite(&pdo_list_lock); 656 } 657 658 typedef struct { 659 PDRIVER_OBJECT DriverObject; 660 UNICODE_STRING name; 661 pnp_callback func; 662 PIO_WORKITEM work_item; 663 } pnp_callback_context; 664 665 _Function_class_(IO_WORKITEM_ROUTINE) 666 #ifdef __REACTOS__ 667 static void NTAPI do_pnp_callback(PDEVICE_OBJECT DeviceObject, PVOID con) { 668 #else 669 static void do_pnp_callback(PDEVICE_OBJECT DeviceObject, PVOID con) { 670 #endif 671 pnp_callback_context* context = con; 672 673 UNUSED(DeviceObject); 674 675 context->func(context->DriverObject, &context->name); 676 677 if (context->name.Buffer) 678 ExFreePool(context->name.Buffer); 679 680 IoFreeWorkItem(context->work_item); 681 } 682 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; 686 687 work_item = IoAllocateWorkItem(master_devobj); 688 689 context = ExAllocatePoolWithTag(PagedPool, sizeof(pnp_callback_context), ALLOC_TAG); 690 691 if (!context) { 692 ERR("out of memory\n"); 693 IoFreeWorkItem(work_item); 694 return; 695 } 696 697 context->DriverObject = DriverObject; 698 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"); 703 ExFreePool(context); 704 IoFreeWorkItem(work_item); 705 return; 706 } 707 708 RtlCopyMemory(context->name.Buffer, name->Buffer, name->Length); 709 context->name.Length = context->name.MaximumLength = name->Length; 710 } else { 711 context->name.Length = context->name.MaximumLength = 0; 712 context->name.Buffer = NULL; 713 } 714 715 context->func = func; 716 context->work_item = work_item; 717 718 IoQueueWorkItem(work_item, do_pnp_callback, DelayedWorkQueue, context); 719 } 720 721 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) 722 #ifdef __REACTOS__ 723 NTSTATUS NTAPI volume_notification(PVOID NotificationStructure, PVOID Context) { 724 #else 725 NTSTATUS volume_notification(PVOID NotificationStructure, PVOID Context) { 726 #endif 727 DEVICE_INTERFACE_CHANGE_NOTIFICATION* dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure; 728 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context; 729 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); 734 735 return STATUS_SUCCESS; 736 } 737 738 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) 739 #ifdef __REACTOS__ 740 NTSTATUS NTAPI pnp_notification(PVOID NotificationStructure, PVOID Context) { 741 #else 742 NTSTATUS pnp_notification(PVOID NotificationStructure, PVOID Context) { 743 #endif 744 DEVICE_INTERFACE_CHANGE_NOTIFICATION* dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure; 745 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context; 746 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); 751 752 return STATUS_SUCCESS; 753 } 754 755 static void mountmgr_process_drive(PDEVICE_OBJECT mountmgr, PUNICODE_STRING device_name) { 756 NTSTATUS Status; 757 LIST_ENTRY* le; 758 BOOL done = FALSE; 759 760 ExAcquireResourceSharedLite(&pdo_list_lock, TRUE); 761 762 le = pdo_list.Flink; 763 while (le != &pdo_list) { 764 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 765 LIST_ENTRY* le2; 766 767 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 768 769 le2 = pdode->children.Flink; 770 771 while (le2 != &pdode->children) { 772 volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry); 773 774 if (vc->devobj) { 775 MOUNTDEV_NAME mdn; 776 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); 780 else { 781 MOUNTDEV_NAME* mdn2; 782 ULONG mdnsize = (ULONG)offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength; 783 784 mdn2 = ExAllocatePoolWithTag(NonPagedPool, mdnsize, ALLOC_TAG); 785 if (!mdn2) 786 ERR("out of memory\n"); 787 else { 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); 791 else { 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); 796 else 797 vc->had_drive_letter = TRUE; 798 799 done = TRUE; 800 break; 801 } 802 } 803 804 ExFreePool(mdn2); 805 } 806 } 807 } 808 809 le2 = le2->Flink; 810 } 811 812 ExReleaseResourceLite(&pdode->child_lock); 813 814 if (done) 815 break; 816 817 le = le->Flink; 818 } 819 820 ExReleaseResourceLite(&pdo_list_lock); 821 } 822 823 static void mountmgr_updated(PDEVICE_OBJECT mountmgr, MOUNTMGR_MOUNT_POINTS* mmps) { 824 ULONG i; 825 826 static WCHAR pref[] = L"\\DosDevices\\"; 827 828 for (i = 0; i < mmps->NumberOfMountPoints; i++) { 829 UNICODE_STRING symlink, device_name; 830 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; 834 } else { 835 symlink.Buffer = NULL; 836 symlink.Length = symlink.MaximumLength = 0; 837 } 838 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; 842 } else { 843 device_name.Buffer = NULL; 844 device_name.Length = device_name.MaximumLength = 0; 845 } 846 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); 850 } 851 } 852 853 _Function_class_(KSTART_ROUTINE) 854 #ifdef __REACTOS__ 855 void NTAPI mountmgr_thread(_In_ void* context) { 856 #else 857 void mountmgr_thread(_In_ void* context) { 858 #endif 859 UNICODE_STRING mmdevpath; 860 NTSTATUS Status; 861 PFILE_OBJECT FileObject; 862 PDEVICE_OBJECT mountmgr; 863 MOUNTMGR_CHANGE_NOTIFY_INFO mcni; 864 865 UNUSED(context); 866 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); 871 return; 872 } 873 874 mcni.EpicNumber = 0; 875 876 while (TRUE) { 877 PIRP Irp; 878 MOUNTMGR_MOUNT_POINT mmp; 879 MOUNTMGR_MOUNT_POINTS mmps; 880 IO_STATUS_BLOCK iosb; 881 882 KeClearEvent(&mountmgr_thread_event); 883 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); 886 887 if (!Irp) { 888 ERR("out of memory\n"); 889 break; 890 } 891 892 Status = IoCallDriver(mountmgr, Irp); 893 894 if (Status == STATUS_PENDING) { 895 KeWaitForSingleObject(&mountmgr_thread_event, Executive, KernelMode, FALSE, NULL); 896 Status = iosb.Status; 897 } 898 899 if (shutting_down) 900 break; 901 902 if (!NT_SUCCESS(Status)) { 903 ERR("IOCTL_MOUNTMGR_CHANGE_NOTIFY returned %08x\n", Status); 904 break; 905 } 906 907 TRACE("mountmgr changed\n"); 908 909 RtlZeroMemory(&mmp, sizeof(MOUNTMGR_MOUNT_POINT)); 910 911 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp, sizeof(MOUNTMGR_MOUNT_POINT), &mmps, sizeof(MOUNTMGR_MOUNT_POINTS), 912 FALSE, NULL); 913 914 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 915 ERR("IOCTL_MOUNTMGR_QUERY_POINTS 1 returned %08x\n", Status); 916 917 if (mmps.Size > 0) { 918 MOUNTMGR_MOUNT_POINTS* mmps2; 919 920 mmps2 = ExAllocatePoolWithTag(NonPagedPool, mmps.Size, ALLOC_TAG); 921 if (!mmps2) { 922 ERR("out of memory\n"); 923 break; 924 } 925 926 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp, sizeof(MOUNTMGR_MOUNT_POINTS), mmps2, mmps.Size, 927 FALSE, NULL); 928 if (!NT_SUCCESS(Status)) 929 ERR("IOCTL_MOUNTMGR_QUERY_POINTS returned %08x\n", Status); 930 else 931 mountmgr_updated(mountmgr, mmps2); 932 933 ExFreePool(mmps2); 934 } 935 } 936 937 ObDereferenceObject(FileObject); 938 939 mountmgr_thread_handle = NULL; 940 941 PsTerminateSystemThread(STATUS_SUCCESS); 942 } 943