* Sync up to trunk head (r64959).
[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, List);
123 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
124 NewWorkItem->List.Blink = NULL;
125 NewWorkItem->List.Flink = NULL;
126 ExQueueWorkItem((PWORK_QUEUE_ITEM)NewWorkItem, 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 WorkItem->List.Flink = NULL;
159 WorkItem->DeviceExtension = DeviceExtension;
160 WorkItem->WorkerRoutine = SendOnlineNotificationWorker;
161 WorkItem->Parameter = WorkItem;
162 WorkItem->SymbolicName.Length = SymbolicName->Length;
163 WorkItem->SymbolicName.MaximumLength = SymbolicName->Length + sizeof(WCHAR);
164 WorkItem->SymbolicName.Buffer = AllocatePool(WorkItem->SymbolicName.MaximumLength);
165 if (!WorkItem->SymbolicName.Buffer)
166 {
167 FreePool(WorkItem);
168 return;
169 }
170
171 RtlCopyMemory(WorkItem->SymbolicName.Buffer, SymbolicName->Buffer, SymbolicName->Length);
172 WorkItem->SymbolicName.Buffer[SymbolicName->Length / sizeof(WCHAR)] = UNICODE_NULL;
173
174 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
175 DeviceExtension->OnlineNotificationCount++;
176
177 /* If no worker are active */
178 if (DeviceExtension->OnlineNotificationWorkerActive == 0)
179 {
180 /* Queue that one for execution */
181 DeviceExtension->OnlineNotificationWorkerActive = 1;
182 ExQueueWorkItem((PWORK_QUEUE_ITEM)WorkItem, DelayedWorkQueue);
183 }
184 else
185 {
186 /* Otherwise, just put it in the queue list */
187 InsertTailList(&(DeviceExtension->OnlineNotificationListHead), &(WorkItem->List));
188 }
189
190 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
191
192 return;
193 }
194
195 /*
196 * @implemented
197 */
198 VOID
199 WaitForOnlinesToComplete(IN PDEVICE_EXTENSION DeviceExtension)
200 {
201 KIRQL OldIrql;
202
203 KeInitializeEvent(&(DeviceExtension->OnlineNotificationEvent), NotificationEvent, FALSE);
204
205 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
206
207 /* Just wait all the worker are done */
208 if (DeviceExtension->OnlineNotificationCount != 1)
209 {
210 DeviceExtension->OnlineNotificationCount--;
211 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
212
213 KeWaitForSingleObject(&(DeviceExtension->OnlineNotificationEvent),
214 Executive,
215 KernelMode,
216 FALSE,
217 NULL);
218
219 KeAcquireSpinLock(&(DeviceExtension->WorkerLock), &OldIrql);
220 DeviceExtension->OnlineNotificationCount++;
221 }
222
223 KeReleaseSpinLock(&(DeviceExtension->WorkerLock), OldIrql);
224 }
225
226 /*
227 * @implemented
228 */
229 NTSTATUS
230 NTAPI
231 MountMgrTargetDeviceNotification(IN PVOID NotificationStructure,
232 IN PVOID Context)
233 {
234 PDEVICE_EXTENSION DeviceExtension;
235 PDEVICE_INFORMATION DeviceInformation;
236 PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification;
237
238 DeviceInformation = Context;
239 DeviceExtension = DeviceInformation->DeviceExtension;
240 Notification = NotificationStructure;
241
242 /* If it's to signal that removal is complete, then, execute the function */
243 if (IsEqualGUID(&(Notification->Event), &GUID_TARGET_DEVICE_REMOVE_COMPLETE))
244 {
245 MountMgrMountedDeviceRemoval(DeviceExtension, Notification->SymbolicLinkName);
246 }
247 /* It it's to signal that a volume has been mounted
248 * Verify if a database sync is required and execute it
249 */
250 else if (IsEqualGUID(&(Notification->Event), &GUID_IO_VOLUME_MOUNT))
251 {
252 if (InterlockedCompareExchange(&(DeviceInformation->MountState),
253 FALSE,
254 TRUE) == TRUE)
255 {
256 InterlockedDecrement(&(DeviceInformation->MountState));
257 }
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 InsertTailList(&CopyList, &(Irp->Tail.Overlay.ListEntry));
332 }
333 IoReleaseCancelSpinLock(OldIrql);
334
335 /* Then, notifiy them one by one */
336 while (!IsListEmpty(&CopyList))
337 {
338 NextEntry = RemoveHeadList(&CopyList);
339 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
340
341 *((PULONG)Irp->AssociatedIrp.SystemBuffer) = DeviceExtension->EpicNumber;
342 Irp->IoStatus.Information = sizeof(DeviceExtension->EpicNumber);
343
344 IoCompleteRequest(Irp, IO_NO_INCREMENT);
345 }
346 }
347
348 /*
349 * @implemented
350 */
351 VOID
352 MountMgrNotifyNameChange(IN PDEVICE_EXTENSION DeviceExtension,
353 IN PUNICODE_STRING DeviceName,
354 IN BOOLEAN ValidateVolume)
355 {
356 PIRP Irp;
357 KEVENT Event;
358 NTSTATUS Status;
359 PLIST_ENTRY NextEntry;
360 PFILE_OBJECT FileObject;
361 PIO_STACK_LOCATION Stack;
362 PDEVICE_OBJECT DeviceObject;
363 IO_STATUS_BLOCK IoStatusBlock;
364 PDEVICE_RELATIONS DeviceRelations;
365 PDEVICE_INFORMATION DeviceInformation;
366 TARGET_DEVICE_CUSTOM_NOTIFICATION DeviceNotification;
367
368 /* If we have to validate volume */
369 if (ValidateVolume)
370 {
371 /* Then, ensure we can find the device */
372 NextEntry = DeviceExtension->DeviceListHead.Flink;
373 while (NextEntry != &(DeviceExtension->DeviceListHead))
374 {
375 DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
376 if (RtlCompareUnicodeString(DeviceName, &(DeviceInformation->DeviceName), TRUE) == 0)
377 {
378 break;
379 }
380 }
381
382 if (NextEntry == &(DeviceExtension->DeviceListHead) ||
383 !DeviceInformation->Volume)
384 {
385 return;
386 }
387 }
388
389 /* Then, get device object */
390 Status = IoGetDeviceObjectPointer(DeviceName,
391 FILE_READ_ATTRIBUTES,
392 &FileObject,
393 &DeviceObject);
394 if (!NT_SUCCESS(Status))
395 {
396 return;
397 }
398
399 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
400
401 KeInitializeEvent(&Event, NotificationEvent, FALSE);
402
403 /* Set up empty IRP (yes, yes!) */
404 Irp = IoBuildDeviceIoControlRequest(0,
405 DeviceObject,
406 NULL,
407 0,
408 NULL,
409 0,
410 FALSE,
411 &Event,
412 &IoStatusBlock);
413 if (!Irp)
414 {
415 ObDereferenceObject(DeviceObject);
416 ObDereferenceObject(FileObject);
417 return;
418 }
419
420 Stack = IoGetNextIrpStackLocation(Irp);
421
422 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
423 Irp->IoStatus.Information = 0;
424
425 /* Properly set it, we want to query device relations */
426 Stack->MajorFunction = IRP_MJ_PNP;
427 Stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
428 Stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
429 Stack->FileObject = FileObject;
430
431 /* And call driver */
432 Status = IoCallDriver(DeviceObject, Irp);
433 if (Status == STATUS_PENDING)
434 {
435 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
436 Status = IoStatusBlock.Status;
437 }
438
439 ObDereferenceObject(DeviceObject);
440 ObDereferenceObject(FileObject);
441
442 if (!NT_SUCCESS(Status))
443 {
444 return;
445 }
446
447 /* Validate device return */
448 DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
449 if (DeviceRelations->Count < 1)
450 {
451 ExFreePool(DeviceRelations);
452 return;
453 }
454
455 DeviceObject = DeviceRelations->Objects[0];
456 ExFreePool(DeviceRelations);
457
458 /* Set up real notification */
459 DeviceNotification.Version = 1;
460 DeviceNotification.Size = sizeof(TARGET_DEVICE_CUSTOM_NOTIFICATION);
461 DeviceNotification.Event = GUID_IO_VOLUME_NAME_CHANGE;
462 DeviceNotification.FileObject = NULL;
463 DeviceNotification.NameBufferOffset = -1;
464
465 /* And report */
466 IoReportTargetDeviceChangeAsynchronous(DeviceObject,
467 &DeviceNotification,
468 NULL, NULL);
469
470 ObDereferenceObject(DeviceObject);
471
472 return;
473 }
474
475 /*
476 * @implemented
477 */
478 VOID
479 RemoveWorkItem(IN PUNIQUE_ID_WORK_ITEM WorkItem)
480 {
481 PDEVICE_EXTENSION DeviceExtension = WorkItem->DeviceExtension;
482
483 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
484
485 /* If even if being worked, it's too late */
486 if (WorkItem->Event)
487 {
488 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
489 KeSetEvent(WorkItem->Event, 0, FALSE);
490 }
491 else
492 {
493 /* Otherwise, remove it from the list, and delete it */
494 RemoveEntryList(&(WorkItem->UniqueIdWorkerItemListEntry));
495 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
496 IoFreeIrp(WorkItem->Irp);
497 FreePool(WorkItem->DeviceName.Buffer);
498 FreePool(WorkItem->IrpBuffer);
499 FreePool(WorkItem);
500 }
501 }
502
503 /*
504 * @implemented
505 */
506 VOID
507 NTAPI
508 UniqueIdChangeNotifyWorker(IN PDEVICE_OBJECT DeviceObject,
509 IN PVOID Context)
510 {
511 PUNIQUE_ID_WORK_ITEM WorkItem = Context;
512 PMOUNTDEV_UNIQUE_ID OldUniqueId, NewUniqueId;
513 PMOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT UniqueIdChange;
514
515 UNREFERENCED_PARAMETER(DeviceObject);
516
517 /* Validate worker */
518 if (!NT_SUCCESS(WorkItem->Irp->IoStatus.Status))
519 {
520 RemoveWorkItem(WorkItem);
521 return;
522 }
523
524 UniqueIdChange = WorkItem->Irp->AssociatedIrp.SystemBuffer;
525 /* Get the old unique ID */
526 OldUniqueId = AllocatePool(UniqueIdChange->OldUniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
527 if (!OldUniqueId)
528 {
529 RemoveWorkItem(WorkItem);
530 return;
531 }
532
533 OldUniqueId->UniqueIdLength = UniqueIdChange->OldUniqueIdLength;
534 RtlCopyMemory(OldUniqueId->UniqueId,
535 (PVOID)((ULONG_PTR)UniqueIdChange + UniqueIdChange->OldUniqueIdOffset),
536 UniqueIdChange->OldUniqueIdLength);
537
538 /* Get the new unique ID */
539 NewUniqueId = AllocatePool(UniqueIdChange->NewUniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
540 if (!NewUniqueId)
541 {
542 FreePool(OldUniqueId);
543 RemoveWorkItem(WorkItem);
544 return;
545 }
546
547 NewUniqueId->UniqueIdLength = UniqueIdChange->NewUniqueIdLength;
548 RtlCopyMemory(NewUniqueId->UniqueId,
549 (PVOID)((ULONG_PTR)UniqueIdChange + UniqueIdChange->NewUniqueIdOffset),
550 UniqueIdChange->NewUniqueIdLength);
551
552 /* Call the real worker */
553 MountMgrUniqueIdChangeRoutine(WorkItem->DeviceExtension, OldUniqueId, NewUniqueId);
554 IssueUniqueIdChangeNotifyWorker(WorkItem, NewUniqueId);
555
556 FreePool(NewUniqueId);
557 FreePool(OldUniqueId);
558
559 return;
560 }
561
562 /*
563 * @implemented
564 */
565 NTSTATUS
566 NTAPI
567 UniqueIdChangeNotifyCompletion(IN PDEVICE_OBJECT DeviceObject,
568 IN PIRP Irp,
569 IN PVOID Context)
570 {
571 PUNIQUE_ID_WORK_ITEM WorkItem = Context;
572
573 UNREFERENCED_PARAMETER(DeviceObject);
574 UNREFERENCED_PARAMETER(Irp);
575
576 /* Simply queue the work item */
577 IoQueueWorkItem(WorkItem->WorkItem,
578 UniqueIdChangeNotifyWorker,
579 DelayedWorkQueue,
580 WorkItem);
581
582 return STATUS_MORE_PROCESSING_REQUIRED;
583 }
584
585 /*
586 * @implemented
587 */
588 VOID
589 IssueUniqueIdChangeNotifyWorker(IN PUNIQUE_ID_WORK_ITEM WorkItem,
590 IN PMOUNTDEV_UNIQUE_ID UniqueId)
591 {
592 PIRP Irp;
593 NTSTATUS Status;
594 PFILE_OBJECT FileObject;
595 PIO_STACK_LOCATION Stack;
596 PDEVICE_OBJECT DeviceObject;
597
598 /* Get the device object */
599 Status = IoGetDeviceObjectPointer(&(WorkItem->DeviceName),
600 FILE_READ_ATTRIBUTES,
601 &FileObject,
602 &DeviceObject);
603 if (!NT_SUCCESS(Status))
604 {
605 RemoveWorkItem(WorkItem);
606 return;
607 }
608
609 /* And then, the attached device */
610 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
611
612 /* Initialize the IRP */
613 Irp = WorkItem->Irp;
614 IoInitializeIrp(Irp, IoSizeOfIrp(WorkItem->StackSize), (CCHAR)WorkItem->StackSize);
615
616 if (InterlockedExchange((PLONG)&(WorkItem->Event), 0) != 0)
617 {
618 ObDereferenceObject(FileObject);
619 ObDereferenceObject(DeviceObject);
620 RemoveWorkItem(WorkItem);
621 return;
622 }
623
624 Irp->AssociatedIrp.SystemBuffer = WorkItem->IrpBuffer;
625 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
626 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, UniqueId, UniqueId->UniqueIdLength + sizeof(USHORT));
627
628 Stack = IoGetNextIrpStackLocation(Irp);
629
630 Stack->Parameters.DeviceIoControl.InputBufferLength = UniqueId->UniqueIdLength + sizeof(USHORT);
631 Stack->Parameters.DeviceIoControl.OutputBufferLength = WorkItem->IrpBufferLength;
632 Stack->Parameters.DeviceIoControl.Type3InputBuffer = 0;
633 Stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY;
634 Stack->MajorFunction = IRP_MJ_DEVICE_CONTROL;
635
636 Status = IoSetCompletionRoutineEx(WorkItem->DeviceExtension->DeviceObject,
637 Irp,
638 UniqueIdChangeNotifyCompletion,
639 WorkItem,
640 TRUE, TRUE, TRUE);
641 if (!NT_SUCCESS(Status))
642 {
643 ObDereferenceObject(FileObject);
644 ObDereferenceObject(DeviceObject);
645 RemoveWorkItem(WorkItem);
646 return;
647 }
648
649 /* Call the driver */
650 IoCallDriver(DeviceObject, Irp);
651 ObDereferenceObject(FileObject);
652 ObDereferenceObject(DeviceObject);
653 }
654
655 /*
656 * @implemented
657 */
658 VOID
659 IssueUniqueIdChangeNotify(IN PDEVICE_EXTENSION DeviceExtension,
660 IN PUNICODE_STRING DeviceName,
661 IN PMOUNTDEV_UNIQUE_ID UniqueId)
662 {
663 NTSTATUS Status;
664 PVOID IrpBuffer = NULL;
665 PFILE_OBJECT FileObject;
666 PDEVICE_OBJECT DeviceObject;
667 PUNIQUE_ID_WORK_ITEM WorkItem = NULL;
668
669 /* Get the associated device object */
670 Status = IoGetDeviceObjectPointer(DeviceName,
671 FILE_READ_ATTRIBUTES,
672 &FileObject,
673 &DeviceObject);
674 if (!NT_SUCCESS(Status))
675 {
676 return;
677 }
678
679 /* And then, get attached device */
680 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
681
682 ObDereferenceObject(FileObject);
683
684 /* Allocate a work item */
685 WorkItem = AllocatePool(sizeof(UNIQUE_ID_WORK_ITEM));
686 if (!WorkItem)
687 {
688 ObDereferenceObject(DeviceObject);
689 return;
690 }
691
692 WorkItem->Event = NULL;
693 WorkItem->WorkItem = IoAllocateWorkItem(DeviceExtension->DeviceObject);
694 if (!WorkItem->WorkItem)
695 {
696 ObDereferenceObject(DeviceObject);
697 goto Cleanup;
698 }
699
700 WorkItem->DeviceExtension = DeviceExtension;
701 WorkItem->StackSize = DeviceObject->StackSize;
702 /* Already provide the IRP */
703 WorkItem->Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
704
705 ObDereferenceObject(DeviceObject);
706
707 if (!WorkItem->Irp)
708 {
709 goto Cleanup;
710 }
711
712 /* Ensure it has enough space */
713 IrpBuffer = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024);
714 if (!IrpBuffer)
715 {
716 goto Cleanup;
717 }
718
719 WorkItem->DeviceName.Length = DeviceName->Length;
720 WorkItem->DeviceName.MaximumLength = DeviceName->Length + sizeof(WCHAR);
721 WorkItem->DeviceName.Buffer = AllocatePool(WorkItem->DeviceName.MaximumLength);
722 if (!WorkItem->DeviceName.Buffer)
723 {
724 goto Cleanup;
725 }
726
727 RtlCopyMemory(WorkItem->DeviceName.Buffer, DeviceName->Buffer, DeviceName->Length);
728 WorkItem->DeviceName.Buffer[DeviceName->Length / sizeof(WCHAR)] = UNICODE_NULL;
729
730 WorkItem->IrpBuffer = IrpBuffer;
731 WorkItem->IrpBufferLength = sizeof(MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY_OUTPUT) + 1024;
732
733 /* Add the worker in the list */
734 KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
735 InsertHeadList(&(DeviceExtension->UniqueIdWorkerItemListHead), &(WorkItem->UniqueIdWorkerItemListEntry));
736 KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
737
738 /* And call the worker */
739 IssueUniqueIdChangeNotifyWorker(WorkItem, UniqueId);
740
741 return;
742
743 Cleanup:
744 if (IrpBuffer)
745 {
746 FreePool(IrpBuffer);
747 }
748
749 if (WorkItem->Irp)
750 {
751 IoFreeIrp(WorkItem->Irp);
752 }
753
754 if (WorkItem->WorkItem)
755 {
756 IoFreeWorkItem(WorkItem->WorkItem);
757 }
758
759 if (WorkItem)
760 {
761 FreePool(WorkItem);
762 }
763 }