1 /* 2 * ReactOS kernel 3 * Copyright (C) 2011 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program 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 General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 18 * 19 * COPYRIGHT: See COPYING in the top level directory 20 * PROJECT: ReactOS kernel 21 * FILE: drivers/filesystem/mountmgr/notify.c 22 * PURPOSE: Mount Manager - Notifications handlers 23 * PROGRAMMER: Pierre Schweitzer (pierre.schweitzer@reactos.org) 24 * Alex Ionescu (alex.ionescu@reactos.org) 25 */ 26 27 #include "mntmgr.h" 28 29 #include <ioevent.h> 30 31 #define NDEBUG 32 #include <debug.h> 33 34 /* 35 * @implemented 36 */ 37 VOID 38 SendOnlineNotification(IN PUNICODE_STRING SymbolicName) 39 { 40 PIRP Irp; 41 KEVENT Event; 42 NTSTATUS Status; 43 PFILE_OBJECT FileObject; 44 PIO_STACK_LOCATION Stack; 45 PDEVICE_OBJECT DeviceObject; 46 IO_STATUS_BLOCK IoStatusBlock; 47 48 /* Get device object */ 49 Status = IoGetDeviceObjectPointer(SymbolicName, 50 FILE_READ_ATTRIBUTES, 51 &FileObject, 52 &DeviceObject); 53 if (!NT_SUCCESS(Status)) 54 { 55 return; 56 } 57 58 /* And attached device object */ 59 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 60 61 /* And send VOLUME_ONLINE */ 62 KeInitializeEvent(&Event, NotificationEvent, FALSE); 63 Irp = IoBuildDeviceIoControlRequest(IOCTL_VOLUME_ONLINE, 64 DeviceObject, 65 NULL, 0, 66 NULL, 0, 67 FALSE, 68 &Event, 69 &IoStatusBlock); 70 if (!Irp) 71 { 72 goto Cleanup; 73 } 74 75 Stack = IoGetNextIrpStackLocation(Irp); 76 Stack->FileObject = FileObject; 77 78 Status = IoCallDriver(DeviceObject, Irp); 79 if (Status == STATUS_PENDING) 80 { 81 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 82 } 83 84 Cleanup: 85 ObDereferenceObject(DeviceObject); 86 ObDereferenceObject(FileObject); 87 88 return; 89 } 90 91 /* 92 * @implemented 93 */ 94 VOID 95 NTAPI 96 SendOnlineNotificationWorker(IN PVOID Parameter) 97 { 98 KIRQL OldIrql; 99 PLIST_ENTRY Head; 100 PDEVICE_EXTENSION DeviceExtension; 101 PONLINE_NOTIFICATION_WORK_ITEM WorkItem; 102 PONLINE_NOTIFICATION_WORK_ITEM NewWorkItem; 103 104 WorkItem = (PONLINE_NOTIFICATION_WORK_ITEM)Parameter; 105 DeviceExtension = WorkItem->DeviceExtension; 106 107 /* First, send the notification */ 108 SendOnlineNotification(&(WorkItem->SymbolicName)); 109 110 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql); 111 /* If there are no notifications running any longer, reset event */ 112 if (--DeviceExtension->OnlineNotificationCount == 0) 113 { 114 KeSetEvent(&(DeviceExtension->OnlineNotificationEvent), 0, FALSE); 115 } 116 117 /* If there are still notifications in queue */ 118 if (!IsListEmpty(&(DeviceExtension->OnlineNotificationListHead))) 119 { 120 /* Queue a new one for execution */ 121 Head = RemoveHeadList(&(DeviceExtension->OnlineNotificationListHead)); 122 NewWorkItem = CONTAINING_RECORD(Head, ONLINE_NOTIFICATION_WORK_ITEM, WorkItem.List); 123 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql); 124 NewWorkItem->WorkItem.List.Blink = NULL; 125 NewWorkItem->WorkItem.List.Flink = NULL; 126 ExQueueWorkItem(&NewWorkItem->WorkItem, DelayedWorkQueue); 127 } 128 else 129 { 130 /* Mark it's over */ 131 DeviceExtension->OnlineNotificationWorkerActive = 0; 132 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql); 133 } 134 135 FreePool(WorkItem->SymbolicName.Buffer); 136 FreePool(WorkItem); 137 138 return; 139 } 140 141 /* 142 * @implemented 143 */ 144 VOID 145 PostOnlineNotification(IN PDEVICE_EXTENSION DeviceExtension, 146 IN PUNICODE_STRING SymbolicName) 147 { 148 KIRQL OldIrql; 149 PONLINE_NOTIFICATION_WORK_ITEM WorkItem; 150 151 /* Allocate a notification work item */ 152 WorkItem = AllocatePool(sizeof(ONLINE_NOTIFICATION_WORK_ITEM)); 153 if (!WorkItem) 154 { 155 return; 156 } 157 158 ExInitializeWorkItem(&WorkItem->WorkItem, SendOnlineNotificationWorker, WorkItem); 159 WorkItem->DeviceExtension = DeviceExtension; 160 WorkItem->SymbolicName.Length = SymbolicName->Length; 161 WorkItem->SymbolicName.MaximumLength = SymbolicName->Length + sizeof(WCHAR); 162 WorkItem->SymbolicName.Buffer = AllocatePool(WorkItem->SymbolicName.MaximumLength); 163 if (!WorkItem->SymbolicName.Buffer) 164 { 165 FreePool(WorkItem); 166 return; 167 } 168 169 RtlCopyMemory(WorkItem->SymbolicName.Buffer, SymbolicName->Buffer, SymbolicName->Length); 170 WorkItem->SymbolicName.Buffer[SymbolicName->Length / sizeof(WCHAR)] = UNICODE_NULL; 171 172 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql); 173 DeviceExtension->OnlineNotificationCount++; 174 175 /* If no worker are active */ 176 if (DeviceExtension->OnlineNotificationWorkerActive == 0) 177 { 178 /* Queue that one for execution */ 179 DeviceExtension->OnlineNotificationWorkerActive = 1; 180 ExQueueWorkItem(&WorkItem->WorkItem, DelayedWorkQueue); 181 } 182 else 183 { 184 /* Otherwise, just put it in the queue list */ 185 InsertTailList(&(DeviceExtension->OnlineNotificationListHead), &(WorkItem->WorkItem.List)); 186 } 187 188 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql); 189 190 return; 191 } 192 193 /* 194 * @implemented 195 */ 196 VOID 197 WaitForOnlinesToComplete(IN PDEVICE_EXTENSION DeviceExtension) 198 { 199 KIRQL OldIrql; 200 201 KeInitializeEvent(&(DeviceExtension->OnlineNotificationEvent), NotificationEvent, FALSE); 202 203 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql); 204 205 /* Just wait all the worker are done */ 206 if (DeviceExtension->OnlineNotificationCount != 1) 207 { 208 DeviceExtension->OnlineNotificationCount--; 209 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql); 210 211 KeWaitForSingleObject(&(DeviceExtension->OnlineNotificationEvent), 212 Executive, 213 KernelMode, 214 FALSE, 215 NULL); 216 217 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql); 218 DeviceExtension->OnlineNotificationCount++; 219 } 220 221 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql); 222 } 223 224 /* 225 * @implemented 226 */ 227 NTSTATUS 228 NTAPI 229 MountMgrTargetDeviceNotification(IN PVOID NotificationStructure, 230 IN PVOID Context) 231 { 232 PDEVICE_EXTENSION DeviceExtension; 233 PDEVICE_INFORMATION DeviceInformation; 234 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification; 235 236 DeviceInformation = Context; 237 DeviceExtension = DeviceInformation->DeviceExtension; 238 Notification = NotificationStructure; 239 240 /* If it's to signal that removal is complete, then, execute the function */ 241 if (IsEqualGUID(&(Notification->Event), &GUID_TARGET_DEVICE_REMOVE_COMPLETE)) 242 { 243 MountMgrMountedDeviceRemoval(DeviceExtension, Notification->SymbolicLinkName); 244 } 245 /* It it's to signal that a volume has been mounted 246 * Verify if a database sync is required and execute it 247 */ 248 else if (IsEqualGUID(&(Notification->Event), &GUID_IO_VOLUME_MOUNT)) 249 { 250 /* If we were already mounted, then mark us unmounted */ 251 if (InterlockedCompareExchange(&(DeviceInformation->MountState), 252 FALSE, 253 FALSE) == TRUE) 254 { 255 InterlockedDecrement(&(DeviceInformation->MountState)); 256 } 257 /* Otherwise, start mounting the device and first, reconcile its DB if required */ 258 else 259 { 260 if (DeviceInformation->NeedsReconcile) 261 { 262 DeviceInformation->NeedsReconcile = FALSE; 263 ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation); 264 } 265 } 266 } 267 268 return STATUS_SUCCESS; 269 } 270 271 /* 272 * @implemented 273 */ 274 VOID 275 RegisterForTargetDeviceNotification(IN PDEVICE_EXTENSION DeviceExtension, 276 IN PDEVICE_INFORMATION DeviceInformation) 277 { 278 NTSTATUS Status; 279 PFILE_OBJECT FileObject; 280 PDEVICE_OBJECT DeviceObject; 281 282 /* Get device object */ 283 Status = IoGetDeviceObjectPointer(&(DeviceInformation->DeviceName), 284 FILE_READ_ATTRIBUTES, 285 &FileObject, 286 &DeviceObject); 287 if (!NT_SUCCESS(Status)) 288 { 289 return; 290 } 291 292 /* And simply register for notifications */ 293 Status = IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange, 294 0, FileObject, 295 DeviceExtension->DriverObject, 296 MountMgrTargetDeviceNotification, 297 DeviceInformation, 298 &(DeviceInformation->TargetDeviceNotificationEntry)); 299 if (!NT_SUCCESS(Status)) 300 { 301 DeviceInformation->TargetDeviceNotificationEntry = NULL; 302 } 303 304 ObDereferenceObject(FileObject); 305 306 return; 307 } 308 309 /* 310 * @implemented 311 */ 312 VOID 313 MountMgrNotify(IN PDEVICE_EXTENSION DeviceExtension) 314 { 315 PIRP Irp; 316 KIRQL OldIrql; 317 LIST_ENTRY CopyList; 318 PLIST_ENTRY NextEntry; 319 320 /* Increase the epic number */ 321 DeviceExtension->EpicNumber++; 322 323 InitializeListHead(&CopyList); 324 325 /* Copy all the pending IRPs for notification */ 326 IoAcquireCancelSpinLock(&OldIrql); 327 while (!IsListEmpty(&(DeviceExtension->IrpListHead))) 328 { 329 NextEntry = RemoveHeadList(&(DeviceExtension->IrpListHead)); 330 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); 331 IoSetCancelRoutine(Irp, NULL); 332 InsertTailList(&CopyList, &(Irp->Tail.Overlay.ListEntry)); 333 } 334 IoReleaseCancelSpinLock(OldIrql); 335 336 /* Then, notify them one by one */ 337 while (!IsListEmpty(&CopyList)) 338 { 339 NextEntry = RemoveHeadList(&CopyList); 340 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); 341 342 *((PULONG)Irp->AssociatedIrp.SystemBuffer) = DeviceExtension->EpicNumber; 343 Irp->IoStatus.Information = sizeof(DeviceExtension->EpicNumber); 344 345 IoCompleteRequest(Irp, IO_NO_INCREMENT); 346 } 347 } 348 349 /* 350 * @implemented 351 */ 352 VOID 353 MountMgrNotifyNameChange(IN PDEVICE_EXTENSION DeviceExtension, 354 IN PUNICODE_STRING DeviceName, 355 IN BOOLEAN ValidateVolume) 356 { 357 PIRP Irp; 358 KEVENT Event; 359 NTSTATUS Status; 360 PLIST_ENTRY NextEntry; 361 PFILE_OBJECT FileObject; 362 PIO_STACK_LOCATION Stack; 363 PDEVICE_OBJECT DeviceObject; 364 IO_STATUS_BLOCK IoStatusBlock; 365 PDEVICE_RELATIONS DeviceRelations; 366 PDEVICE_INFORMATION DeviceInformation; 367 TARGET_DEVICE_CUSTOM_NOTIFICATION DeviceNotification; 368 369 /* If we have to validate volume */ 370 if (ValidateVolume) 371 { 372 /* Then, ensure we can find the device */ 373 for (NextEntry = DeviceExtension->DeviceListHead.Flink; 374 NextEntry != &DeviceExtension->DeviceListHead; 375 NextEntry = NextEntry->Flink) 376 { 377 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry); 378 if (RtlCompareUnicodeString(DeviceName, &(DeviceInformation->DeviceName), TRUE) == 0) 379 { 380 break; 381 } 382 } 383 384 /* No need to notify for a PnP device or if we didn't find the device */ 385 if (NextEntry == &(DeviceExtension->DeviceListHead) || 386 !DeviceInformation->ManuallyRegistered) 387 { 388 return; 389 } 390 } 391 392 /* Then, get device object */ 393 Status = IoGetDeviceObjectPointer(DeviceName, 394 FILE_READ_ATTRIBUTES, 395 &FileObject, 396 &DeviceObject); 397 if (!NT_SUCCESS(Status)) 398 { 399 return; 400 } 401 402 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 403 404 KeInitializeEvent(&Event, NotificationEvent, FALSE); 405 406 /* Set up empty IRP (yes, yes!) */ 407 Irp = IoBuildDeviceIoControlRequest(0, 408 DeviceObject, 409 NULL, 410 0, 411 NULL, 412 0, 413 FALSE, 414 &Event, 415 &IoStatusBlock); 416 if (!Irp) 417 { 418 ObDereferenceObject(DeviceObject); 419 ObDereferenceObject(FileObject); 420 return; 421 } 422 423 Stack = IoGetNextIrpStackLocation(Irp); 424 425 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 426 Irp->IoStatus.Information = 0; 427 428 /* Properly set it, we want to query device relations */ 429 Stack->MajorFunction = IRP_MJ_PNP; 430 Stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS; 431 Stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation; 432 Stack->FileObject = FileObject; 433 434 /* And call driver */ 435 Status = IoCallDriver(DeviceObject, Irp); 436 if (Status == STATUS_PENDING) 437 { 438 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 439 Status = IoStatusBlock.Status; 440 } 441 442 ObDereferenceObject(DeviceObject); 443 ObDereferenceObject(FileObject); 444 445 if (!NT_SUCCESS(Status)) 446 { 447 return; 448 } 449 450 /* Validate device return */ 451 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information; 452 if (DeviceRelations->Count < 1) 453 { 454 ExFreePool(DeviceRelations); 455 return; 456 } 457 458 DeviceObject = DeviceRelations->Objects[0]; 459 ExFreePool(DeviceRelations); 460 461 /* Set up real notification */ 462 DeviceNotification.Version = 1; 463 DeviceNotification.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION); 464 DeviceNotification.Event = GUID_IO_VOLUME_NAME_CHANGE; 465 DeviceNotification.FileObject = NULL; 466 DeviceNotification.NameBufferOffset = -1; 467 468 /* And report */ 469 IoReportTargetDeviceChangeAsynchronous(DeviceObject, 470 &DeviceNotification, 471 NULL, NULL); 472 473 ObDereferenceObject(DeviceObject); 474 475 return; 476 } 477 478 /* 479 * @implemented 480 */ 481 VOID 482 RemoveWorkItem(IN PUNIQUE_ID_WORK_ITEM WorkItem) 483 { 484 PDEVICE_EXTENSION DeviceExtension = WorkItem->DeviceExtension; 485 486 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 487 488 /* If even if being worked, it's too late */ 489 if (WorkItem->Event) 490 { 491 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 492 KeSetEvent(WorkItem->Event, 0, FALSE); 493 } 494 else 495 { 496 /* Otherwise, remove it from the list, and delete it */ 497 RemoveEntryList(&(WorkItem->UniqueIdWorkerItemListEntry)); 498 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 499 IoFreeIrp(WorkItem->Irp); 500 FreePool(WorkItem->DeviceName.Buffer); 501 FreePool(WorkItem->IrpBuffer); 502 FreePool(WorkItem); 503 } 504 } 505 506 /* 507 * @implemented 508 */ 509 VOID 510 NTAPI 511 UniqueIdChangeNotifyWorker(IN PDEVICE_OBJECT DeviceObject, 512 IN PVOID Context) 513 { 514 PUNIQUE_ID_WORK_ITEM WorkItem = Context; 515 PMOUNTDEV_UNIQUE_ID OldUniqueId, NewUniqueId; 516 PMOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT UniqueIdChange; 517 518 UNREFERENCED_PARAMETER(DeviceObject); 519 520 /* Validate worker */ 521 if (!NT_SUCCESS(WorkItem->Irp->IoStatus.Status)) 522 { 523 RemoveWorkItem(WorkItem); 524 return; 525 } 526 527 UniqueIdChange = WorkItem->Irp->AssociatedIrp.SystemBuffer; 528 /* Get the old unique ID */ 529 OldUniqueId = AllocatePool(UniqueIdChange->OldUniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 530 if (!OldUniqueId) 531 { 532 RemoveWorkItem(WorkItem); 533 return; 534 } 535 536 OldUniqueId->UniqueIdLength = UniqueIdChange->OldUniqueIdLength; 537 RtlCopyMemory(OldUniqueId->UniqueId, 538 (PVOID)((ULONG_PTR)UniqueIdChange + UniqueIdChange->OldUniqueIdOffset), 539 UniqueIdChange->OldUniqueIdLength); 540 541 /* Get the new unique ID */ 542 NewUniqueId = AllocatePool(UniqueIdChange->NewUniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID)); 543 if (!NewUniqueId) 544 { 545 FreePool(OldUniqueId); 546 RemoveWorkItem(WorkItem); 547 return; 548 } 549 550 NewUniqueId->UniqueIdLength = UniqueIdChange->NewUniqueIdLength; 551 RtlCopyMemory(NewUniqueId->UniqueId, 552 (PVOID)((ULONG_PTR)UniqueIdChange + UniqueIdChange->NewUniqueIdOffset), 553 UniqueIdChange->NewUniqueIdLength); 554 555 /* Call the real worker */ 556 MountMgrUniqueIdChangeRoutine(WorkItem->DeviceExtension, OldUniqueId, NewUniqueId); 557 IssueUniqueIdChangeNotifyWorker(WorkItem, NewUniqueId); 558 559 FreePool(NewUniqueId); 560 FreePool(OldUniqueId); 561 562 return; 563 } 564 565 /* 566 * @implemented 567 */ 568 NTSTATUS 569 NTAPI 570 UniqueIdChangeNotifyCompletion(IN PDEVICE_OBJECT DeviceObject, 571 IN PIRP Irp, 572 IN PVOID Context) 573 { 574 PUNIQUE_ID_WORK_ITEM WorkItem = Context; 575 576 UNREFERENCED_PARAMETER(DeviceObject); 577 UNREFERENCED_PARAMETER(Irp); 578 579 /* Simply queue the work item */ 580 IoQueueWorkItem(WorkItem->WorkItem, 581 UniqueIdChangeNotifyWorker, 582 DelayedWorkQueue, 583 WorkItem); 584 585 return STATUS_MORE_PROCESSING_REQUIRED; 586 } 587 588 /* 589 * @implemented 590 */ 591 VOID 592 IssueUniqueIdChangeNotifyWorker(IN PUNIQUE_ID_WORK_ITEM WorkItem, 593 IN PMOUNTDEV_UNIQUE_ID UniqueId) 594 { 595 PIRP Irp; 596 NTSTATUS Status; 597 PFILE_OBJECT FileObject; 598 PIO_STACK_LOCATION Stack; 599 PDEVICE_OBJECT DeviceObject; 600 601 /* Get the device object */ 602 Status = IoGetDeviceObjectPointer(&(WorkItem->DeviceName), 603 FILE_READ_ATTRIBUTES, 604 &FileObject, 605 &DeviceObject); 606 if (!NT_SUCCESS(Status)) 607 { 608 RemoveWorkItem(WorkItem); 609 return; 610 } 611 612 /* And then, the attached device */ 613 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 614 615 /* Initialize the IRP */ 616 Irp = WorkItem->Irp; 617 IoInitializeIrp(Irp, IoSizeOfIrp(WorkItem->StackSize), (CCHAR)WorkItem->StackSize); 618 619 if (InterlockedExchange((PLONG)&(WorkItem->Event), 0) != 0) 620 { 621 ObDereferenceObject(FileObject); 622 ObDereferenceObject(DeviceObject); 623 RemoveWorkItem(WorkItem); 624 return; 625 } 626 627 Irp->AssociatedIrp.SystemBuffer = WorkItem->IrpBuffer; 628 Irp->Tail.Overlay.Thread = PsGetCurrentThread(); 629 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, UniqueId, UniqueId->UniqueIdLength + sizeof(USHORT)); 630 631 Stack = IoGetNextIrpStackLocation(Irp); 632 633 Stack->Parameters.DeviceIoControl.InputBufferLength = UniqueId->UniqueIdLength + sizeof(USHORT); 634 Stack->Parameters.DeviceIoControl.OutputBufferLength = WorkItem->IrpBufferLength; 635 Stack->Parameters.DeviceIoControl.Type3InputBuffer = 0; 636 Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY; 637 Stack->MajorFunction = IRP_MJ_DEVICE_CONTROL; 638 639 Status = IoSetCompletionRoutineEx(WorkItem->DeviceExtension->DeviceObject, 640 Irp, 641 UniqueIdChangeNotifyCompletion, 642 WorkItem, 643 TRUE, TRUE, TRUE); 644 if (!NT_SUCCESS(Status)) 645 { 646 ObDereferenceObject(FileObject); 647 ObDereferenceObject(DeviceObject); 648 RemoveWorkItem(WorkItem); 649 return; 650 } 651 652 /* Call the driver */ 653 IoCallDriver(DeviceObject, Irp); 654 ObDereferenceObject(FileObject); 655 ObDereferenceObject(DeviceObject); 656 } 657 658 /* 659 * @implemented 660 */ 661 VOID 662 IssueUniqueIdChangeNotify(IN PDEVICE_EXTENSION DeviceExtension, 663 IN PUNICODE_STRING DeviceName, 664 IN PMOUNTDEV_UNIQUE_ID UniqueId) 665 { 666 NTSTATUS Status; 667 PVOID IrpBuffer = NULL; 668 PFILE_OBJECT FileObject; 669 PDEVICE_OBJECT DeviceObject; 670 PUNIQUE_ID_WORK_ITEM WorkItem = NULL; 671 672 /* Get the associated device object */ 673 Status = IoGetDeviceObjectPointer(DeviceName, 674 FILE_READ_ATTRIBUTES, 675 &FileObject, 676 &DeviceObject); 677 if (!NT_SUCCESS(Status)) 678 { 679 return; 680 } 681 682 /* And then, get attached device */ 683 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); 684 685 ObDereferenceObject(FileObject); 686 687 /* Allocate a work item */ 688 WorkItem = AllocatePool(sizeof(UNIQUE_ID_WORK_ITEM)); 689 if (!WorkItem) 690 { 691 ObDereferenceObject(DeviceObject); 692 return; 693 } 694 695 WorkItem->Event = NULL; 696 WorkItem->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject); 697 if (!WorkItem->WorkItem) 698 { 699 ObDereferenceObject(DeviceObject); 700 goto Cleanup; 701 } 702 703 WorkItem->DeviceExtension = DeviceExtension; 704 WorkItem->StackSize = DeviceObject->StackSize; 705 /* Already provide the IRP */ 706 WorkItem->Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 707 708 ObDereferenceObject(DeviceObject); 709 710 if (!WorkItem->Irp) 711 { 712 goto Cleanup; 713 } 714 715 /* Ensure it has enough space */ 716 IrpBuffer = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024); 717 if (!IrpBuffer) 718 { 719 goto Cleanup; 720 } 721 722 WorkItem->DeviceName.Length = DeviceName->Length; 723 WorkItem->DeviceName.MaximumLength = DeviceName->Length + sizeof(WCHAR); 724 WorkItem->DeviceName.Buffer = AllocatePool(WorkItem->DeviceName.MaximumLength); 725 if (!WorkItem->DeviceName.Buffer) 726 { 727 goto Cleanup; 728 } 729 730 RtlCopyMemory(WorkItem->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length); 731 WorkItem->DeviceName.Buffer[DeviceName->Length / sizeof(WCHAR)] = UNICODE_NULL; 732 733 WorkItem->IrpBuffer = IrpBuffer; 734 WorkItem->IrpBufferLength = sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024; 735 736 /* Add the worker in the list */ 737 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL); 738 InsertHeadList(&(DeviceExtension->UniqueIdWorkerItemListHead), &(WorkItem->UniqueIdWorkerItemListEntry)); 739 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE); 740 741 /* And call the worker */ 742 IssueUniqueIdChangeNotifyWorker(WorkItem, UniqueId); 743 744 return; 745 746 Cleanup: 747 if (IrpBuffer) 748 { 749 FreePool(IrpBuffer); 750 } 751 752 if (WorkItem->Irp) 753 { 754 IoFreeIrp(WorkItem->Irp); 755 } 756 757 if (WorkItem->WorkItem) 758 { 759 IoFreeWorkItem(WorkItem->WorkItem); 760 } 761 762 if (WorkItem) 763 { 764 FreePool(WorkItem); 765 } 766 } 767