6f3dd62a2bbcac87eea68b8d3a3f8fbb16420bbf
[reactos.git] / drivers / filesystems / btrfs / search.c
1 /* Copyright (c) Mark Harmstone 2016-17
2 *
3 * This file is part of WinBtrfs.
4 *
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
9 *
10 * WinBtrfs 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 Lesser General Public Licence for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include "btrfs_drv.h"
19
20 #ifndef __REACTOS__
21 #include <ntddk.h>
22 #include <ntifs.h>
23 #include <mountmgr.h>
24 #include <windef.h>
25 #endif
26 #include <ntddstor.h>
27 #include <ntdddisk.h>
28
29 #include <initguid.h>
30 #include <wdmguid.h>
31
32 extern ERESOURCE pdo_list_lock;
33 extern LIST_ENTRY pdo_list;
34 extern UNICODE_STRING registry_path;
35 extern KEVENT mountmgr_thread_event;
36 extern HANDLE mountmgr_thread_handle;
37 extern BOOL shutting_down;
38
39 typedef void (*pnp_callback)(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath);
40
41 extern PDEVICE_OBJECT master_devobj;
42
43 static BOOL fs_ignored(BTRFS_UUID* uuid) {
44 UNICODE_STRING path, ignoreus;
45 NTSTATUS Status;
46 OBJECT_ATTRIBUTES oa;
47 KEY_VALUE_FULL_INFORMATION* kvfi;
48 ULONG dispos, retlen, kvfilen, i, j;
49 HANDLE h;
50 BOOL ret = FALSE;
51
52 path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
53
54 path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
55 if (!path.Buffer) {
56 ERR("out of memory\n");
57 return FALSE;
58 }
59
60 RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
61
62 i = registry_path.Length / sizeof(WCHAR);
63
64 path.Buffer[i] = '\\';
65 i++;
66
67 for (j = 0; j < 16; j++) {
68 path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
69 path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
70
71 i += 2;
72
73 if (j == 3 || j == 5 || j == 7 || j == 9) {
74 path.Buffer[i] = '-';
75 i++;
76 }
77 }
78
79 InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
80
81 Status = ZwCreateKey(&h, KEY_QUERY_VALUE, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos);
82
83 if (!NT_SUCCESS(Status)) {
84 TRACE("ZwCreateKey returned %08x\n", Status);
85 ExFreePool(path.Buffer);
86 return FALSE;
87 }
88
89 RtlInitUnicodeString(&ignoreus, L"Ignore");
90
91 kvfilen = (ULONG)offsetof(KEY_VALUE_FULL_INFORMATION, Name[0]) + (255 * sizeof(WCHAR));
92 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
93 if (!kvfi) {
94 ERR("out of memory\n");
95 ZwClose(h);
96 ExFreePool(path.Buffer);
97 return FALSE;
98 }
99
100 Status = ZwQueryValueKey(h, &ignoreus, KeyValueFullInformation, kvfi, kvfilen, &retlen);
101 if (NT_SUCCESS(Status)) {
102 if (kvfi->Type == REG_DWORD && kvfi->DataLength >= sizeof(UINT32)) {
103 UINT32* pr = (UINT32*)((UINT8*)kvfi + kvfi->DataOffset);
104
105 ret = *pr;
106 }
107 }
108
109 ZwClose(h);
110 ExFreePool(kvfi);
111 ExFreePool(path.Buffer);
112
113 return ret;
114 }
115
116 static void test_vol(PDEVICE_OBJECT mountmgr, PDEVICE_OBJECT DeviceObject, PUNICODE_STRING devpath,
117 DWORD disk_num, DWORD part_num, UINT64 length) {
118 NTSTATUS Status;
119 ULONG toread;
120 UINT8* data = NULL;
121 UINT32 sector_size;
122
123 TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
124
125 sector_size = DeviceObject->SectorSize;
126
127 if (sector_size == 0) {
128 DISK_GEOMETRY geometry;
129 IO_STATUS_BLOCK iosb;
130
131 Status = dev_ioctl(DeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
132 &geometry, sizeof(DISK_GEOMETRY), TRUE, &iosb);
133
134 if (!NT_SUCCESS(Status)) {
135 ERR("%.*S had a sector size of 0, and IOCTL_DISK_GET_DRIVE_GEOMETRY returned %08x\n",
136 devpath->Length / sizeof(WCHAR), devpath->Buffer, Status);
137 goto deref;
138 }
139
140 if (iosb.Information < sizeof(DISK_GEOMETRY)) {
141 ERR("%.*S: IOCTL_DISK_GET_DRIVE_GEOMETRY returned %u bytes, expected %u\n",
142 devpath->Length / sizeof(WCHAR), devpath->Buffer, iosb.Information, sizeof(DISK_GEOMETRY));
143 }
144
145 sector_size = geometry.BytesPerSector;
146
147 if (sector_size == 0) {
148 ERR("%.*S had a sector size of 0\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
149 goto deref;
150 }
151 }
152
153 toread = (ULONG)sector_align(sizeof(superblock), sector_size);
154 data = ExAllocatePoolWithTag(NonPagedPool, toread, ALLOC_TAG);
155 if (!data) {
156 ERR("out of memory\n");
157 goto deref;
158 }
159
160 Status = sync_read_phys(DeviceObject, superblock_addrs[0], toread, data, TRUE);
161
162 if (NT_SUCCESS(Status) && ((superblock*)data)->magic == BTRFS_MAGIC) {
163 superblock* sb = (superblock*)data;
164 UINT32 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
165
166 if (crc32 != *((UINT32*)sb->checksum))
167 ERR("checksum error on superblock\n");
168 else {
169 TRACE("volume found\n");
170
171 if (length >= superblock_addrs[1] + toread) {
172 ULONG i = 1;
173
174 superblock* sb2 = ExAllocatePoolWithTag(NonPagedPool, toread, ALLOC_TAG);
175 if (!sb2) {
176 ERR("out of memory\n");
177 goto deref;
178 }
179
180 while (superblock_addrs[i] > 0 && length >= superblock_addrs[i] + toread) {
181 Status = sync_read_phys(DeviceObject, superblock_addrs[i], toread, (PUCHAR)sb2, TRUE);
182
183 if (NT_SUCCESS(Status) && sb2->magic == BTRFS_MAGIC) {
184 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb2->uuid, (ULONG)sizeof(superblock) - sizeof(sb2->checksum));
185
186 if (crc32 == *((UINT32*)sb2->checksum) && sb2->generation > sb->generation)
187 RtlCopyMemory(sb, sb2, toread);
188 }
189
190 i++;
191 }
192
193 ExFreePool(sb2);
194 }
195
196 if (!fs_ignored(&sb->uuid)) {
197 DeviceObject->Flags &= ~DO_VERIFY_VOLUME;
198 add_volume_device(sb, mountmgr, devpath, length, disk_num, part_num);
199 }
200 }
201 }
202
203 deref:
204 if (data)
205 ExFreePool(data);
206 }
207
208 NTSTATUS remove_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath) {
209 NTSTATUS Status;
210 MOUNTMGR_MOUNT_POINT* mmp;
211 ULONG mmpsize;
212 MOUNTMGR_MOUNT_POINTS mmps1, *mmps2;
213
214 TRACE("removing drive letter\n");
215
216 mmpsize = sizeof(MOUNTMGR_MOUNT_POINT) + devpath->Length;
217
218 mmp = ExAllocatePoolWithTag(PagedPool, mmpsize, ALLOC_TAG);
219 if (!mmp) {
220 ERR("out of memory\n");
221 return STATUS_INSUFFICIENT_RESOURCES;
222 }
223
224 RtlZeroMemory(mmp, mmpsize);
225
226 mmp->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
227 mmp->DeviceNameLength = devpath->Length;
228 RtlCopyMemory(&mmp[1], devpath->Buffer, devpath->Length);
229
230 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_DELETE_POINTS, mmp, mmpsize, &mmps1, sizeof(MOUNTMGR_MOUNT_POINTS), FALSE, NULL);
231
232 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
233 ERR("IOCTL_MOUNTMGR_DELETE_POINTS 1 returned %08x\n", Status);
234 ExFreePool(mmp);
235 return Status;
236 }
237
238 if (Status != STATUS_BUFFER_OVERFLOW || mmps1.Size == 0) {
239 ExFreePool(mmp);
240 return STATUS_NOT_FOUND;
241 }
242
243 mmps2 = ExAllocatePoolWithTag(PagedPool, mmps1.Size, ALLOC_TAG);
244 if (!mmps2) {
245 ERR("out of memory\n");
246 ExFreePool(mmp);
247 return STATUS_INSUFFICIENT_RESOURCES;
248 }
249
250 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_DELETE_POINTS, mmp, mmpsize, mmps2, mmps1.Size, FALSE, NULL);
251
252 if (!NT_SUCCESS(Status))
253 ERR("IOCTL_MOUNTMGR_DELETE_POINTS 2 returned %08x\n", Status);
254
255 ExFreePool(mmps2);
256 ExFreePool(mmp);
257
258 return Status;
259 }
260
261 void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
262 PFILE_OBJECT FileObject, mountmgrfo;
263 PDEVICE_OBJECT devobj, mountmgr;
264 NTSTATUS Status;
265 STORAGE_DEVICE_NUMBER sdn;
266 ULONG dlisize;
267 DRIVE_LAYOUT_INFORMATION_EX* dli = NULL;
268 IO_STATUS_BLOCK iosb;
269 GET_LENGTH_INFORMATION gli;
270 UNICODE_STRING mmdevpath;
271
272 UNUSED(DriverObject);
273
274 Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &devobj);
275 if (!NT_SUCCESS(Status)) {
276 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
277 return;
278 }
279
280 RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
281 Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr);
282 if (!NT_SUCCESS(Status)) {
283 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
284 ObDereferenceObject(FileObject);
285 return;
286 }
287
288 dlisize = 0;
289
290 do {
291 dlisize += 1024;
292
293 if (dli)
294 ExFreePool(dli);
295
296 dli = ExAllocatePoolWithTag(PagedPool, dlisize, ALLOC_TAG);
297 if (!dli) {
298 ERR("out of memory\n");
299 goto end;
300 }
301
302 Status = dev_ioctl(devobj, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0,
303 dli, dlisize, TRUE, &iosb);
304 } while (Status == STATUS_BUFFER_TOO_SMALL);
305
306 // only consider disk as a potential filesystem if it has no partitions
307 if (NT_SUCCESS(Status) && dli->PartitionCount > 0) {
308 ExFreePool(dli);
309 goto end;
310 }
311
312 ExFreePool(dli);
313
314 Status = dev_ioctl(devobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
315 &gli, sizeof(gli), TRUE, NULL);
316
317 if (!NT_SUCCESS(Status)) {
318 ERR("error reading length information: %08x\n", Status);
319 goto end;
320 }
321
322 Status = dev_ioctl(devobj, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
323 &sdn, sizeof(STORAGE_DEVICE_NUMBER), TRUE, NULL);
324 if (!NT_SUCCESS(Status)) {
325 TRACE("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status);
326 sdn.DeviceNumber = 0xffffffff;
327 sdn.PartitionNumber = 0;
328 } else
329 TRACE("DeviceType = %u, DeviceNumber = %u, PartitionNumber = %u\n", sdn.DeviceType, sdn.DeviceNumber, sdn.PartitionNumber);
330
331 test_vol(mountmgr, devobj, devpath, sdn.DeviceNumber, sdn.PartitionNumber, gli.Length.QuadPart);
332
333 end:
334 ObDereferenceObject(FileObject);
335 ObDereferenceObject(mountmgrfo);
336 }
337
338 void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lock) _Releases_exclusive_lock_(_Curr_->child_lock) _In_ volume_device_extension* vde,
339 _In_ volume_child* vc, _In_ BOOL skip_dev) {
340 NTSTATUS Status;
341 pdo_device_extension* pdode = vde->pdode;
342 device_extension* Vcb = vde->mounted_device ? vde->mounted_device->DeviceExtension : NULL;
343
344 if (vc->notification_entry)
345 #ifdef __REACTOS__
346 IoUnregisterPlugPlayNotification(vc->notification_entry);
347 #else
348 IoUnregisterPlugPlayNotificationEx(vc->notification_entry);
349 #endif
350
351 if (vde->mounted_device && (!Vcb || !Vcb->options.allow_degraded)) {
352 Status = pnp_surprise_removal(vde->mounted_device, NULL);
353 if (!NT_SUCCESS(Status))
354 ERR("pnp_surprise_removal returned %08x\n", Status);
355 }
356
357 if (!Vcb || !Vcb->options.allow_degraded) {
358 Status = IoSetDeviceInterfaceState(&vde->bus_name, FALSE);
359 if (!NT_SUCCESS(Status))
360 WARN("IoSetDeviceInterfaceState returned %08x\n", Status);
361 }
362
363 if (pdode->children_loaded > 0) {
364 UNICODE_STRING mmdevpath;
365 PFILE_OBJECT FileObject;
366 PDEVICE_OBJECT mountmgr;
367 LIST_ENTRY* le;
368
369 if (!Vcb || !Vcb->options.allow_degraded) {
370 RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
371 Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr);
372 if (!NT_SUCCESS(Status))
373 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
374 else {
375 le = pdode->children.Flink;
376
377 while (le != &pdode->children) {
378 volume_child* vc2 = CONTAINING_RECORD(le, volume_child, list_entry);
379
380 if (vc2->had_drive_letter) { // re-add entry to mountmgr
381 MOUNTDEV_NAME mdn;
382
383 Status = dev_ioctl(vc2->devobj, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &mdn, sizeof(MOUNTDEV_NAME), TRUE, NULL);
384 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
385 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
386 else {
387 MOUNTDEV_NAME* mdn2;
388 ULONG mdnsize = (ULONG)offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength;
389
390 mdn2 = ExAllocatePoolWithTag(PagedPool, mdnsize, ALLOC_TAG);
391 if (!mdn2)
392 ERR("out of memory\n");
393 else {
394 Status = dev_ioctl(vc2->devobj, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, mdn2, mdnsize, TRUE, NULL);
395 if (!NT_SUCCESS(Status))
396 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
397 else {
398 UNICODE_STRING name;
399
400 name.Buffer = mdn2->Name;
401 name.Length = name.MaximumLength = mdn2->NameLength;
402
403 Status = mountmgr_add_drive_letter(mountmgr, &name);
404 if (!NT_SUCCESS(Status))
405 WARN("mountmgr_add_drive_letter returned %08x\n", Status);
406 }
407
408 ExFreePool(mdn2);
409 }
410 }
411 }
412
413 le = le->Flink;
414 }
415
416 ObDereferenceObject(FileObject);
417 }
418 } else if (!skip_dev) {
419 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
420
421 le = Vcb->devices.Flink;
422 while (le != &Vcb->devices) {
423 device* dev = CONTAINING_RECORD(le, device, list_entry);
424
425 if (dev->devobj == vc->devobj) {
426 dev->devobj = NULL; // mark as missing
427 break;
428 }
429
430 le = le->Flink;
431 }
432
433 ExReleaseResourceLite(&Vcb->tree_lock);
434 }
435
436 if (vde->device->Characteristics & FILE_REMOVABLE_MEDIA) {
437 vde->device->Characteristics &= ~FILE_REMOVABLE_MEDIA;
438
439 le = pdode->children.Flink;
440 while (le != &pdode->children) {
441 volume_child* vc2 = CONTAINING_RECORD(le, volume_child, list_entry);
442
443 if (vc2 != vc && vc2->devobj->Characteristics & FILE_REMOVABLE_MEDIA) {
444 vde->device->Characteristics |= FILE_REMOVABLE_MEDIA;
445 break;
446 }
447
448 le = le->Flink;
449 }
450 }
451 }
452
453 ObDereferenceObject(vc->fileobj);
454 ExFreePool(vc->pnp_name.Buffer);
455 RemoveEntryList(&vc->list_entry);
456 ExFreePool(vc);
457
458 pdode->children_loaded--;
459
460 if (pdode->children_loaded == 0) { // remove volume device
461 BOOL remove = FALSE;
462
463 RemoveEntryList(&pdode->list_entry);
464
465 vde->removing = TRUE;
466
467 Status = IoSetDeviceInterfaceState(&vde->bus_name, FALSE);
468 if (!NT_SUCCESS(Status))
469 WARN("IoSetDeviceInterfaceState returned %08x\n", Status);
470
471 if (vde->pdo->AttachedDevice)
472 IoDetachDevice(vde->pdo);
473
474 if (vde->open_count == 0)
475 remove = TRUE;
476
477 ExReleaseResourceLite(&pdode->child_lock);
478
479 if (!no_pnp) {
480 control_device_extension* cde = master_devobj->DeviceExtension;
481
482 IoInvalidateDeviceRelations(cde->buspdo, BusRelations);
483 }
484
485 if (remove) {
486 PDEVICE_OBJECT pdo;
487
488 if (vde->name.Buffer)
489 ExFreePool(vde->name.Buffer);
490
491 if (Vcb)
492 Vcb->vde = NULL;
493
494 ExDeleteResourceLite(&pdode->child_lock);
495
496 pdo = vde->pdo;
497 IoDeleteDevice(vde->device);
498
499 if (no_pnp)
500 IoDeleteDevice(pdo);
501 }
502 } else
503 ExReleaseResourceLite(&pdode->child_lock);
504 }
505
506 void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
507 STORAGE_DEVICE_NUMBER sdn;
508 PFILE_OBJECT FileObject, mountmgrfo;
509 UNICODE_STRING mmdevpath;
510 PDEVICE_OBJECT devobj, mountmgr;
511 GET_LENGTH_INFORMATION gli;
512 NTSTATUS Status;
513
514 TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
515
516 Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &devobj);
517 if (!NT_SUCCESS(Status)) {
518 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
519 return;
520 }
521
522 // make sure we're not processing devices we've created ourselves
523
524 if (devobj->DriverObject == DriverObject)
525 goto end;
526
527 Status = dev_ioctl(devobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), TRUE, NULL);
528 if (!NT_SUCCESS(Status)) {
529 ERR("IOCTL_DISK_GET_LENGTH_INFO returned %08x\n", Status);
530 goto end;
531 }
532
533 Status = dev_ioctl(devobj, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
534 &sdn, sizeof(STORAGE_DEVICE_NUMBER), TRUE, NULL);
535 if (!NT_SUCCESS(Status)) {
536 TRACE("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status);
537 sdn.DeviceNumber = 0xffffffff;
538 sdn.PartitionNumber = 0;
539 } else
540 TRACE("DeviceType = %u, DeviceNumber = %u, PartitionNumber = %u\n", sdn.DeviceType, sdn.DeviceNumber, sdn.PartitionNumber);
541
542 // If we've just added a partition to a whole-disk filesystem, unmount it
543 if (sdn.DeviceNumber != 0xffffffff) {
544 LIST_ENTRY* le;
545
546 ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE);
547
548 le = pdo_list.Flink;
549 while (le != &pdo_list) {
550 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry);
551 LIST_ENTRY* le2;
552 BOOL changed = FALSE;
553
554 if (pdode->vde) {
555 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE);
556
557 le2 = pdode->children.Flink;
558 while (le2 != &pdode->children) {
559 volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry);
560 LIST_ENTRY* le3 = le2->Flink;
561
562 if (vc->disk_num == sdn.DeviceNumber && vc->part_num == 0) {
563 TRACE("removing device\n");
564
565 remove_volume_child(pdode->vde, vc, FALSE);
566 changed = TRUE;
567
568 break;
569 }
570
571 le2 = le3;
572 }
573
574 if (!changed)
575 ExReleaseResourceLite(&pdode->child_lock);
576 else
577 break;
578 }
579
580 le = le->Flink;
581 }
582
583 ExReleaseResourceLite(&pdo_list_lock);
584 }
585
586 RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
587 Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr);
588 if (!NT_SUCCESS(Status)) {
589 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
590 goto end;
591 }
592
593 test_vol(mountmgr, devobj, devpath, sdn.DeviceNumber, sdn.PartitionNumber, gli.Length.QuadPart);
594
595 ObDereferenceObject(mountmgrfo);
596
597 end:
598 ObDereferenceObject(FileObject);
599 }
600
601 void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
602 LIST_ENTRY* le;
603 UNICODE_STRING devpath2;
604
605 TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
606
607 UNUSED(DriverObject);
608
609 devpath2 = *devpath;
610
611 if (devpath->Length > 4 * sizeof(WCHAR) && devpath->Buffer[0] == '\\' && (devpath->Buffer[1] == '\\' || devpath->Buffer[1] == '?') &&
612 devpath->Buffer[2] == '?' && devpath->Buffer[3] == '\\') {
613 devpath2.Buffer = &devpath2.Buffer[3];
614 devpath2.Length -= 3 * sizeof(WCHAR);
615 devpath2.MaximumLength -= 3 * sizeof(WCHAR);
616 }
617
618 ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE);
619
620 le = pdo_list.Flink;
621 while (le != &pdo_list) {
622 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry);
623 LIST_ENTRY* le2;
624 BOOL changed = FALSE;
625
626 if (pdode->vde) {
627 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE);
628
629 le2 = pdode->children.Flink;
630 while (le2 != &pdode->children) {
631 volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry);
632 LIST_ENTRY* le3 = le2->Flink;
633
634 if (vc->pnp_name.Length == devpath2.Length && RtlCompareMemory(vc->pnp_name.Buffer, devpath2.Buffer, devpath2.Length) == devpath2.Length) {
635 TRACE("removing device\n");
636
637 remove_volume_child(pdode->vde, vc, FALSE);
638 changed = TRUE;
639
640 break;
641 }
642
643 le2 = le3;
644 }
645
646 if (!changed)
647 ExReleaseResourceLite(&pdode->child_lock);
648 else
649 break;
650 }
651
652 le = le->Flink;
653 }
654
655 ExReleaseResourceLite(&pdo_list_lock);
656 }
657
658 typedef struct {
659 PDRIVER_OBJECT DriverObject;
660 UNICODE_STRING name;
661 pnp_callback func;
662 PIO_WORKITEM work_item;
663 } pnp_callback_context;
664
665 _Function_class_(IO_WORKITEM_ROUTINE)
666 #ifdef __REACTOS__
667 static void NTAPI do_pnp_callback(PDEVICE_OBJECT DeviceObject, PVOID con) {
668 #else
669 static void do_pnp_callback(PDEVICE_OBJECT DeviceObject, PVOID con) {
670 #endif
671 pnp_callback_context* context = con;
672
673 UNUSED(DeviceObject);
674
675 context->func(context->DriverObject, &context->name);
676
677 if (context->name.Buffer)
678 ExFreePool(context->name.Buffer);
679
680 IoFreeWorkItem(context->work_item);
681 }
682
683 static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING name, pnp_callback func) {
684 PIO_WORKITEM work_item;
685 pnp_callback_context* context;
686
687 work_item = IoAllocateWorkItem(master_devobj);
688
689 context = ExAllocatePoolWithTag(PagedPool, sizeof(pnp_callback_context), ALLOC_TAG);
690
691 if (!context) {
692 ERR("out of memory\n");
693 IoFreeWorkItem(work_item);
694 return;
695 }
696
697 context->DriverObject = DriverObject;
698
699 if (name->Length > 0) {
700 context->name.Buffer = ExAllocatePoolWithTag(PagedPool, name->Length, ALLOC_TAG);
701 if (!context->name.Buffer) {
702 ERR("out of memory\n");
703 ExFreePool(context);
704 IoFreeWorkItem(work_item);
705 return;
706 }
707
708 RtlCopyMemory(context->name.Buffer, name->Buffer, name->Length);
709 context->name.Length = context->name.MaximumLength = name->Length;
710 } else {
711 context->name.Length = context->name.MaximumLength = 0;
712 context->name.Buffer = NULL;
713 }
714
715 context->func = func;
716 context->work_item = work_item;
717
718 IoQueueWorkItem(work_item, do_pnp_callback, DelayedWorkQueue, context);
719 }
720
721 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE)
722 #ifdef __REACTOS__
723 NTSTATUS NTAPI volume_notification(PVOID NotificationStructure, PVOID Context) {
724 #else
725 NTSTATUS volume_notification(PVOID NotificationStructure, PVOID Context) {
726 #endif
727 DEVICE_INTERFACE_CHANGE_NOTIFICATION* dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure;
728 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context;
729
730 if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID))
731 enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, volume_arrival);
732 else if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID))
733 enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, volume_removal);
734
735 return STATUS_SUCCESS;
736 }
737
738 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE)
739 #ifdef __REACTOS__
740 NTSTATUS NTAPI pnp_notification(PVOID NotificationStructure, PVOID Context) {
741 #else
742 NTSTATUS pnp_notification(PVOID NotificationStructure, PVOID Context) {
743 #endif
744 DEVICE_INTERFACE_CHANGE_NOTIFICATION* dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure;
745 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context;
746
747 if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID))
748 enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, disk_arrival);
749 else if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID))
750 enqueue_pnp_callback(DriverObject, dicn->SymbolicLinkName, volume_removal);
751
752 return STATUS_SUCCESS;
753 }
754
755 static void mountmgr_process_drive(PDEVICE_OBJECT mountmgr, PUNICODE_STRING device_name) {
756 NTSTATUS Status;
757 LIST_ENTRY* le;
758 BOOL done = FALSE;
759
760 ExAcquireResourceSharedLite(&pdo_list_lock, TRUE);
761
762 le = pdo_list.Flink;
763 while (le != &pdo_list) {
764 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry);
765 LIST_ENTRY* le2;
766
767 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
768
769 le2 = pdode->children.Flink;
770
771 while (le2 != &pdode->children) {
772 volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry);
773
774 if (vc->devobj) {
775 MOUNTDEV_NAME mdn;
776
777 Status = dev_ioctl(vc->devobj, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &mdn, sizeof(MOUNTDEV_NAME), TRUE, NULL);
778 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
779 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
780 else {
781 MOUNTDEV_NAME* mdn2;
782 ULONG mdnsize = (ULONG)offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength;
783
784 mdn2 = ExAllocatePoolWithTag(NonPagedPool, mdnsize, ALLOC_TAG);
785 if (!mdn2)
786 ERR("out of memory\n");
787 else {
788 Status = dev_ioctl(vc->devobj, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, mdn2, mdnsize, TRUE, NULL);
789 if (!NT_SUCCESS(Status))
790 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status);
791 else {
792 if (mdn2->NameLength == device_name->Length && RtlCompareMemory(mdn2->Name, device_name->Buffer, device_name->Length) == device_name->Length) {
793 Status = remove_drive_letter(mountmgr, device_name);
794 if (!NT_SUCCESS(Status))
795 ERR("remove_drive_letter returned %08x\n", Status);
796 else
797 vc->had_drive_letter = TRUE;
798
799 done = TRUE;
800 break;
801 }
802 }
803
804 ExFreePool(mdn2);
805 }
806 }
807 }
808
809 le2 = le2->Flink;
810 }
811
812 ExReleaseResourceLite(&pdode->child_lock);
813
814 if (done)
815 break;
816
817 le = le->Flink;
818 }
819
820 ExReleaseResourceLite(&pdo_list_lock);
821 }
822
823 static void mountmgr_updated(PDEVICE_OBJECT mountmgr, MOUNTMGR_MOUNT_POINTS* mmps) {
824 ULONG i;
825
826 static WCHAR pref[] = L"\\DosDevices\\";
827
828 for (i = 0; i < mmps->NumberOfMountPoints; i++) {
829 UNICODE_STRING symlink, device_name;
830
831 if (mmps->MountPoints[i].SymbolicLinkNameOffset != 0) {
832 symlink.Buffer = (WCHAR*)(((UINT8*)mmps) + mmps->MountPoints[i].SymbolicLinkNameOffset);
833 symlink.Length = symlink.MaximumLength = mmps->MountPoints[i].SymbolicLinkNameLength;
834 } else {
835 symlink.Buffer = NULL;
836 symlink.Length = symlink.MaximumLength = 0;
837 }
838
839 if (mmps->MountPoints[i].DeviceNameOffset != 0) {
840 device_name.Buffer = (WCHAR*)(((UINT8*)mmps) + mmps->MountPoints[i].DeviceNameOffset);
841 device_name.Length = device_name.MaximumLength = mmps->MountPoints[i].DeviceNameLength;
842 } else {
843 device_name.Buffer = NULL;
844 device_name.Length = device_name.MaximumLength = 0;
845 }
846
847 if (symlink.Length > wcslen(pref) * sizeof(WCHAR) &&
848 RtlCompareMemory(symlink.Buffer, pref, wcslen(pref) * sizeof(WCHAR)) == wcslen(pref) * sizeof(WCHAR))
849 mountmgr_process_drive(mountmgr, &device_name);
850 }
851 }
852
853 _Function_class_(KSTART_ROUTINE)
854 #ifdef __REACTOS__
855 void NTAPI mountmgr_thread(_In_ void* context) {
856 #else
857 void mountmgr_thread(_In_ void* context) {
858 #endif
859 UNICODE_STRING mmdevpath;
860 NTSTATUS Status;
861 PFILE_OBJECT FileObject;
862 PDEVICE_OBJECT mountmgr;
863 MOUNTMGR_CHANGE_NOTIFY_INFO mcni;
864
865 UNUSED(context);
866
867 RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
868 Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr);
869 if (!NT_SUCCESS(Status)) {
870 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
871 return;
872 }
873
874 mcni.EpicNumber = 0;
875
876 while (TRUE) {
877 PIRP Irp;
878 MOUNTMGR_MOUNT_POINT mmp;
879 MOUNTMGR_MOUNT_POINTS mmps;
880 IO_STATUS_BLOCK iosb;
881
882 KeClearEvent(&mountmgr_thread_event);
883
884 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_CHANGE_NOTIFY, mountmgr, &mcni, sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO),
885 &mcni, sizeof(MOUNTMGR_CHANGE_NOTIFY_INFO), FALSE, &mountmgr_thread_event, &iosb);
886
887 if (!Irp) {
888 ERR("out of memory\n");
889 break;
890 }
891
892 Status = IoCallDriver(mountmgr, Irp);
893
894 if (Status == STATUS_PENDING) {
895 KeWaitForSingleObject(&mountmgr_thread_event, Executive, KernelMode, FALSE, NULL);
896 Status = iosb.Status;
897 }
898
899 if (shutting_down)
900 break;
901
902 if (!NT_SUCCESS(Status)) {
903 ERR("IOCTL_MOUNTMGR_CHANGE_NOTIFY returned %08x\n", Status);
904 break;
905 }
906
907 TRACE("mountmgr changed\n");
908
909 RtlZeroMemory(&mmp, sizeof(MOUNTMGR_MOUNT_POINT));
910
911 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp, sizeof(MOUNTMGR_MOUNT_POINT), &mmps, sizeof(MOUNTMGR_MOUNT_POINTS),
912 FALSE, NULL);
913
914 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
915 ERR("IOCTL_MOUNTMGR_QUERY_POINTS 1 returned %08x\n", Status);
916
917 if (mmps.Size > 0) {
918 MOUNTMGR_MOUNT_POINTS* mmps2;
919
920 mmps2 = ExAllocatePoolWithTag(NonPagedPool, mmps.Size, ALLOC_TAG);
921 if (!mmps2) {
922 ERR("out of memory\n");
923 break;
924 }
925
926 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp, sizeof(MOUNTMGR_MOUNT_POINTS), mmps2, mmps.Size,
927 FALSE, NULL);
928 if (!NT_SUCCESS(Status))
929 ERR("IOCTL_MOUNTMGR_QUERY_POINTS returned %08x\n", Status);
930 else
931 mountmgr_updated(mountmgr, mmps2);
932
933 ExFreePool(mmps2);
934 }
935 }
936
937 ObDereferenceObject(FileObject);
938
939 mountmgr_thread_handle = NULL;
940
941 PsTerminateSystemThread(STATUS_SUCCESS);
942 }