[MOUNTMGR] Avoid an endless loop while sending GUID_IO_VOLUME_NAME_CHANGE notification
[reactos.git] / drivers / filters / mountmgr / notify.c
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 }