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