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 #include <mountdev.h> 20 #include <ntddvol.h> 21 #include <ntddstor.h> 22 #include <ntdddisk.h> 23 #include <wdmguid.h> 24 25 #define IOCTL_VOLUME_IS_DYNAMIC CTL_CODE(IOCTL_VOLUME_BASE, 18, METHOD_BUFFERED, FILE_ANY_ACCESS) 26 #define IOCTL_VOLUME_POST_ONLINE CTL_CODE(IOCTL_VOLUME_BASE, 25, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) 27 28 extern PDRIVER_OBJECT drvobj; 29 extern PDEVICE_OBJECT master_devobj; 30 extern ERESOURCE pdo_list_lock; 31 extern LIST_ENTRY pdo_list; 32 extern UNICODE_STRING registry_path; 33 34 NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 35 volume_device_extension* vde = DeviceObject->DeviceExtension; 36 37 TRACE("(%p, %p)\n", DeviceObject, Irp); 38 39 if (vde->removing) 40 return STATUS_DEVICE_NOT_READY; 41 42 Irp->IoStatus.Information = FILE_OPENED; 43 InterlockedIncrement(&vde->open_count); 44 45 return STATUS_SUCCESS; 46 } 47 48 NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 49 volume_device_extension* vde = DeviceObject->DeviceExtension; 50 pdo_device_extension* pdode = vde->pdode; 51 52 TRACE("(%p, %p)\n", DeviceObject, Irp); 53 54 Irp->IoStatus.Information = 0; 55 56 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 57 58 if (InterlockedDecrement(&vde->open_count) == 0 && vde->removing) { 59 NTSTATUS Status; 60 UNICODE_STRING mmdevpath; 61 PDEVICE_OBJECT mountmgr; 62 PFILE_OBJECT mountmgrfo; 63 PDEVICE_OBJECT pdo; 64 65 RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); 66 Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr); 67 if (!NT_SUCCESS(Status)) 68 ERR("IoGetDeviceObjectPointer returned %08x\n", Status); 69 else { 70 remove_drive_letter(mountmgr, &vde->name); 71 72 ObDereferenceObject(mountmgrfo); 73 } 74 75 if (vde->mounted_device) { 76 device_extension* Vcb = vde->mounted_device->DeviceExtension; 77 78 Vcb->vde = NULL; 79 } 80 81 if (vde->name.Buffer) 82 ExFreePool(vde->name.Buffer); 83 84 ExReleaseResourceLite(&pdode->child_lock); 85 ExDeleteResourceLite(&pdode->child_lock); 86 IoDetachDevice(vde->pdo); 87 88 pdo = vde->pdo; 89 IoDeleteDevice(vde->device); 90 91 if (no_pnp) 92 IoDeleteDevice(pdo); 93 } else 94 ExReleaseResourceLite(&pdode->child_lock); 95 96 return STATUS_SUCCESS; 97 } 98 99 typedef struct { 100 IO_STATUS_BLOCK iosb; 101 KEVENT Event; 102 } vol_read_context; 103 104 _Function_class_(IO_COMPLETION_ROUTINE) 105 #ifdef __REACTOS__ 106 static NTSTATUS NTAPI vol_read_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) { 107 #else 108 static NTSTATUS vol_read_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) { 109 #endif 110 vol_read_context* context = conptr; 111 112 UNUSED(DeviceObject); 113 114 context->iosb = Irp->IoStatus; 115 KeSetEvent(&context->Event, 0, FALSE); 116 117 return STATUS_MORE_PROCESSING_REQUIRED; 118 } 119 120 NTSTATUS vol_read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 121 volume_device_extension* vde = DeviceObject->DeviceExtension; 122 pdo_device_extension* pdode = vde->pdode; 123 volume_child* vc; 124 NTSTATUS Status; 125 PIRP Irp2; 126 vol_read_context context; 127 PIO_STACK_LOCATION IrpSp, IrpSp2; 128 129 TRACE("(%p, %p)\n", DeviceObject, Irp); 130 131 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 132 133 if (IsListEmpty(&pdode->children)) { 134 ExReleaseResourceLite(&pdode->child_lock); 135 Status = STATUS_INVALID_DEVICE_REQUEST; 136 goto end; 137 } 138 139 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry); 140 141 // We can't use IoSkipCurrentIrpStackLocation as the device isn't in our stack 142 143 Irp2 = IoAllocateIrp(vc->devobj->StackSize, FALSE); 144 145 if (!Irp2) { 146 ERR("IoAllocateIrp failed\n"); 147 ExReleaseResourceLite(&pdode->child_lock); 148 Status = STATUS_INSUFFICIENT_RESOURCES; 149 goto end; 150 } 151 152 IrpSp = IoGetCurrentIrpStackLocation(Irp); 153 IrpSp2 = IoGetNextIrpStackLocation(Irp2); 154 155 IrpSp2->MajorFunction = IRP_MJ_READ; 156 157 if (vc->devobj->Flags & DO_BUFFERED_IO) { 158 Irp2->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, IrpSp->Parameters.Read.Length, ALLOC_TAG); 159 if (!Irp2->AssociatedIrp.SystemBuffer) { 160 ERR("out of memory\n"); 161 ExReleaseResourceLite(&pdode->child_lock); 162 Status = STATUS_INSUFFICIENT_RESOURCES; 163 goto end; 164 } 165 166 Irp2->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION; 167 168 Irp2->UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 169 } else if (vc->devobj->Flags & DO_DIRECT_IO) 170 Irp2->MdlAddress = Irp->MdlAddress; 171 else 172 Irp2->UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 173 174 IrpSp2->Parameters.Read.Length = IrpSp->Parameters.Read.Length; 175 IrpSp2->Parameters.Read.ByteOffset.QuadPart = IrpSp->Parameters.Read.ByteOffset.QuadPart; 176 177 KeInitializeEvent(&context.Event, NotificationEvent, FALSE); 178 Irp2->UserIosb = &context.iosb; 179 180 IoSetCompletionRoutine(Irp2, vol_read_completion, &context, TRUE, TRUE, TRUE); 181 182 Status = IoCallDriver(vc->devobj, Irp2); 183 184 if (Status == STATUS_PENDING) { 185 KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL); 186 Status = context.iosb.Status; 187 } 188 189 ExReleaseResourceLite(&pdode->child_lock); 190 191 Irp->IoStatus.Information = context.iosb.Information; 192 193 end: 194 Irp->IoStatus.Status = Status; 195 IoCompleteRequest(Irp, IO_NO_INCREMENT); 196 197 return Status; 198 } 199 200 NTSTATUS vol_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 201 volume_device_extension* vde = DeviceObject->DeviceExtension; 202 pdo_device_extension* pdode = vde->pdode; 203 volume_child* vc; 204 NTSTATUS Status; 205 PIRP Irp2; 206 vol_read_context context; 207 PIO_STACK_LOCATION IrpSp, IrpSp2; 208 209 TRACE("(%p, %p)\n", DeviceObject, Irp); 210 211 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 212 213 if (IsListEmpty(&pdode->children)) { 214 ExReleaseResourceLite(&pdode->child_lock); 215 Status = STATUS_INVALID_DEVICE_REQUEST; 216 goto end; 217 } 218 219 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry); 220 221 if (vc->list_entry.Flink != &pdode->children) { // more than once device 222 ExReleaseResourceLite(&pdode->child_lock); 223 Status = STATUS_ACCESS_DENIED; 224 goto end; 225 } 226 227 // We can't use IoSkipCurrentIrpStackLocation as the device isn't in our stack 228 229 Irp2 = IoAllocateIrp(vc->devobj->StackSize, FALSE); 230 231 if (!Irp2) { 232 ERR("IoAllocateIrp failed\n"); 233 ExReleaseResourceLite(&pdode->child_lock); 234 Status = STATUS_INSUFFICIENT_RESOURCES; 235 goto end; 236 } 237 238 IrpSp = IoGetCurrentIrpStackLocation(Irp); 239 IrpSp2 = IoGetNextIrpStackLocation(Irp2); 240 241 IrpSp2->MajorFunction = IRP_MJ_WRITE; 242 243 if (vc->devobj->Flags & DO_BUFFERED_IO) { 244 Irp2->AssociatedIrp.SystemBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 245 246 Irp2->Flags |= IRP_BUFFERED_IO; 247 248 Irp2->UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 249 } else if (vc->devobj->Flags & DO_DIRECT_IO) 250 Irp2->MdlAddress = Irp->MdlAddress; 251 else 252 Irp2->UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 253 254 IrpSp2->Parameters.Write.Length = IrpSp->Parameters.Write.Length; 255 IrpSp2->Parameters.Write.ByteOffset.QuadPart = IrpSp->Parameters.Write.ByteOffset.QuadPart; 256 257 KeInitializeEvent(&context.Event, NotificationEvent, FALSE); 258 Irp2->UserIosb = &context.iosb; 259 260 IoSetCompletionRoutine(Irp2, vol_read_completion, &context, TRUE, TRUE, TRUE); 261 262 Status = IoCallDriver(vc->devobj, Irp2); 263 264 if (Status == STATUS_PENDING) { 265 KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL); 266 Status = context.iosb.Status; 267 } 268 269 ExReleaseResourceLite(&pdode->child_lock); 270 271 Irp->IoStatus.Information = context.iosb.Information; 272 273 end: 274 Irp->IoStatus.Status = Status; 275 IoCompleteRequest(Irp, IO_NO_INCREMENT); 276 277 return Status; 278 } 279 280 NTSTATUS vol_query_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 281 TRACE("(%p, %p)\n", DeviceObject, Irp); 282 283 return STATUS_INVALID_DEVICE_REQUEST; 284 } 285 286 NTSTATUS vol_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 287 TRACE("(%p, %p)\n", DeviceObject, Irp); 288 289 return STATUS_INVALID_DEVICE_REQUEST; 290 } 291 292 NTSTATUS vol_query_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 293 TRACE("(%p, %p)\n", DeviceObject, Irp); 294 295 return STATUS_INVALID_DEVICE_REQUEST; 296 } 297 298 NTSTATUS vol_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 299 TRACE("(%p, %p)\n", DeviceObject, Irp); 300 301 return STATUS_INVALID_DEVICE_REQUEST; 302 } 303 304 NTSTATUS vol_flush_buffers(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 305 TRACE("(%p, %p)\n", DeviceObject, Irp); 306 307 return STATUS_INVALID_DEVICE_REQUEST; 308 } 309 310 NTSTATUS vol_query_volume_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 311 TRACE("(%p, %p)\n", DeviceObject, Irp); 312 313 return STATUS_INVALID_DEVICE_REQUEST; 314 } 315 316 NTSTATUS vol_set_volume_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 317 TRACE("(%p, %p)\n", DeviceObject, Irp); 318 319 return STATUS_INVALID_DEVICE_REQUEST; 320 } 321 322 NTSTATUS vol_cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 323 TRACE("(%p, %p)\n", DeviceObject, Irp); 324 325 Irp->IoStatus.Information = 0; 326 327 return STATUS_SUCCESS; 328 } 329 330 NTSTATUS vol_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 331 TRACE("(%p, %p)\n", DeviceObject, Irp); 332 333 return STATUS_INVALID_DEVICE_REQUEST; 334 } 335 336 NTSTATUS vol_file_system_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 337 TRACE("(%p, %p)\n", DeviceObject, Irp); 338 339 return STATUS_INVALID_DEVICE_REQUEST; 340 } 341 342 NTSTATUS vol_lock_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 343 TRACE("(%p, %p)\n", DeviceObject, Irp); 344 345 return STATUS_INVALID_DEVICE_REQUEST; 346 } 347 348 static NTSTATUS vol_query_device_name(volume_device_extension* vde, PIRP Irp) { 349 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 350 PMOUNTDEV_NAME name; 351 352 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_NAME)) { 353 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME); 354 return STATUS_BUFFER_TOO_SMALL; 355 } 356 357 name = Irp->AssociatedIrp.SystemBuffer; 358 name->NameLength = vde->name.Length; 359 360 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < offsetof(MOUNTDEV_NAME, Name[0]) + name->NameLength) { 361 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME); 362 return STATUS_BUFFER_OVERFLOW; 363 } 364 365 RtlCopyMemory(name->Name, vde->name.Buffer, vde->name.Length); 366 367 Irp->IoStatus.Information = offsetof(MOUNTDEV_NAME, Name[0]) + name->NameLength; 368 369 return STATUS_SUCCESS; 370 } 371 372 static NTSTATUS vol_query_unique_id(volume_device_extension* vde, PIRP Irp) { 373 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 374 MOUNTDEV_UNIQUE_ID* mduid; 375 pdo_device_extension* pdode; 376 377 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_UNIQUE_ID)) { 378 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID); 379 return STATUS_BUFFER_TOO_SMALL; 380 } 381 382 mduid = Irp->AssociatedIrp.SystemBuffer; 383 mduid->UniqueIdLength = sizeof(BTRFS_UUID); 384 385 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < offsetof(MOUNTDEV_UNIQUE_ID, UniqueId[0]) + mduid->UniqueIdLength) { 386 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID); 387 return STATUS_BUFFER_OVERFLOW; 388 } 389 390 if (!vde->pdo) 391 return STATUS_INVALID_PARAMETER; 392 393 pdode = vde->pdode; 394 395 RtlCopyMemory(mduid->UniqueId, &pdode->uuid, sizeof(BTRFS_UUID)); 396 397 Irp->IoStatus.Information = offsetof(MOUNTDEV_UNIQUE_ID, UniqueId[0]) + mduid->UniqueIdLength; 398 399 return STATUS_SUCCESS; 400 } 401 402 static NTSTATUS vol_is_dynamic(PIRP Irp) { 403 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 404 UINT8* buf; 405 406 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0 || !Irp->AssociatedIrp.SystemBuffer) 407 return STATUS_INVALID_PARAMETER; 408 409 buf = (UINT8*)Irp->AssociatedIrp.SystemBuffer; 410 411 *buf = 1; 412 413 Irp->IoStatus.Information = 1; 414 415 return STATUS_SUCCESS; 416 } 417 418 static NTSTATUS vol_check_verify(volume_device_extension* vde) { 419 pdo_device_extension* pdode = vde->pdode; 420 NTSTATUS Status; 421 LIST_ENTRY* le; 422 423 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 424 425 le = pdode->children.Flink; 426 while (le != &pdode->children) { 427 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 428 429 Status = dev_ioctl(vc->devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, FALSE, NULL); 430 if (!NT_SUCCESS(Status)) 431 goto end; 432 433 le = le->Flink; 434 } 435 436 Status = STATUS_SUCCESS; 437 438 end: 439 ExReleaseResourceLite(&pdode->child_lock); 440 441 return Status; 442 } 443 444 static NTSTATUS vol_get_disk_extents(volume_device_extension* vde, PIRP Irp) { 445 pdo_device_extension* pdode = vde->pdode; 446 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 447 LIST_ENTRY* le; 448 ULONG num_extents = 0, i, max_extents = 1; 449 NTSTATUS Status; 450 VOLUME_DISK_EXTENTS *ext, *ext3; 451 452 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VOLUME_DISK_EXTENTS)) 453 return STATUS_BUFFER_TOO_SMALL; 454 455 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 456 457 le = pdode->children.Flink; 458 while (le != &pdode->children) { 459 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 460 VOLUME_DISK_EXTENTS ext2; 461 462 Status = dev_ioctl(vc->devobj, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &ext2, sizeof(VOLUME_DISK_EXTENTS), FALSE, NULL); 463 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { 464 ERR("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS returned %08x\n", Status); 465 goto end; 466 } 467 468 num_extents += ext2.NumberOfDiskExtents; 469 470 if (ext2.NumberOfDiskExtents > max_extents) 471 max_extents = ext2.NumberOfDiskExtents; 472 473 le = le->Flink; 474 } 475 476 ext = Irp->AssociatedIrp.SystemBuffer; 477 478 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < offsetof(VOLUME_DISK_EXTENTS, Extents[0]) + (num_extents * sizeof(DISK_EXTENT))) { 479 Irp->IoStatus.Information = offsetof(VOLUME_DISK_EXTENTS, Extents[0]); 480 ext->NumberOfDiskExtents = num_extents; 481 Status = STATUS_BUFFER_OVERFLOW; 482 goto end; 483 } 484 485 ext3 = ExAllocatePoolWithTag(PagedPool, offsetof(VOLUME_DISK_EXTENTS, Extents[0]) + (max_extents * sizeof(DISK_EXTENT)), ALLOC_TAG); 486 if (!ext3) { 487 ERR("out of memory\n"); 488 Status = STATUS_INSUFFICIENT_RESOURCES; 489 goto end; 490 } 491 492 i = 0; 493 ext->NumberOfDiskExtents = 0; 494 495 le = pdode->children.Flink; 496 while (le != &pdode->children) { 497 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 498 499 Status = dev_ioctl(vc->devobj, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, ext3, 500 (ULONG)offsetof(VOLUME_DISK_EXTENTS, Extents[0]) + (max_extents * sizeof(DISK_EXTENT)), FALSE, NULL); 501 if (!NT_SUCCESS(Status)) { 502 ERR("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS returned %08x\n", Status); 503 ExFreePool(ext3); 504 goto end; 505 } 506 507 if (i + ext3->NumberOfDiskExtents > num_extents) { 508 Irp->IoStatus.Information = offsetof(VOLUME_DISK_EXTENTS, Extents[0]); 509 ext->NumberOfDiskExtents = i + ext3->NumberOfDiskExtents; 510 Status = STATUS_BUFFER_OVERFLOW; 511 ExFreePool(ext3); 512 goto end; 513 } 514 515 RtlCopyMemory(&ext->Extents[i], ext3->Extents, sizeof(DISK_EXTENT) * ext3->NumberOfDiskExtents); 516 i += ext3->NumberOfDiskExtents; 517 518 le = le->Flink; 519 } 520 521 ExFreePool(ext3); 522 523 Status = STATUS_SUCCESS; 524 525 ext->NumberOfDiskExtents = i; 526 Irp->IoStatus.Information = offsetof(VOLUME_DISK_EXTENTS, Extents[0]) + (i * sizeof(DISK_EXTENT)); 527 528 end: 529 ExReleaseResourceLite(&pdode->child_lock); 530 531 return Status; 532 } 533 534 static NTSTATUS vol_is_writable(volume_device_extension* vde) { 535 pdo_device_extension* pdode = vde->pdode; 536 NTSTATUS Status; 537 LIST_ENTRY* le; 538 BOOL writable = FALSE; 539 540 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 541 542 le = pdode->children.Flink; 543 while (le != &pdode->children) { 544 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 545 546 Status = dev_ioctl(vc->devobj, IOCTL_DISK_IS_WRITABLE, NULL, 0, NULL, 0, TRUE, NULL); 547 548 if (NT_SUCCESS(Status)) { 549 writable = TRUE; 550 break; 551 } else if (Status != STATUS_MEDIA_WRITE_PROTECTED) 552 goto end; 553 554 le = le->Flink; 555 } 556 557 Status = writable ? STATUS_SUCCESS : STATUS_MEDIA_WRITE_PROTECTED; 558 559 end: 560 ExReleaseResourceLite(&pdode->child_lock); 561 562 return STATUS_SUCCESS; 563 } 564 565 static NTSTATUS vol_get_length(volume_device_extension* vde, PIRP Irp) { 566 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 567 pdo_device_extension* pdode = vde->pdode; 568 GET_LENGTH_INFORMATION* gli; 569 LIST_ENTRY* le; 570 571 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_LENGTH_INFORMATION)) 572 return STATUS_BUFFER_TOO_SMALL; 573 574 gli = (GET_LENGTH_INFORMATION*)Irp->AssociatedIrp.SystemBuffer; 575 576 gli->Length.QuadPart = 0; 577 578 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 579 580 le = pdode->children.Flink; 581 while (le != &pdode->children) { 582 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 583 584 gli->Length.QuadPart += vc->size; 585 586 le = le->Flink; 587 } 588 589 ExReleaseResourceLite(&pdode->child_lock); 590 591 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION); 592 593 return STATUS_SUCCESS; 594 } 595 596 static NTSTATUS vol_get_drive_geometry(PDEVICE_OBJECT DeviceObject, PIRP Irp) { 597 volume_device_extension* vde = DeviceObject->DeviceExtension; 598 pdo_device_extension* pdode = vde->pdode; 599 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 600 DISK_GEOMETRY* geom; 601 UINT64 length; 602 LIST_ENTRY* le; 603 604 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)) 605 return STATUS_BUFFER_TOO_SMALL; 606 607 length = 0; 608 609 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 610 611 le = pdode->children.Flink; 612 while (le != &pdode->children) { 613 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 614 615 length += vc->size; 616 617 le = le->Flink; 618 } 619 620 ExReleaseResourceLite(&pdode->child_lock); 621 622 geom = (DISK_GEOMETRY*)Irp->AssociatedIrp.SystemBuffer; 623 geom->BytesPerSector = DeviceObject->SectorSize == 0 ? 0x200 : DeviceObject->SectorSize; 624 geom->SectorsPerTrack = 0x3f; 625 geom->TracksPerCylinder = 0xff; 626 geom->Cylinders.QuadPart = length / (UInt32x32To64(geom->TracksPerCylinder, geom->SectorsPerTrack) * geom->BytesPerSector); 627 geom->MediaType = DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA ? RemovableMedia : FixedMedia; 628 629 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY); 630 631 return STATUS_SUCCESS; 632 } 633 634 static NTSTATUS vol_get_gpt_attributes(PIRP Irp) { 635 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 636 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION* vggai; 637 638 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION)) 639 return STATUS_BUFFER_TOO_SMALL; 640 641 vggai = (VOLUME_GET_GPT_ATTRIBUTES_INFORMATION*)Irp->AssociatedIrp.SystemBuffer; 642 643 vggai->GptAttributes = 0; 644 645 Irp->IoStatus.Information = sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION); 646 647 return STATUS_SUCCESS; 648 } 649 650 static NTSTATUS vol_get_device_number(volume_device_extension* vde, PIRP Irp) { 651 pdo_device_extension* pdode = vde->pdode; 652 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 653 volume_child* vc; 654 STORAGE_DEVICE_NUMBER* sdn; 655 656 // If only one device, return its disk number. This is needed for ejection to work. 657 658 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DEVICE_NUMBER)) 659 return STATUS_BUFFER_TOO_SMALL; 660 661 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 662 663 if (IsListEmpty(&pdode->children) || pdode->num_children > 1) { 664 ExReleaseResourceLite(&pdode->child_lock); 665 return STATUS_INVALID_DEVICE_REQUEST; 666 } 667 668 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry); 669 670 if (vc->disk_num == 0xffffffff) { 671 ExReleaseResourceLite(&pdode->child_lock); 672 return STATUS_INVALID_DEVICE_REQUEST; 673 } 674 675 sdn = (STORAGE_DEVICE_NUMBER*)Irp->AssociatedIrp.SystemBuffer; 676 677 sdn->DeviceType = FILE_DEVICE_DISK; 678 sdn->DeviceNumber = vc->disk_num; 679 sdn->PartitionNumber = vc->part_num; 680 681 ExReleaseResourceLite(&pdode->child_lock); 682 683 Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER); 684 685 return STATUS_SUCCESS; 686 } 687 688 _Function_class_(IO_COMPLETION_ROUTINE) 689 #ifdef __REACTOS__ 690 static NTSTATUS NTAPI vol_ioctl_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) { 691 #else 692 static NTSTATUS vol_ioctl_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) { 693 #endif 694 KEVENT* event = conptr; 695 696 UNUSED(DeviceObject); 697 UNUSED(Irp); 698 699 KeSetEvent(event, 0, FALSE); 700 701 return STATUS_MORE_PROCESSING_REQUIRED; 702 } 703 704 static NTSTATUS vol_ioctl_passthrough(volume_device_extension* vde, PIRP Irp) { 705 NTSTATUS Status; 706 volume_child* vc; 707 PIRP Irp2; 708 PIO_STACK_LOCATION IrpSp, IrpSp2; 709 KEVENT Event; 710 pdo_device_extension* pdode = vde->pdode; 711 712 TRACE("(%p, %p)\n", vde, Irp); 713 714 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 715 716 if (IsListEmpty(&pdode->children)) { 717 ExReleaseResourceLite(&pdode->child_lock); 718 return STATUS_INVALID_DEVICE_REQUEST; 719 } 720 721 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry); 722 723 if (vc->list_entry.Flink != &pdode->children) { // more than one device 724 ExReleaseResourceLite(&pdode->child_lock); 725 return STATUS_INVALID_DEVICE_REQUEST; 726 } 727 728 Irp2 = IoAllocateIrp(vc->devobj->StackSize, FALSE); 729 730 if (!Irp2) { 731 ERR("IoAllocateIrp failed\n"); 732 ExReleaseResourceLite(&pdode->child_lock); 733 return STATUS_INSUFFICIENT_RESOURCES; 734 } 735 736 IrpSp = IoGetCurrentIrpStackLocation(Irp); 737 IrpSp2 = IoGetNextIrpStackLocation(Irp2); 738 739 IrpSp2->MajorFunction = IrpSp->MajorFunction; 740 IrpSp2->MinorFunction = IrpSp->MinorFunction; 741 742 IrpSp2->Parameters.DeviceIoControl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength; 743 IrpSp2->Parameters.DeviceIoControl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength; 744 IrpSp2->Parameters.DeviceIoControl.IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode; 745 IrpSp2->Parameters.DeviceIoControl.Type3InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; 746 747 Irp2->AssociatedIrp.SystemBuffer = Irp->AssociatedIrp.SystemBuffer; 748 Irp2->MdlAddress = Irp->MdlAddress; 749 Irp2->UserBuffer = Irp->UserBuffer; 750 Irp2->Flags = Irp->Flags; 751 752 KeInitializeEvent(&Event, NotificationEvent, FALSE); 753 754 IoSetCompletionRoutine(Irp2, vol_ioctl_completion, &Event, TRUE, TRUE, TRUE); 755 756 Status = IoCallDriver(vc->devobj, Irp2); 757 758 if (Status == STATUS_PENDING) { 759 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 760 Status = Irp2->IoStatus.Status; 761 } 762 763 Irp->IoStatus.Status = Irp2->IoStatus.Status; 764 Irp->IoStatus.Information = Irp2->IoStatus.Information; 765 766 ExReleaseResourceLite(&pdode->child_lock); 767 768 return Status; 769 } 770 771 NTSTATUS vol_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 772 volume_device_extension* vde = DeviceObject->DeviceExtension; 773 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 774 775 TRACE("(%p, %p)\n", DeviceObject, Irp); 776 777 Irp->IoStatus.Information = 0; 778 779 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { 780 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: 781 return vol_query_device_name(vde, Irp); 782 783 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: 784 return vol_query_unique_id(vde, Irp); 785 786 case IOCTL_STORAGE_GET_DEVICE_NUMBER: 787 return vol_get_device_number(vde, Irp); 788 789 case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: 790 TRACE("unhandled control code IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME\n"); 791 break; 792 793 case IOCTL_MOUNTDEV_QUERY_STABLE_GUID: 794 TRACE("unhandled control code IOCTL_MOUNTDEV_QUERY_STABLE_GUID\n"); 795 break; 796 797 case IOCTL_MOUNTDEV_LINK_CREATED: 798 TRACE("unhandled control code IOCTL_MOUNTDEV_LINK_CREATED\n"); 799 break; 800 801 case IOCTL_VOLUME_GET_GPT_ATTRIBUTES: 802 return vol_get_gpt_attributes(Irp); 803 804 case IOCTL_VOLUME_IS_DYNAMIC: 805 return vol_is_dynamic(Irp); 806 807 case IOCTL_VOLUME_ONLINE: 808 TRACE("unhandled control code IOCTL_VOLUME_ONLINE\n"); 809 break; 810 811 case IOCTL_VOLUME_POST_ONLINE: 812 TRACE("unhandled control code IOCTL_VOLUME_POST_ONLINE\n"); 813 break; 814 815 case IOCTL_DISK_GET_DRIVE_GEOMETRY: 816 return vol_get_drive_geometry(DeviceObject, Irp); 817 818 case IOCTL_DISK_IS_WRITABLE: 819 return vol_is_writable(vde); 820 821 case IOCTL_DISK_GET_LENGTH_INFO: 822 return vol_get_length(vde, Irp); 823 824 case IOCTL_STORAGE_CHECK_VERIFY: 825 case IOCTL_DISK_CHECK_VERIFY: 826 return vol_check_verify(vde); 827 828 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS: 829 return vol_get_disk_extents(vde, Irp); 830 831 default: // pass ioctl through if only one child device 832 return vol_ioctl_passthrough(vde, Irp); 833 } 834 835 return STATUS_INVALID_DEVICE_REQUEST; 836 } 837 838 NTSTATUS vol_shutdown(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 839 TRACE("(%p, %p)\n", DeviceObject, Irp); 840 841 return STATUS_INVALID_DEVICE_REQUEST; 842 } 843 844 NTSTATUS vol_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 845 TRACE("(%p, %p)\n", DeviceObject, Irp); 846 847 return STATUS_INVALID_DEVICE_REQUEST; 848 } 849 850 NTSTATUS vol_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 851 TRACE("(%p, %p)\n", DeviceObject, Irp); 852 853 return STATUS_INVALID_DEVICE_REQUEST; 854 } 855 856 NTSTATUS vol_power(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { 857 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 858 NTSTATUS Status; 859 860 TRACE("(%p, %p)\n", DeviceObject, Irp); 861 862 if (IrpSp->MinorFunction == IRP_MN_SET_POWER || IrpSp->MinorFunction == IRP_MN_QUERY_POWER) 863 Irp->IoStatus.Status = STATUS_SUCCESS; 864 865 Status = Irp->IoStatus.Status; 866 PoStartNextPowerIrp(Irp); 867 868 return Status; 869 } 870 871 NTSTATUS mountmgr_add_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath) { 872 NTSTATUS Status; 873 ULONG mmdltsize; 874 MOUNTMGR_DRIVE_LETTER_TARGET* mmdlt; 875 MOUNTMGR_DRIVE_LETTER_INFORMATION mmdli; 876 877 mmdltsize = (ULONG)offsetof(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName[0]) + devpath->Length; 878 879 mmdlt = ExAllocatePoolWithTag(NonPagedPool, mmdltsize, ALLOC_TAG); 880 if (!mmdlt) { 881 ERR("out of memory\n"); 882 return STATUS_INSUFFICIENT_RESOURCES; 883 } 884 885 mmdlt->DeviceNameLength = devpath->Length; 886 RtlCopyMemory(&mmdlt->DeviceName, devpath->Buffer, devpath->Length); 887 TRACE("mmdlt = %.*S\n", mmdlt->DeviceNameLength / sizeof(WCHAR), mmdlt->DeviceName); 888 889 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER, mmdlt, mmdltsize, &mmdli, sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION), FALSE, NULL); 890 891 if (!NT_SUCCESS(Status)) 892 ERR("IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER returned %08x\n", Status); 893 else 894 TRACE("DriveLetterWasAssigned = %u, CurrentDriveLetter = %c\n", mmdli.DriveLetterWasAssigned, mmdli.CurrentDriveLetter); 895 896 ExFreePool(mmdlt); 897 898 return Status; 899 } 900 901 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE) 902 #ifdef __REACTOS__ 903 NTSTATUS NTAPI pnp_removal(PVOID NotificationStructure, PVOID Context) { 904 #else 905 NTSTATUS pnp_removal(PVOID NotificationStructure, PVOID Context) { 906 #endif 907 TARGET_DEVICE_REMOVAL_NOTIFICATION* tdrn = (TARGET_DEVICE_REMOVAL_NOTIFICATION*)NotificationStructure; 908 pdo_device_extension* pdode = (pdo_device_extension*)Context; 909 910 if (RtlCompareMemory(&tdrn->Event, &GUID_TARGET_DEVICE_QUERY_REMOVE, sizeof(GUID)) == sizeof(GUID)) { 911 TRACE("GUID_TARGET_DEVICE_QUERY_REMOVE\n"); 912 913 if (pdode->vde && pdode->vde->mounted_device) 914 return pnp_query_remove_device(pdode->vde->mounted_device, NULL); 915 } 916 917 return STATUS_SUCCESS; 918 } 919 920 static BOOL allow_degraded_mount(BTRFS_UUID* uuid) { 921 HANDLE h; 922 NTSTATUS Status; 923 OBJECT_ATTRIBUTES oa; 924 UNICODE_STRING path, adus; 925 UINT32 degraded = mount_allow_degraded; 926 ULONG i, j, kvfilen, retlen; 927 KEY_VALUE_FULL_INFORMATION* kvfi; 928 929 path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR)); 930 path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG); 931 932 if (!path.Buffer) { 933 ERR("out of memory\n"); 934 return FALSE; 935 } 936 937 RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length); 938 i = registry_path.Length / sizeof(WCHAR); 939 940 path.Buffer[i] = '\\'; 941 i++; 942 943 for (j = 0; j < 16; j++) { 944 path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4); 945 path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF); 946 947 i += 2; 948 949 if (j == 3 || j == 5 || j == 7 || j == 9) { 950 path.Buffer[i] = '-'; 951 i++; 952 } 953 } 954 955 InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); 956 957 kvfilen = (ULONG)offsetof(KEY_VALUE_FULL_INFORMATION, Name[0]) + (255 * sizeof(WCHAR)); 958 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG); 959 if (!kvfi) { 960 ERR("out of memory\n"); 961 ExFreePool(path.Buffer); 962 return FALSE; 963 } 964 965 Status = ZwOpenKey(&h, KEY_QUERY_VALUE, &oa); 966 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 967 goto end; 968 else if (!NT_SUCCESS(Status)) { 969 ERR("ZwOpenKey returned %08x\n", Status); 970 goto end; 971 } 972 973 adus.Buffer = L"AllowDegraded"; 974 adus.Length = adus.MaximumLength = (USHORT)(wcslen(adus.Buffer) * sizeof(WCHAR)); 975 976 if (NT_SUCCESS(ZwQueryValueKey(h, &adus, KeyValueFullInformation, kvfi, kvfilen, &retlen))) { 977 if (kvfi->Type == REG_DWORD && kvfi->DataLength >= sizeof(UINT32)) { 978 UINT32* val = (UINT32*)((UINT8*)kvfi + kvfi->DataOffset); 979 980 degraded = *val; 981 } 982 } 983 984 ZwClose(h); 985 986 end: 987 ExFreePool(kvfi); 988 989 ExFreePool(path.Buffer); 990 991 return degraded; 992 } 993 994 void add_volume_device(superblock* sb, PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath, UINT64 length, ULONG disk_num, ULONG part_num) { 995 NTSTATUS Status; 996 LIST_ENTRY* le; 997 PDEVICE_OBJECT DeviceObject; 998 volume_child* vc; 999 PFILE_OBJECT FileObject; 1000 UNICODE_STRING devpath2; 1001 BOOL inserted = FALSE, new_pdo = FALSE; 1002 pdo_device_extension* pdode = NULL; 1003 PDEVICE_OBJECT pdo = NULL; 1004 1005 if (devpath->Length == 0) 1006 return; 1007 1008 ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE); 1009 1010 le = pdo_list.Flink; 1011 while (le != &pdo_list) { 1012 pdo_device_extension* pdode2 = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 1013 1014 if (RtlCompareMemory(&pdode2->uuid, &sb->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 1015 pdode = pdode2; 1016 break; 1017 } 1018 1019 le = le->Flink; 1020 } 1021 1022 Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject); 1023 if (!NT_SUCCESS(Status)) { 1024 ERR("IoGetDeviceObjectPointer returned %08x\n", Status); 1025 ExReleaseResourceLite(&pdo_list_lock); 1026 return; 1027 } 1028 1029 if (!pdode) { 1030 if (no_pnp) { 1031 Status = IoReportDetectedDevice(drvobj, InterfaceTypeUndefined, 0xFFFFFFFF, 0xFFFFFFFF, NULL, NULL, 0, &pdo); 1032 1033 if (!NT_SUCCESS(Status)) { 1034 ERR("IoReportDetectedDevice returned %08x\n", Status); 1035 ExReleaseResourceLite(&pdo_list_lock); 1036 return; 1037 } 1038 1039 pdode = ExAllocatePoolWithTag(NonPagedPool, sizeof(pdo_device_extension), ALLOC_TAG); 1040 1041 if (!pdode) { 1042 ERR("out of memory\n"); 1043 ExReleaseResourceLite(&pdo_list_lock); 1044 return; 1045 } 1046 } else { 1047 Status = IoCreateDevice(drvobj, sizeof(pdo_device_extension), NULL, FILE_DEVICE_DISK, 1048 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &pdo); 1049 if (!NT_SUCCESS(Status)) { 1050 ERR("IoCreateDevice returned %08x\n", Status); 1051 ExReleaseResourceLite(&pdo_list_lock); 1052 goto fail; 1053 } 1054 1055 pdo->Flags |= DO_BUS_ENUMERATED_DEVICE; 1056 1057 pdode = pdo->DeviceExtension; 1058 } 1059 1060 RtlZeroMemory(pdode, sizeof(pdo_device_extension)); 1061 1062 pdode->type = VCB_TYPE_PDO; 1063 pdode->pdo = pdo; 1064 pdode->uuid = sb->uuid; 1065 1066 ExInitializeResourceLite(&pdode->child_lock); 1067 InitializeListHead(&pdode->children); 1068 pdode->num_children = sb->num_devices; 1069 pdode->children_loaded = 0; 1070 1071 pdo->Flags &= ~DO_DEVICE_INITIALIZING; 1072 pdo->SectorSize = (USHORT)sb->sector_size; 1073 1074 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); 1075 1076 new_pdo = TRUE; 1077 } else { 1078 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); 1079 ExConvertExclusiveToSharedLite(&pdo_list_lock); 1080 1081 le = pdode->children.Flink; 1082 while (le != &pdode->children) { 1083 volume_child* vc2 = CONTAINING_RECORD(le, volume_child, list_entry); 1084 1085 if (RtlCompareMemory(&vc2->uuid, &sb->dev_item.device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 1086 // duplicate, ignore 1087 ExReleaseResourceLite(&pdode->child_lock); 1088 ExReleaseResourceLite(&pdo_list_lock); 1089 goto fail; 1090 } 1091 1092 le = le->Flink; 1093 } 1094 } 1095 1096 vc = ExAllocatePoolWithTag(PagedPool, sizeof(volume_child), ALLOC_TAG); 1097 if (!vc) { 1098 ERR("out of memory\n"); 1099 1100 ExReleaseResourceLite(&pdode->child_lock); 1101 ExReleaseResourceLite(&pdo_list_lock); 1102 1103 goto fail; 1104 } 1105 1106 vc->uuid = sb->dev_item.device_uuid; 1107 vc->devid = sb->dev_item.dev_id; 1108 vc->generation = sb->generation; 1109 vc->notification_entry = NULL; 1110 1111 Status = IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange, 0, FileObject, 1112 drvobj, pnp_removal, pdode, &vc->notification_entry); 1113 if (!NT_SUCCESS(Status)) 1114 WARN("IoRegisterPlugPlayNotification returned %08x\n", Status); 1115 1116 vc->devobj = DeviceObject; 1117 vc->fileobj = FileObject; 1118 1119 devpath2 = *devpath; 1120 1121 // The PNP path sometimes begins \\?\ and sometimes \??\. We need to remove this prefix 1122 // so we can compare properly if the device is removed. 1123 if (devpath->Length > 4 * sizeof(WCHAR) && devpath->Buffer[0] == '\\' && (devpath->Buffer[1] == '\\' || devpath->Buffer[1] == '?') && 1124 devpath->Buffer[2] == '?' && devpath->Buffer[3] == '\\') { 1125 devpath2.Buffer = &devpath2.Buffer[3]; 1126 devpath2.Length -= 3 * sizeof(WCHAR); 1127 devpath2.MaximumLength -= 3 * sizeof(WCHAR); 1128 } 1129 1130 vc->pnp_name.Length = vc->pnp_name.MaximumLength = devpath2.Length; 1131 vc->pnp_name.Buffer = ExAllocatePoolWithTag(PagedPool, devpath2.Length, ALLOC_TAG); 1132 1133 if (vc->pnp_name.Buffer) 1134 RtlCopyMemory(vc->pnp_name.Buffer, devpath2.Buffer, devpath2.Length); 1135 else { 1136 ERR("out of memory\n"); 1137 vc->pnp_name.Length = vc->pnp_name.MaximumLength = 0; 1138 } 1139 1140 vc->size = length; 1141 vc->seeding = sb->flags & BTRFS_SUPERBLOCK_FLAGS_SEEDING ? TRUE : FALSE; 1142 vc->disk_num = disk_num; 1143 vc->part_num = part_num; 1144 vc->had_drive_letter = FALSE; 1145 1146 le = pdode->children.Flink; 1147 while (le != &pdode->children) { 1148 volume_child* vc2 = CONTAINING_RECORD(le, volume_child, list_entry); 1149 1150 if (vc2->generation < vc->generation) { 1151 if (le == pdode->children.Flink) 1152 pdode->num_children = sb->num_devices; 1153 1154 InsertHeadList(vc2->list_entry.Blink, &vc->list_entry); 1155 inserted = TRUE; 1156 break; 1157 } 1158 1159 le = le->Flink; 1160 } 1161 1162 if (!inserted) 1163 InsertTailList(&pdode->children, &vc->list_entry); 1164 1165 pdode->children_loaded++; 1166 1167 if (pdode->vde && pdode->vde->mounted_device) { 1168 device_extension* Vcb = pdode->vde->mounted_device->DeviceExtension; 1169 1170 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 1171 1172 le = Vcb->devices.Flink; 1173 while (le != &Vcb->devices) { 1174 device* dev = CONTAINING_RECORD(le, device, list_entry); 1175 1176 if (!dev->devobj && RtlCompareMemory(&dev->devitem.device_uuid, &sb->dev_item.device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 1177 dev->devobj = DeviceObject; 1178 dev->disk_num = disk_num; 1179 dev->part_num = part_num; 1180 init_device(Vcb, dev, FALSE); 1181 break; 1182 } 1183 1184 le = le->Flink; 1185 } 1186 1187 ExReleaseResourceLite(&Vcb->tree_lock); 1188 } 1189 1190 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { 1191 pdode->removable = TRUE; 1192 1193 if (pdode->vde && pdode->vde->device) 1194 pdode->vde->device->Characteristics |= FILE_REMOVABLE_MEDIA; 1195 } 1196 1197 if (pdode->num_children == pdode->children_loaded || (pdode->children_loaded == 1 && allow_degraded_mount(&sb->uuid))) { 1198 if (pdode->num_children == 1) { 1199 Status = remove_drive_letter(mountmgr, devpath); 1200 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) 1201 WARN("remove_drive_letter returned %08x\n", Status); 1202 1203 vc->had_drive_letter = NT_SUCCESS(Status); 1204 } else { 1205 le = pdode->children.Flink; 1206 1207 while (le != &pdode->children) { 1208 UNICODE_STRING name; 1209 1210 vc = CONTAINING_RECORD(le, volume_child, list_entry); 1211 1212 name.Length = name.MaximumLength = vc->pnp_name.Length + (3 * sizeof(WCHAR)); 1213 name.Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG); 1214 1215 if (!name.Buffer) { 1216 ERR("out of memory\n"); 1217 1218 ExReleaseResourceLite(&pdode->child_lock); 1219 ExReleaseResourceLite(&pdo_list_lock); 1220 1221 goto fail; 1222 } 1223 1224 RtlCopyMemory(name.Buffer, L"\\??", 3 * sizeof(WCHAR)); 1225 RtlCopyMemory(&name.Buffer[3], vc->pnp_name.Buffer, vc->pnp_name.Length); 1226 1227 Status = remove_drive_letter(mountmgr, &name); 1228 1229 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) 1230 WARN("remove_drive_letter returned %08x\n", Status); 1231 1232 ExFreePool(name.Buffer); 1233 1234 vc->had_drive_letter = NT_SUCCESS(Status); 1235 1236 le = le->Flink; 1237 } 1238 } 1239 1240 if ((!new_pdo || !no_pnp) && pdode->vde) { 1241 Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, TRUE); 1242 if (!NT_SUCCESS(Status)) 1243 WARN("IoSetDeviceInterfaceState returned %08x\n", Status); 1244 } 1245 } 1246 1247 ExReleaseResourceLite(&pdode->child_lock); 1248 1249 if (new_pdo) { 1250 control_device_extension* cde = master_devobj->DeviceExtension; 1251 1252 InsertTailList(&pdo_list, &pdode->list_entry); 1253 1254 if (!no_pnp) 1255 IoInvalidateDeviceRelations(cde->buspdo, BusRelations); 1256 } 1257 1258 ExReleaseResourceLite(&pdo_list_lock); 1259 1260 if (new_pdo && no_pnp) 1261 AddDevice(drvobj, pdo); 1262 1263 return; 1264 1265 fail: 1266 ObDereferenceObject(FileObject); 1267 } 1268