[REISERFS]
[reactos.git] / reactos / drivers / filesystems / btrfs / search.c
1 /* Copyright (c) Mark Harmstone 2016
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
27 #include <initguid.h>
28 #ifndef __REACTOS__
29 #include <winioctl.h>
30 #endif
31 #include <wdmguid.h>
32
33 extern LIST_ENTRY volumes;
34 extern ERESOURCE volumes_lock;
35 extern LIST_ENTRY pnp_disks;
36
37 static NTSTATUS create_part0(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT DeviceObject, PUNICODE_STRING devpath,
38 PUNICODE_STRING nameus, BTRFS_UUID* uuid) {
39 PDEVICE_OBJECT newdevobj;
40 UNICODE_STRING name;
41 NTSTATUS Status;
42 part0_device_extension* p0de;
43
44 static const WCHAR part0_suffix[] = L"Btrfs";
45
46 name.Length = name.MaximumLength = devpath->Length + (wcslen(part0_suffix) * sizeof(WCHAR));
47 name.Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG);
48 if (!name.Buffer) {
49 ERR("out of memory\n");
50 return STATUS_INSUFFICIENT_RESOURCES;
51 }
52
53 RtlCopyMemory(name.Buffer, devpath->Buffer, devpath->Length);
54 RtlCopyMemory(&name.Buffer[devpath->Length / sizeof(WCHAR)], part0_suffix, wcslen(part0_suffix) * sizeof(WCHAR));
55
56 Status = IoCreateDevice(DriverObject, sizeof(part0_device_extension), &name, FILE_DEVICE_DISK, FILE_DEVICE_SECURE_OPEN, FALSE, &newdevobj);
57 if (!NT_SUCCESS(Status)) {
58 ERR("IoCreateDevice returned %08x\n", Status);
59 ExFreePool(name.Buffer);
60 return Status;
61 }
62
63 p0de = newdevobj->DeviceExtension;
64 p0de->type = VCB_TYPE_PARTITION0;
65 p0de->devobj = DeviceObject;
66 RtlCopyMemory(&p0de->uuid, uuid, sizeof(BTRFS_UUID));
67
68 p0de->name.Length = name.Length;
69 p0de->name.MaximumLength = name.MaximumLength;
70 p0de->name.Buffer = ExAllocatePoolWithTag(PagedPool, p0de->name.MaximumLength, ALLOC_TAG);
71
72 if (!p0de->name.Buffer) {
73 ERR("out of memory\b");
74 ExFreePool(name.Buffer);
75 ExFreePool(p0de->name.Buffer);
76 IoDeleteDevice(newdevobj);
77 return STATUS_INSUFFICIENT_RESOURCES;
78 }
79
80 RtlCopyMemory(p0de->name.Buffer, name.Buffer, name.Length);
81
82 ObReferenceObject(DeviceObject);
83
84 newdevobj->StackSize = DeviceObject->StackSize + 1;
85 newdevobj->SectorSize = DeviceObject->SectorSize;
86
87 newdevobj->Flags |= DO_DIRECT_IO;
88 newdevobj->Flags &= ~DO_DEVICE_INITIALIZING;
89
90 *nameus = name;
91
92 return STATUS_SUCCESS;
93 }
94
95 void add_volume(PDEVICE_OBJECT mountmgr, PUNICODE_STRING us) {
96 ULONG tnsize;
97 MOUNTMGR_TARGET_NAME* tn;
98 KEVENT Event;
99 IO_STATUS_BLOCK IoStatusBlock;
100 PIRP Irp;
101 NTSTATUS Status;
102 ULONG mmdltsize;
103 MOUNTMGR_DRIVE_LETTER_TARGET* mmdlt;
104 MOUNTMGR_DRIVE_LETTER_INFORMATION mmdli;
105
106 TRACE("found BTRFS volume\n");
107
108 tnsize = sizeof(MOUNTMGR_TARGET_NAME) - sizeof(WCHAR) + us->Length;
109 tn = ExAllocatePoolWithTag(NonPagedPool, tnsize, ALLOC_TAG);
110 if (!tn) {
111 ERR("out of memory\n");
112 return;
113 }
114
115 tn->DeviceNameLength = us->Length;
116 RtlCopyMemory(tn->DeviceName, us->Buffer, tn->DeviceNameLength);
117
118 KeInitializeEvent(&Event, NotificationEvent, FALSE);
119 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
120 mountmgr, tn, tnsize,
121 NULL, 0, FALSE, &Event, &IoStatusBlock);
122 if (!Irp) {
123 ERR("%.*S: IoBuildDeviceIoControlRequest 1 failed\n", us->Length / sizeof(WCHAR), us->Buffer);
124 ExFreePool(tn);
125 return;
126 }
127
128 Status = IoCallDriver(mountmgr, Irp);
129 if (Status == STATUS_PENDING) {
130 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
131 Status = IoStatusBlock.Status;
132 }
133
134 if (!NT_SUCCESS(Status)) {
135 ERR("%.*S: IoCallDriver 1 returned %08x\n", us->Length / sizeof(WCHAR), us->Buffer, Status);
136 return;
137 }
138
139 ExFreePool(tn);
140
141 mmdltsize = offsetof(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName[0]) + us->Length;
142
143 mmdlt = ExAllocatePoolWithTag(NonPagedPool, mmdltsize, ALLOC_TAG);
144 if (!mmdlt) {
145 ERR("out of memory\n");
146 return;
147 }
148
149 mmdlt->DeviceNameLength = us->Length;
150 RtlCopyMemory(&mmdlt->DeviceName, us->Buffer, us->Length);
151 TRACE("mmdlt = %.*S\n", mmdlt->DeviceNameLength / sizeof(WCHAR), mmdlt->DeviceName);
152
153 KeInitializeEvent(&Event, NotificationEvent, FALSE);
154 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER,
155 mountmgr, mmdlt, mmdltsize,
156 &mmdli, sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION), FALSE, &Event, &IoStatusBlock);
157 if (!Irp) {
158 ERR("%.*S: IoBuildDeviceIoControlRequest 2 failed\n", us->Length / sizeof(WCHAR), us->Buffer);
159 return;
160 }
161
162 Status = IoCallDriver(mountmgr, Irp);
163 if (Status == STATUS_PENDING) {
164 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
165 Status = IoStatusBlock.Status;
166 }
167
168 if (!NT_SUCCESS(Status)) {
169 ERR("%.*S: IoCallDriver 2 returned %08x\n", us->Length / sizeof(WCHAR), us->Buffer, Status);
170 } else
171 TRACE("DriveLetterWasAssigned = %u, CurrentDriveLetter = %c\n", mmdli.DriveLetterWasAssigned, mmdli.CurrentDriveLetter);
172
173 ExFreePool(mmdlt);
174 }
175
176 static void STDCALL test_vol(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath, DWORD disk_num, DWORD part_num, LIST_ENTRY* volumes) {
177 KEVENT Event;
178 PIRP Irp;
179 IO_STATUS_BLOCK IoStatusBlock;
180 NTSTATUS Status;
181 PFILE_OBJECT FileObject;
182 PDEVICE_OBJECT DeviceObject;
183 LARGE_INTEGER Offset;
184 ULONG toread;
185 UINT8* data = NULL;
186 UINT32 sector_size;
187
188 TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
189
190 Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject);
191 if (!NT_SUCCESS(Status)) {
192 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
193 return;
194 }
195
196 sector_size = DeviceObject->SectorSize;
197
198 if (sector_size == 0) {
199 DISK_GEOMETRY geometry;
200 IO_STATUS_BLOCK iosb;
201
202 Status = dev_ioctl(DeviceObject, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
203 &geometry, sizeof(DISK_GEOMETRY), TRUE, &iosb);
204
205 if (!NT_SUCCESS(Status)) {
206 ERR("%.*S had a sector size of 0, and IOCTL_DISK_GET_DRIVE_GEOMETRY returned %08x\n",
207 devpath->Length / sizeof(WCHAR), devpath->Buffer, Status);
208 goto deref;
209 }
210
211 if (iosb.Information < sizeof(DISK_GEOMETRY)) {
212 ERR("%.*S: IOCTL_DISK_GET_DRIVE_GEOMETRY returned %u bytes, expected %u\n",
213 devpath->Length / sizeof(WCHAR), devpath->Buffer, iosb.Information, sizeof(DISK_GEOMETRY));
214 }
215
216 sector_size = geometry.BytesPerSector;
217
218 if (sector_size == 0) {
219 ERR("%.*S had a sector size of 0\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
220 goto deref;
221 }
222 }
223
224 KeInitializeEvent(&Event, NotificationEvent, FALSE);
225
226 Offset.QuadPart = superblock_addrs[0];
227
228 toread = sector_align(sizeof(superblock), sector_size);
229 data = ExAllocatePoolWithTag(NonPagedPool, toread, ALLOC_TAG);
230 if (!data) {
231 ERR("out of memory\n");
232 goto deref;
233 }
234
235 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, data, toread, &Offset, &Event, &IoStatusBlock);
236
237 if (!Irp) {
238 ERR("IoBuildSynchronousFsdRequest failed\n");
239 goto deref;
240 }
241
242 Status = IoCallDriver(DeviceObject, Irp);
243
244 if (Status == STATUS_PENDING) {
245 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
246 Status = IoStatusBlock.Status;
247 }
248
249 if (NT_SUCCESS(Status) && IoStatusBlock.Information > 0 && ((superblock*)data)->magic == BTRFS_MAGIC) {
250 int i;
251 GET_LENGTH_INFORMATION gli;
252 superblock* sb = (superblock*)data;
253 volume* v = ExAllocatePoolWithTag(PagedPool, sizeof(volume), ALLOC_TAG);
254
255 if (!v) {
256 ERR("out of memory\n");
257 goto deref;
258 }
259
260 Status = dev_ioctl(DeviceObject, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
261 &gli, sizeof(gli), TRUE, NULL);
262 if (!NT_SUCCESS(Status)) {
263 ERR("error reading length information: %08x\n", Status);
264 ExFreePool(v);
265 goto deref;
266 }
267
268 if (part_num == 0) {
269 UNICODE_STRING us3;
270
271 Status = create_part0(DriverObject, DeviceObject, devpath, &us3, &sb->dev_item.device_uuid);
272
273 if (!NT_SUCCESS(Status)) {
274 ERR("create_part0 returned %08x\n", Status);
275 ExFreePool(v);
276 goto deref;
277 }
278
279 v->devpath = us3;
280 } else {
281 v->devpath.Length = v->devpath.MaximumLength = devpath->Length;
282 v->devpath.Buffer = ExAllocatePoolWithTag(PagedPool, v->devpath.Length, ALLOC_TAG);
283
284 if (!v->devpath.Buffer) {
285 ERR("out of memory\n");
286 ExFreePool(v);
287 goto deref;
288 }
289
290 RtlCopyMemory(v->devpath.Buffer, devpath->Buffer, v->devpath.Length);
291 }
292
293 RtlCopyMemory(&v->fsuuid, &sb->uuid, sizeof(BTRFS_UUID));
294 RtlCopyMemory(&v->devuuid, &sb->dev_item.device_uuid, sizeof(BTRFS_UUID));
295 v->devnum = sb->dev_item.dev_id;
296 v->processed = FALSE;
297 v->length = gli.Length.QuadPart;
298 v->gen1 = sb->generation;
299 v->gen2 = 0;
300 v->seeding = sb->flags & BTRFS_SUPERBLOCK_FLAGS_SEEDING ? TRUE : FALSE;
301 v->disk_num = disk_num;
302 v->part_num = part_num;
303
304 ExAcquireResourceExclusiveLite(&volumes_lock, TRUE);
305 InsertTailList(volumes, &v->list_entry);
306 ExReleaseResourceLite(&volumes_lock);
307
308 i = 1;
309 while (superblock_addrs[i] != 0 && superblock_addrs[i] + toread <= v->length) {
310 KeInitializeEvent(&Event, NotificationEvent, FALSE);
311
312 Offset.QuadPart = superblock_addrs[i];
313
314 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ, DeviceObject, data, toread, &Offset, &Event, &IoStatusBlock);
315
316 if (!Irp) {
317 ERR("IoBuildSynchronousFsdRequest failed\n");
318 goto deref;
319 }
320
321 Status = IoCallDriver(DeviceObject, Irp);
322
323 if (Status == STATUS_PENDING) {
324 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
325 Status = IoStatusBlock.Status;
326 }
327
328 if (NT_SUCCESS(Status)) {
329 UINT32 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum));
330
331 if (crc32 != *((UINT32*)sb->checksum))
332 WARN("superblock %u CRC error\n", i);
333 else if (sb->generation > v->gen1) {
334 v->gen2 = v->gen1;
335 v->gen1 = sb->generation;
336 }
337 } else {
338 ERR("got error %08x while reading superblock %u\n", Status, i);
339 }
340
341 i++;
342 }
343
344 TRACE("volume found\n");
345 TRACE("gen1 = %llx, gen2 = %llx\n", v->gen1, v->gen2);
346 TRACE("FS uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
347 v->fsuuid.uuid[0], v->fsuuid.uuid[1], v->fsuuid.uuid[2], v->fsuuid.uuid[3], v->fsuuid.uuid[4], v->fsuuid.uuid[5], v->fsuuid.uuid[6], v->fsuuid.uuid[7],
348 v->fsuuid.uuid[8], v->fsuuid.uuid[9], v->fsuuid.uuid[10], v->fsuuid.uuid[11], v->fsuuid.uuid[12], v->fsuuid.uuid[13], v->fsuuid.uuid[14], v->fsuuid.uuid[15]);
349 TRACE("device uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
350 v->devuuid.uuid[0], v->devuuid.uuid[1], v->devuuid.uuid[2], v->devuuid.uuid[3], v->devuuid.uuid[4], v->devuuid.uuid[5], v->devuuid.uuid[6], v->devuuid.uuid[7],
351 v->devuuid.uuid[8], v->devuuid.uuid[9], v->devuuid.uuid[10], v->devuuid.uuid[11], v->devuuid.uuid[12], v->devuuid.uuid[13], v->devuuid.uuid[14], v->devuuid.uuid[15]);
352 TRACE("device number %llx\n", v->devnum);
353 }
354
355 deref:
356 if (data)
357 ExFreePool(data);
358
359 ObDereferenceObject(FileObject);
360 }
361
362 void remove_drive_letter(PDEVICE_OBJECT mountmgr, volume* v) {
363 NTSTATUS Status;
364 KEVENT Event;
365 PIRP Irp;
366 MOUNTMGR_MOUNT_POINT* mmp;
367 ULONG mmpsize;
368 MOUNTMGR_MOUNT_POINTS mmps1, *mmps2;
369 IO_STATUS_BLOCK IoStatusBlock;
370
371 mmpsize = sizeof(MOUNTMGR_MOUNT_POINT) + v->devpath.Length;
372
373 mmp = ExAllocatePoolWithTag(PagedPool, mmpsize, ALLOC_TAG);
374 if (!mmp) {
375 ERR("out of memory\n");
376 return;
377 }
378
379 RtlZeroMemory(mmp, mmpsize);
380
381 mmp->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
382 mmp->DeviceNameLength = v->devpath.Length;
383 RtlCopyMemory(&mmp[1], v->devpath.Buffer, v->devpath.Length);
384
385 KeInitializeEvent(&Event, NotificationEvent, FALSE);
386 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS,
387 mountmgr, mmp, mmpsize,
388 &mmps1, sizeof(MOUNTMGR_MOUNT_POINTS), FALSE, &Event, &IoStatusBlock);
389 if (!Irp) {
390 ERR("%.*S: IoBuildDeviceIoControlRequest 1 failed\n", v->devpath.Length / sizeof(WCHAR), v->devpath.Buffer);
391 ExFreePool(mmp);
392 return;
393 }
394
395 Status = IoCallDriver(mountmgr, Irp);
396 if (Status == STATUS_PENDING) {
397 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
398 Status = IoStatusBlock.Status;
399 }
400
401 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
402 ERR("%.*S: IoCallDriver 1 returned %08x\n", v->devpath.Length / sizeof(WCHAR), v->devpath.Buffer, Status);
403 ExFreePool(mmp);
404 return;
405 }
406
407 if (Status != STATUS_BUFFER_OVERFLOW || mmps1.Size == 0) {
408 ExFreePool(mmp);
409 return;
410 }
411
412 mmps2 = ExAllocatePoolWithTag(PagedPool, mmps1.Size, ALLOC_TAG);
413 if (!mmps2) {
414 ERR("out of memory\n");
415 ExFreePool(mmp);
416 return;
417 }
418
419 KeInitializeEvent(&Event, NotificationEvent, FALSE);
420 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS,
421 mountmgr, mmp, mmpsize,
422 mmps2, mmps1.Size, FALSE, &Event, &IoStatusBlock);
423 if (!Irp) {
424 ERR("%.*S: IoBuildDeviceIoControlRequest 2 failed\n", v->devpath.Length / sizeof(WCHAR), v->devpath.Buffer);
425 ExFreePool(mmps2);
426 ExFreePool(mmp);
427 return;
428 }
429
430 Status = IoCallDriver(mountmgr, Irp);
431 if (Status == STATUS_PENDING) {
432 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
433 Status = IoStatusBlock.Status;
434 }
435
436 if (!NT_SUCCESS(Status)) {
437 ERR("%.*S: IoCallDriver 2 returned %08x\n", v->devpath.Length / sizeof(WCHAR), v->devpath.Buffer, Status);
438 ExFreePool(mmps2);
439 ExFreePool(mmp);
440 return;
441 }
442
443 ExFreePool(mmps2);
444 ExFreePool(mmp);
445 }
446
447 static void refresh_mountmgr(PDEVICE_OBJECT mountmgr, LIST_ENTRY* volumes) {
448 LIST_ENTRY* le;
449
450 ExAcquireResourceExclusiveLite(&volumes_lock, TRUE);
451
452 le = volumes->Flink;
453 while (le != volumes) {
454 volume* v = CONTAINING_RECORD(le, volume, list_entry);
455
456 if (!v->processed) {
457 LIST_ENTRY* le2 = le;
458 volume* mountvol = v;
459
460 while (le2 != volumes) {
461 volume* v2 = CONTAINING_RECORD(le2, volume, list_entry);
462
463 if (RtlCompareMemory(&v2->fsuuid, &v->fsuuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
464 v2->processed = TRUE;
465
466 if (v2->devnum < mountvol->devnum) {
467 remove_drive_letter(mountmgr, mountvol);
468 mountvol = v2;
469 } else if (v2->devnum > mountvol->devnum)
470 remove_drive_letter(mountmgr, v2);
471 }
472
473 le2 = le2->Flink;
474 }
475
476 add_volume(mountmgr, &mountvol->devpath);
477 }
478
479 le = le->Flink;
480 }
481
482 ExReleaseResourceLite(&volumes_lock);
483 }
484
485 static void add_pnp_disk(ULONG disk_num, PUNICODE_STRING devpath) {
486 LIST_ENTRY* le;
487 pnp_disk* disk;
488
489 le = pnp_disks.Flink;
490 while (le != &pnp_disks) {
491 disk = CONTAINING_RECORD(le, pnp_disk, list_entry);
492
493 if (disk->devpath.Length == devpath->Length &&
494 RtlCompareMemory(disk->devpath.Buffer, devpath->Buffer, devpath->Length) == devpath->Length)
495 return;
496
497 le = le->Flink;
498 }
499
500 disk = ExAllocatePoolWithTag(PagedPool, sizeof(pnp_disk), ALLOC_TAG);
501 if (!disk) {
502 ERR("out of memory\n");
503 return;
504 }
505
506 disk->devpath.Length = disk->devpath.MaximumLength = devpath->Length;
507 disk->devpath.Buffer = ExAllocatePoolWithTag(PagedPool, devpath->Length, ALLOC_TAG);
508
509 if (!disk->devpath.Buffer) {
510 ERR("out of memory\n");
511 ExFreePool(disk);
512 return;
513 }
514
515 RtlCopyMemory(disk->devpath.Buffer, devpath->Buffer, devpath->Length);
516
517 disk->disk_num = disk_num;
518
519 InsertTailList(&pnp_disks, &disk->list_entry);
520 }
521
522 static void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
523 PFILE_OBJECT FileObject, FileObject2;
524 PDEVICE_OBJECT devobj, mountmgr;
525 NTSTATUS Status;
526 STORAGE_DEVICE_NUMBER sdn;
527 ULONG dlisize;
528 DRIVE_LAYOUT_INFORMATION_EX* dli;
529 IO_STATUS_BLOCK iosb;
530 int i, num_parts = 0;
531 UNICODE_STRING devname, num, bspus, mmdevpath;
532 WCHAR devnamew[255], numw[20];
533 USHORT preflen;
534
535 static WCHAR device_harddisk[] = L"\\Device\\Harddisk";
536 static WCHAR bs_partition[] = L"\\Partition";
537
538 // FIXME - work with CD-ROMs and floppies(?)
539
540 Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &devobj);
541 if (!NT_SUCCESS(Status)) {
542 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
543 return;
544 }
545
546 RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
547 Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject2, &mountmgr);
548 if (!NT_SUCCESS(Status)) {
549 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
550 ObDereferenceObject(FileObject);
551 return;
552 }
553
554 Status = dev_ioctl(devobj, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
555 &sdn, sizeof(STORAGE_DEVICE_NUMBER), TRUE, &iosb);
556 if (!NT_SUCCESS(Status)) {
557 ERR("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status);
558 goto end;
559 }
560
561 ExAcquireResourceExclusiveLite(&volumes_lock, TRUE);
562 add_pnp_disk(sdn.DeviceNumber, devpath);
563 ExReleaseResourceLite(&volumes_lock);
564
565 dlisize = 0;
566
567 do {
568 dlisize += 1024;
569 dli = ExAllocatePoolWithTag(PagedPool, dlisize, ALLOC_TAG);
570
571 Status = dev_ioctl(devobj, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0,
572 dli, dlisize, TRUE, &iosb);
573 } while (Status == STATUS_BUFFER_TOO_SMALL);
574
575 if (!NT_SUCCESS(Status)) {
576 ExFreePool(dli);
577 goto no_parts;
578 }
579
580 wcscpy(devnamew, device_harddisk);
581 devname.Buffer = devnamew;
582 devname.MaximumLength = sizeof(devnamew);
583 devname.Length = wcslen(device_harddisk) * sizeof(WCHAR);
584
585 num.Buffer = numw;
586 num.MaximumLength = sizeof(numw);
587 RtlIntegerToUnicodeString(sdn.DeviceNumber, 10, &num);
588 RtlAppendUnicodeStringToString(&devname, &num);
589
590 bspus.Buffer = bs_partition;
591 bspus.Length = bspus.MaximumLength = wcslen(bs_partition) * sizeof(WCHAR);
592 RtlAppendUnicodeStringToString(&devname, &bspus);
593
594 preflen = devname.Length;
595
596 for (i = 0; i < dli->PartitionCount; i++) {
597 if (dli->PartitionEntry[i].PartitionLength.QuadPart != 0 && dli->PartitionEntry[i].PartitionNumber != 0) {
598 devname.Length = preflen;
599 RtlIntegerToUnicodeString(dli->PartitionEntry[i].PartitionNumber, 10, &num);
600 RtlAppendUnicodeStringToString(&devname, &num);
601
602 test_vol(DriverObject, mountmgr, &devname, sdn.DeviceNumber, dli->PartitionEntry[i].PartitionNumber, &volumes);
603
604 num_parts++;
605 }
606 }
607
608 ExFreePool(dli);
609
610 no_parts:
611 if (num_parts == 0) {
612 devname.Length = preflen;
613 devname.Buffer[devname.Length / sizeof(WCHAR)] = '0';
614 devname.Length += sizeof(WCHAR);
615
616 test_vol(DriverObject, mountmgr, &devname, sdn.DeviceNumber, 0, &volumes);
617 }
618
619 end:
620 refresh_mountmgr(mountmgr, &volumes);
621
622 ObDereferenceObject(FileObject);
623 ObDereferenceObject(FileObject2);
624 }
625
626 static void disk_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
627 LIST_ENTRY* le;
628 pnp_disk* disk = NULL;
629
630 // FIXME - remove Partition0Btrfs devices and unlink from mountmgr
631 // FIXME - emergency unmount of RAIDed volumes
632
633 ExAcquireResourceExclusiveLite(&volumes_lock, TRUE);
634
635 le = pnp_disks.Flink;
636 while (le != &pnp_disks) {
637 pnp_disk* disk2 = CONTAINING_RECORD(le, pnp_disk, list_entry);
638
639 if (disk2->devpath.Length == devpath->Length &&
640 RtlCompareMemory(disk2->devpath.Buffer, devpath->Buffer, devpath->Length) == devpath->Length) {
641 disk = disk2;
642 break;
643 }
644
645 le = le->Flink;
646 }
647
648 if (!disk) {
649 ExReleaseResourceLite(&volumes_lock);
650 return;
651 }
652
653 le = volumes.Flink;
654 while (le != &volumes) {
655 volume* v = CONTAINING_RECORD(le, volume, list_entry);
656 LIST_ENTRY* le2 = le->Flink;
657
658 if (v->disk_num == disk->disk_num) {
659 if (v->devpath.Buffer)
660 ExFreePool(v->devpath.Buffer);
661
662 RemoveEntryList(&v->list_entry);
663
664 ExFreePool(v);
665 }
666
667 le = le2;
668 }
669
670 ExReleaseResourceLite(&volumes_lock);
671
672 ExFreePool(disk->devpath.Buffer);
673
674 RemoveEntryList(&disk->list_entry);
675
676 ExFreePool(disk);
677 }
678
679 #ifdef __REACTOS__
680 NTSTATUS NTAPI pnp_notification(PVOID NotificationStructure, PVOID Context) {
681 #else
682 NTSTATUS pnp_notification(PVOID NotificationStructure, PVOID Context) {
683 #endif
684 DEVICE_INTERFACE_CHANGE_NOTIFICATION* dicn = (DEVICE_INTERFACE_CHANGE_NOTIFICATION*)NotificationStructure;
685 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Context;
686
687 if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID))
688 disk_arrival(DriverObject, dicn->SymbolicLinkName);
689 else if (RtlCompareMemory(&dicn->Event, &GUID_DEVICE_INTERFACE_REMOVAL, sizeof(GUID)) == sizeof(GUID))
690 disk_removal(DriverObject, dicn->SymbolicLinkName);
691
692 return STATUS_SUCCESS;
693 }