Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / drivers / filesystems / btrfs / volume.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 #include <mountdev.h>
20 #include <ntddvol.h>
21 #include <ntddstor.h>
22 #include <ntdddisk.h>
23 #include <wdmguid.h>
24
25 #define IOCTL_VOLUME_IS_DYNAMIC CTL_CODE(IOCTL_VOLUME_BASE, 18, METHOD_BUFFERED, FILE_ANY_ACCESS)
26 #define IOCTL_VOLUME_POST_ONLINE CTL_CODE(IOCTL_VOLUME_BASE, 25, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
27
28 extern PDRIVER_OBJECT drvobj;
29 extern PDEVICE_OBJECT master_devobj;
30 extern ERESOURCE pdo_list_lock;
31 extern LIST_ENTRY pdo_list;
32 extern UNICODE_STRING registry_path;
33
34 NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
35 volume_device_extension* vde = DeviceObject->DeviceExtension;
36
37 TRACE("(%p, %p)\n", DeviceObject, Irp);
38
39 if (vde->removing)
40 return STATUS_DEVICE_NOT_READY;
41
42 Irp->IoStatus.Information = FILE_OPENED;
43 InterlockedIncrement(&vde->open_count);
44
45 return STATUS_SUCCESS;
46 }
47
48 NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
49 volume_device_extension* vde = DeviceObject->DeviceExtension;
50 pdo_device_extension* pdode = vde->pdode;
51
52 TRACE("(%p, %p)\n", DeviceObject, Irp);
53
54 Irp->IoStatus.Information = 0;
55
56 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
57
58 if (InterlockedDecrement(&vde->open_count) == 0 && vde->removing) {
59 NTSTATUS Status;
60 UNICODE_STRING mmdevpath;
61 PDEVICE_OBJECT mountmgr;
62 PFILE_OBJECT mountmgrfo;
63 PDEVICE_OBJECT pdo;
64
65 RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
66 Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr);
67 if (!NT_SUCCESS(Status))
68 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
69 else {
70 remove_drive_letter(mountmgr, &vde->name);
71
72 ObDereferenceObject(mountmgrfo);
73 }
74
75 if (vde->mounted_device) {
76 device_extension* Vcb = vde->mounted_device->DeviceExtension;
77
78 Vcb->vde = NULL;
79 }
80
81 if (vde->name.Buffer)
82 ExFreePool(vde->name.Buffer);
83
84 ExReleaseResourceLite(&pdode->child_lock);
85 ExDeleteResourceLite(&pdode->child_lock);
86 IoDetachDevice(vde->pdo);
87
88 pdo = vde->pdo;
89 IoDeleteDevice(vde->device);
90
91 if (no_pnp)
92 IoDeleteDevice(pdo);
93 } else
94 ExReleaseResourceLite(&pdode->child_lock);
95
96 return STATUS_SUCCESS;
97 }
98
99 typedef struct {
100 IO_STATUS_BLOCK iosb;
101 KEVENT Event;
102 } vol_read_context;
103
104 _Function_class_(IO_COMPLETION_ROUTINE)
105 #ifdef __REACTOS__
106 static NTSTATUS NTAPI vol_read_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
107 #else
108 static NTSTATUS vol_read_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
109 #endif
110 vol_read_context* context = conptr;
111
112 UNUSED(DeviceObject);
113
114 context->iosb = Irp->IoStatus;
115 KeSetEvent(&context->Event, 0, FALSE);
116
117 return STATUS_MORE_PROCESSING_REQUIRED;
118 }
119
120 NTSTATUS vol_read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
121 volume_device_extension* vde = DeviceObject->DeviceExtension;
122 pdo_device_extension* pdode = vde->pdode;
123 volume_child* vc;
124 NTSTATUS Status;
125 PIRP Irp2;
126 vol_read_context context;
127 PIO_STACK_LOCATION IrpSp, IrpSp2;
128
129 TRACE("(%p, %p)\n", DeviceObject, Irp);
130
131 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
132
133 if (IsListEmpty(&pdode->children)) {
134 ExReleaseResourceLite(&pdode->child_lock);
135 Status = STATUS_INVALID_DEVICE_REQUEST;
136 goto end;
137 }
138
139 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry);
140
141 // We can't use IoSkipCurrentIrpStackLocation as the device isn't in our stack
142
143 Irp2 = IoAllocateIrp(vc->devobj->StackSize, FALSE);
144
145 if (!Irp2) {
146 ERR("IoAllocateIrp failed\n");
147 ExReleaseResourceLite(&pdode->child_lock);
148 Status = STATUS_INSUFFICIENT_RESOURCES;
149 goto end;
150 }
151
152 IrpSp = IoGetCurrentIrpStackLocation(Irp);
153 IrpSp2 = IoGetNextIrpStackLocation(Irp2);
154
155 IrpSp2->MajorFunction = IRP_MJ_READ;
156
157 if (vc->devobj->Flags & DO_BUFFERED_IO) {
158 Irp2->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, IrpSp->Parameters.Read.Length, ALLOC_TAG);
159 if (!Irp2->AssociatedIrp.SystemBuffer) {
160 ERR("out of memory\n");
161 ExReleaseResourceLite(&pdode->child_lock);
162 Status = STATUS_INSUFFICIENT_RESOURCES;
163 goto end;
164 }
165
166 Irp2->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
167
168 Irp2->UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
169 } else if (vc->devobj->Flags & DO_DIRECT_IO)
170 Irp2->MdlAddress = Irp->MdlAddress;
171 else
172 Irp2->UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
173
174 IrpSp2->Parameters.Read.Length = IrpSp->Parameters.Read.Length;
175 IrpSp2->Parameters.Read.ByteOffset.QuadPart = IrpSp->Parameters.Read.ByteOffset.QuadPart;
176
177 KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
178 Irp2->UserIosb = &context.iosb;
179
180 IoSetCompletionRoutine(Irp2, vol_read_completion, &context, TRUE, TRUE, TRUE);
181
182 Status = IoCallDriver(vc->devobj, Irp2);
183
184 if (Status == STATUS_PENDING) {
185 KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL);
186 Status = context.iosb.Status;
187 }
188
189 ExReleaseResourceLite(&pdode->child_lock);
190
191 Irp->IoStatus.Information = context.iosb.Information;
192
193 end:
194 Irp->IoStatus.Status = Status;
195 IoCompleteRequest(Irp, IO_NO_INCREMENT);
196
197 return Status;
198 }
199
200 NTSTATUS vol_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
201 volume_device_extension* vde = DeviceObject->DeviceExtension;
202 pdo_device_extension* pdode = vde->pdode;
203 volume_child* vc;
204 NTSTATUS Status;
205 PIRP Irp2;
206 vol_read_context context;
207 PIO_STACK_LOCATION IrpSp, IrpSp2;
208
209 TRACE("(%p, %p)\n", DeviceObject, Irp);
210
211 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
212
213 if (IsListEmpty(&pdode->children)) {
214 ExReleaseResourceLite(&pdode->child_lock);
215 Status = STATUS_INVALID_DEVICE_REQUEST;
216 goto end;
217 }
218
219 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry);
220
221 if (vc->list_entry.Flink != &pdode->children) { // more than once device
222 ExReleaseResourceLite(&pdode->child_lock);
223 Status = STATUS_ACCESS_DENIED;
224 goto end;
225 }
226
227 // We can't use IoSkipCurrentIrpStackLocation as the device isn't in our stack
228
229 Irp2 = IoAllocateIrp(vc->devobj->StackSize, FALSE);
230
231 if (!Irp2) {
232 ERR("IoAllocateIrp failed\n");
233 ExReleaseResourceLite(&pdode->child_lock);
234 Status = STATUS_INSUFFICIENT_RESOURCES;
235 goto end;
236 }
237
238 IrpSp = IoGetCurrentIrpStackLocation(Irp);
239 IrpSp2 = IoGetNextIrpStackLocation(Irp2);
240
241 IrpSp2->MajorFunction = IRP_MJ_WRITE;
242
243 if (vc->devobj->Flags & DO_BUFFERED_IO) {
244 Irp2->AssociatedIrp.SystemBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
245
246 Irp2->Flags |= IRP_BUFFERED_IO;
247
248 Irp2->UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
249 } else if (vc->devobj->Flags & DO_DIRECT_IO)
250 Irp2->MdlAddress = Irp->MdlAddress;
251 else
252 Irp2->UserBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
253
254 IrpSp2->Parameters.Write.Length = IrpSp->Parameters.Write.Length;
255 IrpSp2->Parameters.Write.ByteOffset.QuadPart = IrpSp->Parameters.Write.ByteOffset.QuadPart;
256
257 KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
258 Irp2->UserIosb = &context.iosb;
259
260 IoSetCompletionRoutine(Irp2, vol_read_completion, &context, TRUE, TRUE, TRUE);
261
262 Status = IoCallDriver(vc->devobj, Irp2);
263
264 if (Status == STATUS_PENDING) {
265 KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL);
266 Status = context.iosb.Status;
267 }
268
269 ExReleaseResourceLite(&pdode->child_lock);
270
271 Irp->IoStatus.Information = context.iosb.Information;
272
273 end:
274 Irp->IoStatus.Status = Status;
275 IoCompleteRequest(Irp, IO_NO_INCREMENT);
276
277 return Status;
278 }
279
280 NTSTATUS vol_query_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
281 TRACE("(%p, %p)\n", DeviceObject, Irp);
282
283 return STATUS_INVALID_DEVICE_REQUEST;
284 }
285
286 NTSTATUS vol_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
287 TRACE("(%p, %p)\n", DeviceObject, Irp);
288
289 return STATUS_INVALID_DEVICE_REQUEST;
290 }
291
292 NTSTATUS vol_query_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
293 TRACE("(%p, %p)\n", DeviceObject, Irp);
294
295 return STATUS_INVALID_DEVICE_REQUEST;
296 }
297
298 NTSTATUS vol_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
299 TRACE("(%p, %p)\n", DeviceObject, Irp);
300
301 return STATUS_INVALID_DEVICE_REQUEST;
302 }
303
304 NTSTATUS vol_flush_buffers(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
305 TRACE("(%p, %p)\n", DeviceObject, Irp);
306
307 return STATUS_INVALID_DEVICE_REQUEST;
308 }
309
310 NTSTATUS vol_query_volume_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
311 TRACE("(%p, %p)\n", DeviceObject, Irp);
312
313 return STATUS_INVALID_DEVICE_REQUEST;
314 }
315
316 NTSTATUS vol_set_volume_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
317 TRACE("(%p, %p)\n", DeviceObject, Irp);
318
319 return STATUS_INVALID_DEVICE_REQUEST;
320 }
321
322 NTSTATUS vol_cleanup(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
323 TRACE("(%p, %p)\n", DeviceObject, Irp);
324
325 Irp->IoStatus.Information = 0;
326
327 return STATUS_SUCCESS;
328 }
329
330 NTSTATUS vol_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
331 TRACE("(%p, %p)\n", DeviceObject, Irp);
332
333 return STATUS_INVALID_DEVICE_REQUEST;
334 }
335
336 NTSTATUS vol_file_system_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
337 TRACE("(%p, %p)\n", DeviceObject, Irp);
338
339 return STATUS_INVALID_DEVICE_REQUEST;
340 }
341
342 NTSTATUS vol_lock_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
343 TRACE("(%p, %p)\n", DeviceObject, Irp);
344
345 return STATUS_INVALID_DEVICE_REQUEST;
346 }
347
348 static NTSTATUS vol_query_device_name(volume_device_extension* vde, PIRP Irp) {
349 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
350 PMOUNTDEV_NAME name;
351
352 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_NAME)) {
353 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
354 return STATUS_BUFFER_TOO_SMALL;
355 }
356
357 name = Irp->AssociatedIrp.SystemBuffer;
358 name->NameLength = vde->name.Length;
359
360 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < offsetof(MOUNTDEV_NAME, Name[0]) + name->NameLength) {
361 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
362 return STATUS_BUFFER_OVERFLOW;
363 }
364
365 RtlCopyMemory(name->Name, vde->name.Buffer, vde->name.Length);
366
367 Irp->IoStatus.Information = offsetof(MOUNTDEV_NAME, Name[0]) + name->NameLength;
368
369 return STATUS_SUCCESS;
370 }
371
372 static NTSTATUS vol_query_unique_id(volume_device_extension* vde, PIRP Irp) {
373 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
374 MOUNTDEV_UNIQUE_ID* mduid;
375 pdo_device_extension* pdode;
376
377 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(MOUNTDEV_UNIQUE_ID)) {
378 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
379 return STATUS_BUFFER_TOO_SMALL;
380 }
381
382 mduid = Irp->AssociatedIrp.SystemBuffer;
383 mduid->UniqueIdLength = sizeof(BTRFS_UUID);
384
385 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < offsetof(MOUNTDEV_UNIQUE_ID, UniqueId[0]) + mduid->UniqueIdLength) {
386 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
387 return STATUS_BUFFER_OVERFLOW;
388 }
389
390 if (!vde->pdo)
391 return STATUS_INVALID_PARAMETER;
392
393 pdode = vde->pdode;
394
395 RtlCopyMemory(mduid->UniqueId, &pdode->uuid, sizeof(BTRFS_UUID));
396
397 Irp->IoStatus.Information = offsetof(MOUNTDEV_UNIQUE_ID, UniqueId[0]) + mduid->UniqueIdLength;
398
399 return STATUS_SUCCESS;
400 }
401
402 static NTSTATUS vol_is_dynamic(PIRP Irp) {
403 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
404 UINT8* buf;
405
406 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0 || !Irp->AssociatedIrp.SystemBuffer)
407 return STATUS_INVALID_PARAMETER;
408
409 buf = (UINT8*)Irp->AssociatedIrp.SystemBuffer;
410
411 *buf = 1;
412
413 Irp->IoStatus.Information = 1;
414
415 return STATUS_SUCCESS;
416 }
417
418 static NTSTATUS vol_check_verify(volume_device_extension* vde) {
419 pdo_device_extension* pdode = vde->pdode;
420 NTSTATUS Status;
421 LIST_ENTRY* le;
422
423 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
424
425 le = pdode->children.Flink;
426 while (le != &pdode->children) {
427 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
428
429 Status = dev_ioctl(vc->devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, NULL, 0, FALSE, NULL);
430 if (!NT_SUCCESS(Status))
431 goto end;
432
433 le = le->Flink;
434 }
435
436 Status = STATUS_SUCCESS;
437
438 end:
439 ExReleaseResourceLite(&pdode->child_lock);
440
441 return Status;
442 }
443
444 static NTSTATUS vol_get_disk_extents(volume_device_extension* vde, PIRP Irp) {
445 pdo_device_extension* pdode = vde->pdode;
446 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
447 LIST_ENTRY* le;
448 ULONG num_extents = 0, i, max_extents = 1;
449 NTSTATUS Status;
450 VOLUME_DISK_EXTENTS *ext, *ext3;
451
452 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VOLUME_DISK_EXTENTS))
453 return STATUS_BUFFER_TOO_SMALL;
454
455 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
456
457 le = pdode->children.Flink;
458 while (le != &pdode->children) {
459 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
460 VOLUME_DISK_EXTENTS ext2;
461
462 Status = dev_ioctl(vc->devobj, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &ext2, sizeof(VOLUME_DISK_EXTENTS), FALSE, NULL);
463 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
464 ERR("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS returned %08x\n", Status);
465 goto end;
466 }
467
468 num_extents += ext2.NumberOfDiskExtents;
469
470 if (ext2.NumberOfDiskExtents > max_extents)
471 max_extents = ext2.NumberOfDiskExtents;
472
473 le = le->Flink;
474 }
475
476 ext = Irp->AssociatedIrp.SystemBuffer;
477
478 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < offsetof(VOLUME_DISK_EXTENTS, Extents[0]) + (num_extents * sizeof(DISK_EXTENT))) {
479 Irp->IoStatus.Information = offsetof(VOLUME_DISK_EXTENTS, Extents[0]);
480 ext->NumberOfDiskExtents = num_extents;
481 Status = STATUS_BUFFER_OVERFLOW;
482 goto end;
483 }
484
485 ext3 = ExAllocatePoolWithTag(PagedPool, offsetof(VOLUME_DISK_EXTENTS, Extents[0]) + (max_extents * sizeof(DISK_EXTENT)), ALLOC_TAG);
486 if (!ext3) {
487 ERR("out of memory\n");
488 Status = STATUS_INSUFFICIENT_RESOURCES;
489 goto end;
490 }
491
492 i = 0;
493 ext->NumberOfDiskExtents = 0;
494
495 le = pdode->children.Flink;
496 while (le != &pdode->children) {
497 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
498
499 Status = dev_ioctl(vc->devobj, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, ext3,
500 (ULONG)offsetof(VOLUME_DISK_EXTENTS, Extents[0]) + (max_extents * sizeof(DISK_EXTENT)), FALSE, NULL);
501 if (!NT_SUCCESS(Status)) {
502 ERR("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS returned %08x\n", Status);
503 ExFreePool(ext3);
504 goto end;
505 }
506
507 if (i + ext3->NumberOfDiskExtents > num_extents) {
508 Irp->IoStatus.Information = offsetof(VOLUME_DISK_EXTENTS, Extents[0]);
509 ext->NumberOfDiskExtents = i + ext3->NumberOfDiskExtents;
510 Status = STATUS_BUFFER_OVERFLOW;
511 ExFreePool(ext3);
512 goto end;
513 }
514
515 RtlCopyMemory(&ext->Extents[i], ext3->Extents, sizeof(DISK_EXTENT) * ext3->NumberOfDiskExtents);
516 i += ext3->NumberOfDiskExtents;
517
518 le = le->Flink;
519 }
520
521 ExFreePool(ext3);
522
523 Status = STATUS_SUCCESS;
524
525 ext->NumberOfDiskExtents = i;
526 Irp->IoStatus.Information = offsetof(VOLUME_DISK_EXTENTS, Extents[0]) + (i * sizeof(DISK_EXTENT));
527
528 end:
529 ExReleaseResourceLite(&pdode->child_lock);
530
531 return Status;
532 }
533
534 static NTSTATUS vol_is_writable(volume_device_extension* vde) {
535 pdo_device_extension* pdode = vde->pdode;
536 NTSTATUS Status;
537 LIST_ENTRY* le;
538 BOOL writable = FALSE;
539
540 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
541
542 le = pdode->children.Flink;
543 while (le != &pdode->children) {
544 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
545
546 Status = dev_ioctl(vc->devobj, IOCTL_DISK_IS_WRITABLE, NULL, 0, NULL, 0, TRUE, NULL);
547
548 if (NT_SUCCESS(Status)) {
549 writable = TRUE;
550 break;
551 } else if (Status != STATUS_MEDIA_WRITE_PROTECTED)
552 goto end;
553
554 le = le->Flink;
555 }
556
557 Status = writable ? STATUS_SUCCESS : STATUS_MEDIA_WRITE_PROTECTED;
558
559 end:
560 ExReleaseResourceLite(&pdode->child_lock);
561
562 return STATUS_SUCCESS;
563 }
564
565 static NTSTATUS vol_get_length(volume_device_extension* vde, PIRP Irp) {
566 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
567 pdo_device_extension* pdode = vde->pdode;
568 GET_LENGTH_INFORMATION* gli;
569 LIST_ENTRY* le;
570
571 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GET_LENGTH_INFORMATION))
572 return STATUS_BUFFER_TOO_SMALL;
573
574 gli = (GET_LENGTH_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
575
576 gli->Length.QuadPart = 0;
577
578 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
579
580 le = pdode->children.Flink;
581 while (le != &pdode->children) {
582 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
583
584 gli->Length.QuadPart += vc->size;
585
586 le = le->Flink;
587 }
588
589 ExReleaseResourceLite(&pdode->child_lock);
590
591 Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
592
593 return STATUS_SUCCESS;
594 }
595
596 static NTSTATUS vol_get_drive_geometry(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
597 volume_device_extension* vde = DeviceObject->DeviceExtension;
598 pdo_device_extension* pdode = vde->pdode;
599 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
600 DISK_GEOMETRY* geom;
601 UINT64 length;
602 LIST_ENTRY* le;
603
604 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY))
605 return STATUS_BUFFER_TOO_SMALL;
606
607 length = 0;
608
609 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
610
611 le = pdode->children.Flink;
612 while (le != &pdode->children) {
613 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
614
615 length += vc->size;
616
617 le = le->Flink;
618 }
619
620 ExReleaseResourceLite(&pdode->child_lock);
621
622 geom = (DISK_GEOMETRY*)Irp->AssociatedIrp.SystemBuffer;
623 geom->BytesPerSector = DeviceObject->SectorSize == 0 ? 0x200 : DeviceObject->SectorSize;
624 geom->SectorsPerTrack = 0x3f;
625 geom->TracksPerCylinder = 0xff;
626 geom->Cylinders.QuadPart = length / (UInt32x32To64(geom->TracksPerCylinder, geom->SectorsPerTrack) * geom->BytesPerSector);
627 geom->MediaType = DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA ? RemovableMedia : FixedMedia;
628
629 Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
630
631 return STATUS_SUCCESS;
632 }
633
634 static NTSTATUS vol_get_gpt_attributes(PIRP Irp) {
635 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
636 VOLUME_GET_GPT_ATTRIBUTES_INFORMATION* vggai;
637
638 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION))
639 return STATUS_BUFFER_TOO_SMALL;
640
641 vggai = (VOLUME_GET_GPT_ATTRIBUTES_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
642
643 vggai->GptAttributes = 0;
644
645 Irp->IoStatus.Information = sizeof(VOLUME_GET_GPT_ATTRIBUTES_INFORMATION);
646
647 return STATUS_SUCCESS;
648 }
649
650 static NTSTATUS vol_get_device_number(volume_device_extension* vde, PIRP Irp) {
651 pdo_device_extension* pdode = vde->pdode;
652 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
653 volume_child* vc;
654 STORAGE_DEVICE_NUMBER* sdn;
655
656 // If only one device, return its disk number. This is needed for ejection to work.
657
658 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DEVICE_NUMBER))
659 return STATUS_BUFFER_TOO_SMALL;
660
661 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
662
663 if (IsListEmpty(&pdode->children) || pdode->num_children > 1) {
664 ExReleaseResourceLite(&pdode->child_lock);
665 return STATUS_INVALID_DEVICE_REQUEST;
666 }
667
668 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry);
669
670 if (vc->disk_num == 0xffffffff) {
671 ExReleaseResourceLite(&pdode->child_lock);
672 return STATUS_INVALID_DEVICE_REQUEST;
673 }
674
675 sdn = (STORAGE_DEVICE_NUMBER*)Irp->AssociatedIrp.SystemBuffer;
676
677 sdn->DeviceType = FILE_DEVICE_DISK;
678 sdn->DeviceNumber = vc->disk_num;
679 sdn->PartitionNumber = vc->part_num;
680
681 ExReleaseResourceLite(&pdode->child_lock);
682
683 Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER);
684
685 return STATUS_SUCCESS;
686 }
687
688 _Function_class_(IO_COMPLETION_ROUTINE)
689 #ifdef __REACTOS__
690 static NTSTATUS NTAPI vol_ioctl_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
691 #else
692 static NTSTATUS vol_ioctl_completion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID conptr) {
693 #endif
694 KEVENT* event = conptr;
695
696 UNUSED(DeviceObject);
697 UNUSED(Irp);
698
699 KeSetEvent(event, 0, FALSE);
700
701 return STATUS_MORE_PROCESSING_REQUIRED;
702 }
703
704 static NTSTATUS vol_ioctl_passthrough(volume_device_extension* vde, PIRP Irp) {
705 NTSTATUS Status;
706 volume_child* vc;
707 PIRP Irp2;
708 PIO_STACK_LOCATION IrpSp, IrpSp2;
709 KEVENT Event;
710 pdo_device_extension* pdode = vde->pdode;
711
712 TRACE("(%p, %p)\n", vde, Irp);
713
714 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
715
716 if (IsListEmpty(&pdode->children)) {
717 ExReleaseResourceLite(&pdode->child_lock);
718 return STATUS_INVALID_DEVICE_REQUEST;
719 }
720
721 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry);
722
723 if (vc->list_entry.Flink != &pdode->children) { // more than one device
724 ExReleaseResourceLite(&pdode->child_lock);
725 return STATUS_INVALID_DEVICE_REQUEST;
726 }
727
728 Irp2 = IoAllocateIrp(vc->devobj->StackSize, FALSE);
729
730 if (!Irp2) {
731 ERR("IoAllocateIrp failed\n");
732 ExReleaseResourceLite(&pdode->child_lock);
733 return STATUS_INSUFFICIENT_RESOURCES;
734 }
735
736 IrpSp = IoGetCurrentIrpStackLocation(Irp);
737 IrpSp2 = IoGetNextIrpStackLocation(Irp2);
738
739 IrpSp2->MajorFunction = IrpSp->MajorFunction;
740 IrpSp2->MinorFunction = IrpSp->MinorFunction;
741
742 IrpSp2->Parameters.DeviceIoControl.OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
743 IrpSp2->Parameters.DeviceIoControl.InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
744 IrpSp2->Parameters.DeviceIoControl.IoControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
745 IrpSp2->Parameters.DeviceIoControl.Type3InputBuffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
746
747 Irp2->AssociatedIrp.SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
748 Irp2->MdlAddress = Irp->MdlAddress;
749 Irp2->UserBuffer = Irp->UserBuffer;
750 Irp2->Flags = Irp->Flags;
751
752 KeInitializeEvent(&Event, NotificationEvent, FALSE);
753
754 IoSetCompletionRoutine(Irp2, vol_ioctl_completion, &Event, TRUE, TRUE, TRUE);
755
756 Status = IoCallDriver(vc->devobj, Irp2);
757
758 if (Status == STATUS_PENDING) {
759 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
760 Status = Irp2->IoStatus.Status;
761 }
762
763 Irp->IoStatus.Status = Irp2->IoStatus.Status;
764 Irp->IoStatus.Information = Irp2->IoStatus.Information;
765
766 ExReleaseResourceLite(&pdode->child_lock);
767
768 return Status;
769 }
770
771 NTSTATUS vol_device_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
772 volume_device_extension* vde = DeviceObject->DeviceExtension;
773 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
774
775 TRACE("(%p, %p)\n", DeviceObject, Irp);
776
777 Irp->IoStatus.Information = 0;
778
779 switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
780 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:
781 return vol_query_device_name(vde, Irp);
782
783 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:
784 return vol_query_unique_id(vde, Irp);
785
786 case IOCTL_STORAGE_GET_DEVICE_NUMBER:
787 return vol_get_device_number(vde, Irp);
788
789 case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:
790 TRACE("unhandled control code IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME\n");
791 break;
792
793 case IOCTL_MOUNTDEV_QUERY_STABLE_GUID:
794 TRACE("unhandled control code IOCTL_MOUNTDEV_QUERY_STABLE_GUID\n");
795 break;
796
797 case IOCTL_MOUNTDEV_LINK_CREATED:
798 TRACE("unhandled control code IOCTL_MOUNTDEV_LINK_CREATED\n");
799 break;
800
801 case IOCTL_VOLUME_GET_GPT_ATTRIBUTES:
802 return vol_get_gpt_attributes(Irp);
803
804 case IOCTL_VOLUME_IS_DYNAMIC:
805 return vol_is_dynamic(Irp);
806
807 case IOCTL_VOLUME_ONLINE:
808 TRACE("unhandled control code IOCTL_VOLUME_ONLINE\n");
809 break;
810
811 case IOCTL_VOLUME_POST_ONLINE:
812 TRACE("unhandled control code IOCTL_VOLUME_POST_ONLINE\n");
813 break;
814
815 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
816 return vol_get_drive_geometry(DeviceObject, Irp);
817
818 case IOCTL_DISK_IS_WRITABLE:
819 return vol_is_writable(vde);
820
821 case IOCTL_DISK_GET_LENGTH_INFO:
822 return vol_get_length(vde, Irp);
823
824 case IOCTL_STORAGE_CHECK_VERIFY:
825 case IOCTL_DISK_CHECK_VERIFY:
826 return vol_check_verify(vde);
827
828 case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
829 return vol_get_disk_extents(vde, Irp);
830
831 default: // pass ioctl through if only one child device
832 return vol_ioctl_passthrough(vde, Irp);
833 }
834
835 return STATUS_INVALID_DEVICE_REQUEST;
836 }
837
838 NTSTATUS vol_shutdown(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
839 TRACE("(%p, %p)\n", DeviceObject, Irp);
840
841 return STATUS_INVALID_DEVICE_REQUEST;
842 }
843
844 NTSTATUS vol_query_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
845 TRACE("(%p, %p)\n", DeviceObject, Irp);
846
847 return STATUS_INVALID_DEVICE_REQUEST;
848 }
849
850 NTSTATUS vol_set_security(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
851 TRACE("(%p, %p)\n", DeviceObject, Irp);
852
853 return STATUS_INVALID_DEVICE_REQUEST;
854 }
855
856 NTSTATUS vol_power(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
857 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
858 NTSTATUS Status;
859
860 TRACE("(%p, %p)\n", DeviceObject, Irp);
861
862 if (IrpSp->MinorFunction == IRP_MN_SET_POWER || IrpSp->MinorFunction == IRP_MN_QUERY_POWER)
863 Irp->IoStatus.Status = STATUS_SUCCESS;
864
865 Status = Irp->IoStatus.Status;
866 PoStartNextPowerIrp(Irp);
867
868 return Status;
869 }
870
871 NTSTATUS mountmgr_add_drive_letter(PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath) {
872 NTSTATUS Status;
873 ULONG mmdltsize;
874 MOUNTMGR_DRIVE_LETTER_TARGET* mmdlt;
875 MOUNTMGR_DRIVE_LETTER_INFORMATION mmdli;
876
877 mmdltsize = (ULONG)offsetof(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName[0]) + devpath->Length;
878
879 mmdlt = ExAllocatePoolWithTag(NonPagedPool, mmdltsize, ALLOC_TAG);
880 if (!mmdlt) {
881 ERR("out of memory\n");
882 return STATUS_INSUFFICIENT_RESOURCES;
883 }
884
885 mmdlt->DeviceNameLength = devpath->Length;
886 RtlCopyMemory(&mmdlt->DeviceName, devpath->Buffer, devpath->Length);
887 TRACE("mmdlt = %.*S\n", mmdlt->DeviceNameLength / sizeof(WCHAR), mmdlt->DeviceName);
888
889 Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER, mmdlt, mmdltsize, &mmdli, sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION), FALSE, NULL);
890
891 if (!NT_SUCCESS(Status))
892 ERR("IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER returned %08x\n", Status);
893 else
894 TRACE("DriveLetterWasAssigned = %u, CurrentDriveLetter = %c\n", mmdli.DriveLetterWasAssigned, mmdli.CurrentDriveLetter);
895
896 ExFreePool(mmdlt);
897
898 return Status;
899 }
900
901 _Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE)
902 #ifdef __REACTOS__
903 NTSTATUS NTAPI pnp_removal(PVOID NotificationStructure, PVOID Context) {
904 #else
905 NTSTATUS pnp_removal(PVOID NotificationStructure, PVOID Context) {
906 #endif
907 TARGET_DEVICE_REMOVAL_NOTIFICATION* tdrn = (TARGET_DEVICE_REMOVAL_NOTIFICATION*)NotificationStructure;
908 pdo_device_extension* pdode = (pdo_device_extension*)Context;
909
910 if (RtlCompareMemory(&tdrn->Event, &GUID_TARGET_DEVICE_QUERY_REMOVE, sizeof(GUID)) == sizeof(GUID)) {
911 TRACE("GUID_TARGET_DEVICE_QUERY_REMOVE\n");
912
913 if (pdode->vde && pdode->vde->mounted_device)
914 return pnp_query_remove_device(pdode->vde->mounted_device, NULL);
915 }
916
917 return STATUS_SUCCESS;
918 }
919
920 static BOOL allow_degraded_mount(BTRFS_UUID* uuid) {
921 HANDLE h;
922 NTSTATUS Status;
923 OBJECT_ATTRIBUTES oa;
924 UNICODE_STRING path, adus;
925 UINT32 degraded = mount_allow_degraded;
926 ULONG i, j, kvfilen, retlen;
927 KEY_VALUE_FULL_INFORMATION* kvfi;
928
929 path.Length = path.MaximumLength = registry_path.Length + (37 * sizeof(WCHAR));
930 path.Buffer = ExAllocatePoolWithTag(PagedPool, path.Length, ALLOC_TAG);
931
932 if (!path.Buffer) {
933 ERR("out of memory\n");
934 return FALSE;
935 }
936
937 RtlCopyMemory(path.Buffer, registry_path.Buffer, registry_path.Length);
938 i = registry_path.Length / sizeof(WCHAR);
939
940 path.Buffer[i] = '\\';
941 i++;
942
943 for (j = 0; j < 16; j++) {
944 path.Buffer[i] = hex_digit((uuid->uuid[j] & 0xF0) >> 4);
945 path.Buffer[i+1] = hex_digit(uuid->uuid[j] & 0xF);
946
947 i += 2;
948
949 if (j == 3 || j == 5 || j == 7 || j == 9) {
950 path.Buffer[i] = '-';
951 i++;
952 }
953 }
954
955 InitializeObjectAttributes(&oa, &path, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
956
957 kvfilen = (ULONG)offsetof(KEY_VALUE_FULL_INFORMATION, Name[0]) + (255 * sizeof(WCHAR));
958 kvfi = ExAllocatePoolWithTag(PagedPool, kvfilen, ALLOC_TAG);
959 if (!kvfi) {
960 ERR("out of memory\n");
961 ExFreePool(path.Buffer);
962 return FALSE;
963 }
964
965 Status = ZwOpenKey(&h, KEY_QUERY_VALUE, &oa);
966 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
967 goto end;
968 else if (!NT_SUCCESS(Status)) {
969 ERR("ZwOpenKey returned %08x\n", Status);
970 goto end;
971 }
972
973 adus.Buffer = L"AllowDegraded";
974 adus.Length = adus.MaximumLength = (USHORT)(wcslen(adus.Buffer) * sizeof(WCHAR));
975
976 if (NT_SUCCESS(ZwQueryValueKey(h, &adus, KeyValueFullInformation, kvfi, kvfilen, &retlen))) {
977 if (kvfi->Type == REG_DWORD && kvfi->DataLength >= sizeof(UINT32)) {
978 UINT32* val = (UINT32*)((UINT8*)kvfi + kvfi->DataOffset);
979
980 degraded = *val;
981 }
982 }
983
984 ZwClose(h);
985
986 ExFreePool(kvfi);
987
988 end:
989 ExFreePool(path.Buffer);
990
991 return degraded;
992 }
993
994 void add_volume_device(superblock* sb, PDEVICE_OBJECT mountmgr, PUNICODE_STRING devpath, UINT64 length, ULONG disk_num, ULONG part_num) {
995 NTSTATUS Status;
996 LIST_ENTRY* le;
997 PDEVICE_OBJECT DeviceObject;
998 volume_child* vc;
999 PFILE_OBJECT FileObject;
1000 UNICODE_STRING devpath2;
1001 BOOL inserted = FALSE, new_pdo = FALSE;
1002 pdo_device_extension* pdode = NULL;
1003 PDEVICE_OBJECT pdo = NULL;
1004
1005 if (devpath->Length == 0)
1006 return;
1007
1008 ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE);
1009
1010 le = pdo_list.Flink;
1011 while (le != &pdo_list) {
1012 pdo_device_extension* pdode2 = CONTAINING_RECORD(le, pdo_device_extension, list_entry);
1013
1014 if (RtlCompareMemory(&pdode2->uuid, &sb->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
1015 pdode = pdode2;
1016 break;
1017 }
1018
1019 le = le->Flink;
1020 }
1021
1022 Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject);
1023 if (!NT_SUCCESS(Status)) {
1024 ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
1025 ExReleaseResourceLite(&pdo_list_lock);
1026 return;
1027 }
1028
1029 if (!pdode) {
1030 if (no_pnp) {
1031 Status = IoReportDetectedDevice(drvobj, InterfaceTypeUndefined, 0xFFFFFFFF, 0xFFFFFFFF, NULL, NULL, 0, &pdo);
1032
1033 if (!NT_SUCCESS(Status)) {
1034 ERR("IoReportDetectedDevice returned %08x\n", Status);
1035 ExReleaseResourceLite(&pdo_list_lock);
1036 return;
1037 }
1038
1039 pdode = ExAllocatePoolWithTag(NonPagedPool, sizeof(pdo_device_extension), ALLOC_TAG);
1040
1041 if (!pdode) {
1042 ERR("out of memory\n");
1043 ExReleaseResourceLite(&pdo_list_lock);
1044 return;
1045 }
1046 } else {
1047 Status = IoCreateDevice(drvobj, sizeof(pdo_device_extension), NULL, FILE_DEVICE_DISK,
1048 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &pdo);
1049 if (!NT_SUCCESS(Status)) {
1050 ERR("IoCreateDevice returned %08x\n", Status);
1051 ExReleaseResourceLite(&pdo_list_lock);
1052 goto fail;
1053 }
1054
1055 pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
1056
1057 pdode = pdo->DeviceExtension;
1058 }
1059
1060 RtlZeroMemory(pdode, sizeof(pdo_device_extension));
1061
1062 pdode->type = VCB_TYPE_PDO;
1063 pdode->pdo = pdo;
1064 pdode->uuid = sb->uuid;
1065
1066 ExInitializeResourceLite(&pdode->child_lock);
1067 InitializeListHead(&pdode->children);
1068 pdode->num_children = sb->num_devices;
1069 pdode->children_loaded = 0;
1070
1071 pdo->Flags &= ~DO_DEVICE_INITIALIZING;
1072 pdo->SectorSize = (USHORT)sb->sector_size;
1073
1074 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE);
1075
1076 new_pdo = TRUE;
1077 } else {
1078 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE);
1079 ExConvertExclusiveToSharedLite(&pdo_list_lock);
1080
1081 le = pdode->children.Flink;
1082 while (le != &pdode->children) {
1083 volume_child* vc2 = CONTAINING_RECORD(le, volume_child, list_entry);
1084
1085 if (RtlCompareMemory(&vc2->uuid, &sb->dev_item.device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
1086 // duplicate, ignore
1087 ExReleaseResourceLite(&pdode->child_lock);
1088 ExReleaseResourceLite(&pdo_list_lock);
1089 goto fail;
1090 }
1091
1092 le = le->Flink;
1093 }
1094 }
1095
1096 vc = ExAllocatePoolWithTag(PagedPool, sizeof(volume_child), ALLOC_TAG);
1097 if (!vc) {
1098 ERR("out of memory\n");
1099
1100 ExReleaseResourceLite(&pdode->child_lock);
1101 ExReleaseResourceLite(&pdo_list_lock);
1102
1103 goto fail;
1104 }
1105
1106 vc->uuid = sb->dev_item.device_uuid;
1107 vc->devid = sb->dev_item.dev_id;
1108 vc->generation = sb->generation;
1109 vc->notification_entry = NULL;
1110
1111 Status = IoRegisterPlugPlayNotification(EventCategoryTargetDeviceChange, 0, FileObject,
1112 drvobj, pnp_removal, pdode, &vc->notification_entry);
1113 if (!NT_SUCCESS(Status))
1114 WARN("IoRegisterPlugPlayNotification returned %08x\n", Status);
1115
1116 vc->devobj = DeviceObject;
1117 vc->fileobj = FileObject;
1118
1119 devpath2 = *devpath;
1120
1121 // The PNP path sometimes begins \\?\ and sometimes \??\. We need to remove this prefix
1122 // so we can compare properly if the device is removed.
1123 if (devpath->Length > 4 * sizeof(WCHAR) && devpath->Buffer[0] == '\\' && (devpath->Buffer[1] == '\\' || devpath->Buffer[1] == '?') &&
1124 devpath->Buffer[2] == '?' && devpath->Buffer[3] == '\\') {
1125 devpath2.Buffer = &devpath2.Buffer[3];
1126 devpath2.Length -= 3 * sizeof(WCHAR);
1127 devpath2.MaximumLength -= 3 * sizeof(WCHAR);
1128 }
1129
1130 vc->pnp_name.Length = vc->pnp_name.MaximumLength = devpath2.Length;
1131 vc->pnp_name.Buffer = ExAllocatePoolWithTag(PagedPool, devpath2.Length, ALLOC_TAG);
1132
1133 if (vc->pnp_name.Buffer)
1134 RtlCopyMemory(vc->pnp_name.Buffer, devpath2.Buffer, devpath2.Length);
1135 else {
1136 ERR("out of memory\n");
1137 vc->pnp_name.Length = vc->pnp_name.MaximumLength = 0;
1138 }
1139
1140 vc->size = length;
1141 vc->seeding = sb->flags & BTRFS_SUPERBLOCK_FLAGS_SEEDING ? TRUE : FALSE;
1142 vc->disk_num = disk_num;
1143 vc->part_num = part_num;
1144 vc->had_drive_letter = FALSE;
1145
1146 le = pdode->children.Flink;
1147 while (le != &pdode->children) {
1148 volume_child* vc2 = CONTAINING_RECORD(le, volume_child, list_entry);
1149
1150 if (vc2->generation < vc->generation) {
1151 if (le == pdode->children.Flink)
1152 pdode->num_children = sb->num_devices;
1153
1154 InsertHeadList(vc2->list_entry.Blink, &vc->list_entry);
1155 inserted = TRUE;
1156 break;
1157 }
1158
1159 le = le->Flink;
1160 }
1161
1162 if (!inserted)
1163 InsertTailList(&pdode->children, &vc->list_entry);
1164
1165 pdode->children_loaded++;
1166
1167 if (pdode->vde && pdode->vde->mounted_device) {
1168 device_extension* Vcb = pdode->vde->mounted_device->DeviceExtension;
1169
1170 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
1171
1172 le = Vcb->devices.Flink;
1173 while (le != &Vcb->devices) {
1174 device* dev = CONTAINING_RECORD(le, device, list_entry);
1175
1176 if (!dev->devobj && RtlCompareMemory(&dev->devitem.device_uuid, &sb->dev_item.device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
1177 dev->devobj = DeviceObject;
1178 dev->disk_num = disk_num;
1179 dev->part_num = part_num;
1180 init_device(Vcb, dev, FALSE);
1181 break;
1182 }
1183
1184 le = le->Flink;
1185 }
1186
1187 ExReleaseResourceLite(&Vcb->tree_lock);
1188 }
1189
1190 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
1191 pdode->removable = TRUE;
1192
1193 if (pdode->vde && pdode->vde->device)
1194 pdode->vde->device->Characteristics |= FILE_REMOVABLE_MEDIA;
1195 }
1196
1197 if (pdode->num_children == pdode->children_loaded || (pdode->children_loaded == 1 && allow_degraded_mount(&sb->uuid))) {
1198 if (pdode->num_children == 1) {
1199 Status = remove_drive_letter(mountmgr, devpath);
1200 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND)
1201 WARN("remove_drive_letter returned %08x\n", Status);
1202
1203 vc->had_drive_letter = NT_SUCCESS(Status);
1204 } else {
1205 le = pdode->children.Flink;
1206
1207 while (le != &pdode->children) {
1208 UNICODE_STRING name;
1209
1210 vc = CONTAINING_RECORD(le, volume_child, list_entry);
1211
1212 name.Length = name.MaximumLength = vc->pnp_name.Length + (3 * sizeof(WCHAR));
1213 name.Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG);
1214
1215 if (!name.Buffer) {
1216 ERR("out of memory\n");
1217
1218 ExReleaseResourceLite(&pdode->child_lock);
1219 ExReleaseResourceLite(&pdo_list_lock);
1220
1221 goto fail;
1222 }
1223
1224 RtlCopyMemory(name.Buffer, L"\\??", 3 * sizeof(WCHAR));
1225 RtlCopyMemory(&name.Buffer[3], vc->pnp_name.Buffer, vc->pnp_name.Length);
1226
1227 Status = remove_drive_letter(mountmgr, &name);
1228
1229 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND)
1230 WARN("remove_drive_letter returned %08x\n", Status);
1231
1232 ExFreePool(name.Buffer);
1233
1234 vc->had_drive_letter = NT_SUCCESS(Status);
1235
1236 le = le->Flink;
1237 }
1238 }
1239
1240 if ((!new_pdo || !no_pnp) && pdode->vde) {
1241 Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, TRUE);
1242 if (!NT_SUCCESS(Status))
1243 WARN("IoSetDeviceInterfaceState returned %08x\n", Status);
1244 }
1245 }
1246
1247 ExReleaseResourceLite(&pdode->child_lock);
1248
1249 if (new_pdo) {
1250 control_device_extension* cde = master_devobj->DeviceExtension;
1251
1252 InsertTailList(&pdo_list, &pdode->list_entry);
1253
1254 if (!no_pnp)
1255 IoInvalidateDeviceRelations(cde->buspdo, BusRelations);
1256 }
1257
1258 ExReleaseResourceLite(&pdo_list_lock);
1259
1260 if (new_pdo && no_pnp)
1261 AddDevice(drvobj, pdo);
1262
1263 return;
1264
1265 fail:
1266 ObDereferenceObject(FileObject);
1267 }