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 if (vde->name.Buffer) 487 ExFreePool(vde->name.Buffer); 488 489 if (Vcb) 490 Vcb->vde = NULL; 491 492 ExDeleteResourceLite(&pdode->child_lock); 493 494 IoDeleteDevice(vde->device); 495 } 496 } else 497 ExReleaseResourceLite(&pdode->child_lock); 498 } 499 500 void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { 501 STORAGE_DEVICE_NUMBER sdn; 502 PFILE_OBJECT FileObject, mountmgrfo; 503 UNICODE_STRING mmdevpath; 504 PDEVICE_OBJECT devobj, mountmgr; 505 GET_LENGTH_INFORMATION gli; 506 NTSTATUS Status; 507 508 TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer); 509 510 Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &devobj); 511 if (!NT_SUCCESS(Status)) { 512 ERR("IoGetDeviceObjectPointer returned %08x\n", Status); 513 return; 514 } 515 516 // make sure we're not processing devices we've created ourselves 517 518 if (devobj->DriverObject == DriverObject) 519 goto end; 520 521 Status = dev_ioctl(devobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), TRUE, NULL); 522 if (!NT_SUCCESS(Status)) { 523 ERR("IOCTL_DISK_GET_LENGTH_INFO returned %08x\n", Status); 524 goto end; 525 } 526 527 Status = dev_ioctl(devobj, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, 528 &sdn, sizeof(STORAGE_DEVICE_NUMBER), TRUE, NULL); 529 if (!NT_SUCCESS(Status)) { 530 TRACE("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status); 531 sdn.DeviceNumber = 0xffffffff; 532 sdn.PartitionNumber = 0; 533 } else 534 TRACE("DeviceType = %u, DeviceNumber = %u, PartitionNumber = %u\n", sdn.DeviceType, sdn.DeviceNumber, sdn.PartitionNumber); 535 536 // If we've just added a partition to a whole-disk filesystem, unmount it 537 if (sdn.DeviceNumber != 0xffffffff && sdn.PartitionNumber != 0) { 538 LIST_ENTRY* le; 539 540 ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE); 541 542 le = pdo_list.Flink; 543 while (le != &pdo_list) { 544 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 545 LIST_ENTRY* le2; 546 BOOL changed = FALSE; 547 548 if (pdode->vde) { 549 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); 550 551 le2 = pdode->children.Flink; 552 while (le2 != &pdode->children) { 553 volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry); 554 LIST_ENTRY* le3 = le2->Flink; 555 556 if (vc->disk_num == sdn.DeviceNumber && vc->part_num == 0) { 557 TRACE("removing device\n"); 558 559 remove_volume_child(pdode->vde, vc, FALSE); 560 changed = TRUE; 561 562 break; 563 } 564 565 le2 = le3; 566 } 567 568 if (!changed) 569 ExReleaseResourceLite(&pdode->child_lock); 570 else 571 break; 572 } 573 574 le = le->Flink; 575 } 576 577 ExReleaseResourceLite(&pdo_list_lock); 578 } 579 580 RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); 581 Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr); 582 if (!NT_SUCCESS(Status)) { 583 ERR("IoGetDeviceObjectPointer returned %08x\n", Status); 584 goto end; 585 } 586 587 test_vol(mountmgr, devobj, devpath, sdn.DeviceNumber, sdn.PartitionNumber, gli.Length.QuadPart); 588 589 ObDereferenceObject(mountmgrfo); 590 591 end: 592 ObDereferenceObject(FileObject); 593 } 594 595 void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) { 596 LIST_ENTRY* le; 597 UNICODE_STRING devpath2; 598 599 TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer); 600 601 UNUSED(DriverObject); 602 603 devpath2 = *devpath; 604 605 if (devpath->Length > 4 * sizeof(WCHAR) && devpath->Buffer[0] == '\\' && (devpath->Buffer[1] == '\\' || devpath->Buffer[1] == '?') && 606 devpath->Buffer[2] == '?' && devpath->Buffer[3] == '\\') { 607 devpath2.Buffer = &devpath2.Buffer[3]; 608 devpath2.Length -= 3 * sizeof(WCHAR); 609 devpath2.MaximumLength -= 3 * sizeof(WCHAR); 610 } 611 612 ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE); 613 614 le = pdo_list.Flink; 615 while (le != &pdo_list) { 616 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 617 LIST_ENTRY* le2; 618 BOOL changed = FALSE; 619 620 if (pdode->vde) { 621 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); 622 623 le2 = pdode->children.Flink; 624 while (le2 != &pdode->children) { 625 volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry); 626 LIST_ENTRY* le3 = le2->Flink; 627 628 if (vc->pnp_name.Length == devpath2.Length && RtlCompareMemory(vc->pnp_name.Buffer, devpath2.Buffer, devpath2.Length) == devpath2.Length) { 629 TRACE("removing device\n"); 630 631 remove_volume_child(pdode->vde, vc, FALSE); 632 changed = TRUE; 633 634 break; 635 } 636 637 le2 = le3; 638 } 639 640 if (!changed) 641 ExReleaseResourceLite(&pdode->child_lock); 642 else 643 break; 644 } 645 646 le = le->Flink; 647 } 648 649 ExReleaseResourceLite(&pdo_list_lock); 650 } 651 652 typedef struct { 653 PDRIVER_OBJECT DriverObject; 654 UNICODE_STRING name; 655 pnp_callback func; 656 PIO_WORKITEM work_item; 657 } pnp_callback_context; 658 659 _Function_class_(IO_WORKITEM_ROUTINE) 660 #ifdef __REACTOS__ 661 static void NTAPI do_pnp_callback(PDEVICE_OBJECT DeviceObject, PVOID con) { 662 #else 663 static void do_pnp_callback(PDEVICE_OBJECT DeviceObject, PVOID con) { 664 #endif 665 pnp_callback_context* context = con; 666 667 UNUSED(DeviceObject); 668 669 context->func(context->DriverObject, &context->name); 670 671 if (context->name.Buffer) 672 ExFreePool(context->name.Buffer); 673 674 IoFreeWorkItem(context->work_item); 675 } 676 677 static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING name, pnp_callback func) { 678 PIO_WORKITEM work_item; 679 pnp_callback_context* context; 680 681 work_item = IoAllocateWorkItem(master_devobj); 682 683 context = ExAllocatePoolWithTag(PagedPool, sizeof(pnp_callback_context), ALLOC_TAG); 684 685 if (!context) { 686 ERR("out of memory\n"); 687 IoFreeWorkItem(work_item); 688 return; 689 } 690 691 context->DriverObject = DriverObject; 692 693 if (name->Length > 0) { 694 context->name.Buffer = ExAllocatePoolWithTag(PagedPool, name->Length, ALLOC_TAG); 695 if (!context->name.Buffer) { 696 ERR("out of memory\n"); 697 ExFreePool(context); 698 IoFreeWorkItem(work_item); 699 return; 700 } 701 702 RtlCopyMemory(context->name.Buffer, name->Buffer, name->Length); 703 context->name.Length = context->name.MaximumLength = name->Length; 704 } else { 705 context->name.Length = context->name.MaximumLength = 0; 706 context->name.Buffer = NULL; 707 } 708 709 context->func = func; 710 context->work_item = work_item; 711 712 IoQueueWorkItem(work_item, do_pnp_callback, DelayedWorkQueue, context); 713 } 714 715 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) 716 #ifdef __REACTOS__ 717 NTSTATUS NTAPI volume_notification(PVOID NotificationStructure, PVOID Context) { 718 #else 719 NTSTATUS volume_notification(PVOID NotificationStructure, PVOID Context) { 720 #endif 721 DEVICE_INTERFACE_CHANGE_NOTIFICATION* dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure; 722 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context; 723 724 if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID)) 725 enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, volume_arrival); 726 else if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID)) 727 enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, volume_removal); 728 729 return STATUS_SUCCESS; 730 } 731 732 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) 733 #ifdef __REACTOS__ 734 NTSTATUS NTAPI pnp_notification(PVOID NotificationStructure, PVOID Context) { 735 #else 736 NTSTATUS pnp_notification(PVOID NotificationStructure, PVOID Context) { 737 #endif 738 DEVICE_INTERFACE_CHANGE_NOTIFICATION* dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure; 739 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context; 740 741 if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID)) 742 enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, disk_arrival); 743 else if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID)) 744 enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, volume_removal); 745 746 return STATUS_SUCCESS; 747 } 748 749 static void mountmgr_process_drive(PDEVICE_OBJECT mountmgr, PUNICODE_STRING device_name) { 750 NTSTATUS Status; 751 LIST_ENTRY* le; 752 BOOL done = FALSE; 753 754 ExAcquireResourceSharedLite(&pdo_list_lock, TRUE); 755 756 le = pdo_list.Flink; 757 while (le != &pdo_list) { 758 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 759 LIST_ENTRY* le2; 760 761 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 762 763 le2 = pdode->children.Flink; 764 765 while (le2 != &pdode->children) { 766 volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry); 767 768 if (vc->devobj) { 769 MOUNTDEV_NAME mdn; 770 771 Status = dev_ioctl(vc->devobj, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &mdn, sizeof(MOUNTDEV_NAME), TRUE, NULL); 772 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 773 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status); 774 else { 775 MOUNTDEV_NAME* mdn2; 776 ULONG mdnsize = (ULONG)offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength; 777 778 mdn2 = ExAllocatePoolWithTag(NonPagedPool, mdnsize, ALLOC_TAG); 779 if (!mdn2) 780 ERR("out of memory\n"); 781 else { 782 Status = dev_ioctl(vc->devobj, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, mdn2, mdnsize, TRUE, NULL); 783 if (!NT_SUCCESS(Status)) 784 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status); 785 else { 786 if (mdn2->NameLength == device_name->Length && RtlCompareMemory(mdn2->Name, device_name->Buffer, device_name->Length) == device_name->Length) { 787 Status = remove_drive_letter(mountmgr, device_name); 788 if (!NT_SUCCESS(Status)) 789 ERR("remove_drive_letter returned %08x\n", Status); 790 else 791 vc->had_drive_letter = TRUE; 792 793 done = TRUE; 794 break; 795 } 796 } 797 798 ExFreePool(mdn2); 799 } 800 } 801 } 802 803 le2 = le2->Flink; 804 } 805 806 ExReleaseResourceLite(&pdode->child_lock); 807 808 if (done) 809 break; 810 811 le = le->Flink; 812 } 813 814 ExReleaseResourceLite(&pdo_list_lock); 815 } 816 817 static void mountmgr_updated(PDEVICE_OBJECT mountmgr, MOUNTMGR_MOUNT_POINTS* mmps) { 818 ULONG i; 819 820 static const WCHAR pref[] = L"\\DosDevices\\"; 821 822 for (i = 0; i < mmps->NumberOfMountPoints; i++) { 823 UNICODE_STRING symlink, device_name; 824 825 if (mmps->MountPoints[i].SymbolicLinkNameOffset != 0) { 826 symlink.Buffer = (WCHAR*)(((UINT8*)mmps) + mmps->MountPoints[i].SymbolicLinkNameOffset); 827 symlink.Length = symlink.MaximumLength = mmps->MountPoints[i].SymbolicLinkNameLength; 828 } else { 829 symlink.Buffer = NULL; 830 symlink.Length = symlink.MaximumLength = 0; 831 } 832 833 if (mmps->MountPoints[i].DeviceNameOffset != 0) { 834 device_name.Buffer = (WCHAR*)(((UINT8*)mmps) + mmps->MountPoints[i].DeviceNameOffset); 835 device_name.Length = device_name.MaximumLength = mmps->MountPoints[i].DeviceNameLength; 836 } else { 837 device_name.Buffer = NULL; 838 device_name.Length = device_name.MaximumLength = 0; 839 } 840 841 if (symlink.Length > sizeof(pref) - sizeof(WCHAR) && 842 RtlCompareMemory(symlink.Buffer, pref, sizeof(pref) - sizeof(WCHAR)) == sizeof(pref) - sizeof(WCHAR)) 843 mountmgr_process_drive(mountmgr, &device_name); 844 } 845 } 846 847 _Function_class_(KSTART_ROUTINE) 848 #ifdef __REACTOS__ 849 void NTAPI mountmgr_thread(_In_ void* context) { 850 #else 851 void mountmgr_thread(_In_ void* context) { 852 #endif 853 UNICODE_STRING mmdevpath; 854 NTSTATUS Status; 855 PFILE_OBJECT FileObject; 856 PDEVICE_OBJECT mountmgr; 857 MOUNTMGR_CHANGE_NOTIFY_INFO mcni; 858 859 UNUSED(context); 860 861 RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); 862 Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr); 863 if (!NT_SUCCESS(Status)) { 864 ERR("IoGetDeviceObjectPointer returned %08x\n", Status); 865 return; 866 } 867 868 mcni.EpicNumber = 0; 869 870 while (TRUE) { 871 PIRP Irp; 872 MOUNTMGR_MOUNT_POINT mmp; 873 MOUNTMGR_MOUNT_POINTS mmps; 874 IO_STATUS_BLOCK iosb; 875 876 KeClearEvent(&mountmgr_thread_event); 877 878 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_CHANGE_NOTIFY, mountmgr, &mcni, sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO), 879 &mcni, sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO), FALSE, &mountmgr_thread_event, &iosb); 880 881 if (!Irp) { 882 ERR("out of memory\n"); 883 break; 884 } 885 886 Status = IoCallDriver(mountmgr, Irp); 887 888 if (Status == STATUS_PENDING) { 889 KeWaitForSingleObject(&mountmgr_thread_event, Executive, KernelMode, FALSE, NULL); 890 Status = iosb.Status; 891 } 892 893 if (shutting_down) 894 break; 895 896 if (!NT_SUCCESS(Status)) { 897 ERR("IOCTL_MOUNTMGR_CHANGE_NOTIFY returned %08x\n", Status); 898 break; 899 } 900 901 TRACE("mountmgr changed\n"); 902 903 RtlZeroMemory(&mmp, sizeof(MOUNTMGR_MOUNT_POINT)); 904 905 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp, sizeof(MOUNTMGR_MOUNT_POINT), &mmps, sizeof(MOUNTMGR_MOUNT_POINTS), 906 FALSE, NULL); 907 908 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 909 ERR("IOCTL_MOUNTMGR_QUERY_POINTS 1 returned %08x\n", Status); 910 else if (mmps.Size > 0) { 911 MOUNTMGR_MOUNT_POINTS* mmps2; 912 913 mmps2 = ExAllocatePoolWithTag(NonPagedPool, mmps.Size, ALLOC_TAG); 914 if (!mmps2) { 915 ERR("out of memory\n"); 916 break; 917 } 918 919 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp, sizeof(MOUNTMGR_MOUNT_POINTS), mmps2, mmps.Size, 920 FALSE, NULL); 921 if (!NT_SUCCESS(Status)) 922 ERR("IOCTL_MOUNTMGR_QUERY_POINTS returned %08x\n", Status); 923 else 924 mountmgr_updated(mountmgr, mmps2); 925 926 ExFreePool(mmps2); 927 } 928 } 929 930 ObDereferenceObject(FileObject); 931 932 mountmgr_thread_handle = NULL; 933 934 PsTerminateSystemThread(STATUS_SUCCESS); 935 } 936