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
SendOnlineNotification(IN PUNICODE_STRING SymbolicName)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
SendOnlineNotificationWorker(IN PVOID Parameter)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
PostOnlineNotification(IN PDEVICE_EXTENSION DeviceExtension,IN PUNICODE_STRING SymbolicName)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
WaitForOnlinesToComplete(IN PDEVICE_EXTENSION DeviceExtension)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
MountMgrTargetDeviceNotification(IN PVOID NotificationStructure,IN PVOID Context)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
RegisterForTargetDeviceNotification(IN PDEVICE_EXTENSION DeviceExtension,IN PDEVICE_INFORMATION DeviceInformation)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
MountMgrNotify(IN PDEVICE_EXTENSION DeviceExtension)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
MountMgrNotifyNameChange(IN PDEVICE_EXTENSION DeviceExtension,IN PUNICODE_STRING DeviceName,IN BOOLEAN ValidateVolume)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
RemoveWorkItem(IN PUNIQUE_ID_WORK_ITEM WorkItem)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
UniqueIdChangeNotifyWorker(IN PDEVICE_OBJECT DeviceObject,IN PVOID Context)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
UniqueIdChangeNotifyCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context)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
IssueUniqueIdChangeNotifyWorker(IN PUNIQUE_ID_WORK_ITEM WorkItem,IN PMOUNTDEV_UNIQUE_ID UniqueId)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
IssueUniqueIdChangeNotify(IN PDEVICE_EXTENSION DeviceExtension,IN PUNICODE_STRING DeviceName,IN PMOUNTDEV_UNIQUE_ID UniqueId)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