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 #ifdef _DEBUG 19 #define DEBUG 20 #endif 21 22 #include "btrfs_drv.h" 23 #ifndef __REACTOS__ 24 #ifndef _MSC_VER 25 #include <cpuid.h> 26 #else 27 #include <intrin.h> 28 #endif 29 #endif 30 #include <ntddscsi.h> 31 #include "btrfs.h" 32 #include <ata.h> 33 34 #ifndef _MSC_VER 35 #include <initguid.h> 36 #include <ntddstor.h> 37 #undef INITGUID 38 #endif 39 40 #include <ntdddisk.h> 41 #include <ntddvol.h> 42 43 #ifdef _MSC_VER 44 #include <initguid.h> 45 #include <ntddstor.h> 46 #undef INITGUID 47 #endif 48 49 #define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS | \ 50 BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO | BTRFS_INCOMPAT_FLAGS_BIG_METADATA | BTRFS_INCOMPAT_FLAGS_RAID56 | \ 51 BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES | \ 52 BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD) 53 #define COMPAT_RO_SUPPORTED (BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE | BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID) 54 55 static const WCHAR device_name[] = {'\\','B','t','r','f','s',0}; 56 static const WCHAR dosdevice_name[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\','B','t','r','f','s',0}; 57 58 DEFINE_GUID(BtrfsBusInterface, 0x4d414874, 0x6865, 0x6761, 0x6d, 0x65, 0x83, 0x69, 0x17, 0x9a, 0x7d, 0x1d); 59 60 PDRIVER_OBJECT drvobj; 61 PDEVICE_OBJECT master_devobj; 62 #ifndef __REACTOS__ 63 BOOL have_sse42 = FALSE, have_sse2 = FALSE; 64 #endif 65 UINT64 num_reads = 0; 66 LIST_ENTRY uid_map_list, gid_map_list; 67 LIST_ENTRY VcbList; 68 ERESOURCE global_loading_lock; 69 UINT32 debug_log_level = 0; 70 UINT32 mount_compress = 0; 71 UINT32 mount_compress_force = 0; 72 UINT32 mount_compress_type = 0; 73 UINT32 mount_zlib_level = 3; 74 UINT32 mount_zstd_level = 3; 75 UINT32 mount_flush_interval = 30; 76 UINT32 mount_max_inline = 2048; 77 UINT32 mount_skip_balance = 0; 78 UINT32 mount_no_barrier = 0; 79 UINT32 mount_no_trim = 0; 80 UINT32 mount_clear_cache = 0; 81 UINT32 mount_allow_degraded = 0; 82 UINT32 mount_readonly = 0; 83 UINT32 no_pnp = 0; 84 BOOL log_started = FALSE; 85 UNICODE_STRING log_device, log_file, registry_path; 86 tPsUpdateDiskCounters fPsUpdateDiskCounters; 87 tCcCopyReadEx fCcCopyReadEx; 88 tCcCopyWriteEx fCcCopyWriteEx; 89 tCcSetAdditionalCacheAttributesEx fCcSetAdditionalCacheAttributesEx; 90 tFsRtlUpdateDiskCounters fFsRtlUpdateDiskCounters; 91 BOOL diskacc = FALSE; 92 void *notification_entry = NULL, *notification_entry2 = NULL, *notification_entry3 = NULL; 93 ERESOURCE pdo_list_lock, mapping_lock; 94 LIST_ENTRY pdo_list; 95 BOOL finished_probing = FALSE; 96 HANDLE degraded_wait_handle = NULL, mountmgr_thread_handle = NULL; 97 BOOL degraded_wait = TRUE; 98 KEVENT mountmgr_thread_event; 99 BOOL shutting_down = FALSE; 100 101 #ifdef _DEBUG 102 PFILE_OBJECT comfo = NULL; 103 PDEVICE_OBJECT comdo = NULL; 104 HANDLE log_handle = NULL; 105 ERESOURCE log_lock; 106 HANDLE serial_thread_handle = NULL; 107 108 static void init_serial(BOOL first_time); 109 #endif 110 111 static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp); 112 113 typedef struct { 114 KEVENT Event; 115 IO_STATUS_BLOCK iosb; 116 } read_context; 117 118 #ifdef _DEBUG 119 _Function_class_(IO_COMPLETION_ROUTINE) 120 static NTSTATUS dbg_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) { 121 read_context* context = conptr; 122 123 UNUSED(DeviceObject); 124 125 context->iosb = Irp->IoStatus; 126 KeSetEvent(&context->Event, 0, FALSE); 127 128 return STATUS_MORE_PROCESSING_REQUIRED; 129 } 130 131 #ifdef DEBUG_LONG_MESSAGES 132 void _debug_message(_In_ const char* func, _In_ const char* file, _In_ unsigned int line, _In_ char* s, ...) { 133 #else 134 void _debug_message(_In_ const char* func, _In_ char* s, ...) { 135 #endif 136 LARGE_INTEGER offset; 137 PIO_STACK_LOCATION IrpSp; 138 NTSTATUS Status; 139 PIRP Irp; 140 va_list ap; 141 char *buf2, *buf; 142 read_context context; 143 UINT32 length; 144 145 buf2 = ExAllocatePoolWithTag(NonPagedPool, 1024, ALLOC_TAG); 146 147 if (!buf2) { 148 DbgPrint("Couldn't allocate buffer in debug_message\n"); 149 return; 150 } 151 152 #ifdef DEBUG_LONG_MESSAGES 153 sprintf(buf2, "%p:%s:%s:%u:", PsGetCurrentThread(), func, file, line); 154 #else 155 sprintf(buf2, "%p:%s:", PsGetCurrentThread(), func); 156 #endif 157 buf = &buf2[strlen(buf2)]; 158 159 va_start(ap, s); 160 vsprintf(buf, s, ap); 161 162 ExAcquireResourceSharedLite(&log_lock, TRUE); 163 164 if (!log_started || (log_device.Length == 0 && log_file.Length == 0)) { 165 DbgPrint(buf2); 166 } else if (log_device.Length > 0) { 167 if (!comdo) { 168 DbgPrint("comdo is NULL :-(\n"); 169 DbgPrint(buf2); 170 goto exit2; 171 } 172 173 length = (UINT32)strlen(buf2); 174 175 offset.u.LowPart = 0; 176 offset.u.HighPart = 0; 177 178 RtlZeroMemory(&context, sizeof(read_context)); 179 180 KeInitializeEvent(&context.Event, NotificationEvent, FALSE); 181 182 Irp = IoAllocateIrp(comdo->StackSize, FALSE); 183 184 if (!Irp) { 185 DbgPrint("IoAllocateIrp failed\n"); 186 goto exit2; 187 } 188 189 IrpSp = IoGetNextIrpStackLocation(Irp); 190 IrpSp->MajorFunction = IRP_MJ_WRITE; 191 192 if (comdo->Flags & DO_BUFFERED_IO) { 193 Irp->AssociatedIrp.SystemBuffer = buf2; 194 195 Irp->Flags = IRP_BUFFERED_IO; 196 } else if (comdo->Flags & DO_DIRECT_IO) { 197 Irp->MdlAddress = IoAllocateMdl(buf2, length, FALSE, FALSE, NULL); 198 if (!Irp->MdlAddress) { 199 DbgPrint("IoAllocateMdl failed\n"); 200 goto exit; 201 } 202 203 MmBuildMdlForNonPagedPool(Irp->MdlAddress); 204 } else { 205 Irp->UserBuffer = buf2; 206 } 207 208 IrpSp->Parameters.Write.Length = length; 209 IrpSp->Parameters.Write.ByteOffset = offset; 210 211 Irp->UserIosb = &context.iosb; 212 213 Irp->UserEvent = &context.Event; 214 215 IoSetCompletionRoutine(Irp, dbg_completion, &context, TRUE, TRUE, TRUE); 216 217 Status = IoCallDriver(comdo, Irp); 218 219 if (Status == STATUS_PENDING) { 220 KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL); 221 Status = context.iosb.Status; 222 } 223 224 if (comdo->Flags & DO_DIRECT_IO) 225 IoFreeMdl(Irp->MdlAddress); 226 227 if (!NT_SUCCESS(Status)) { 228 DbgPrint("failed to write to COM1 - error %08x\n", Status); 229 goto exit; 230 } 231 232 exit: 233 IoFreeIrp(Irp); 234 } else if (log_handle != NULL) { 235 IO_STATUS_BLOCK iosb; 236 237 length = (UINT32)strlen(buf2); 238 239 Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, buf2, length, NULL, NULL); 240 241 if (!NT_SUCCESS(Status)) { 242 DbgPrint("failed to write to file - error %08x\n", Status); 243 } 244 } 245 246 exit2: 247 ExReleaseResourceLite(&log_lock); 248 249 va_end(ap); 250 251 if (buf2) 252 ExFreePool(buf2); 253 } 254 #endif 255 256 BOOL is_top_level(_In_ PIRP Irp) { 257 if (!IoGetTopLevelIrp()) { 258 IoSetTopLevelIrp(Irp); 259 return TRUE; 260 } 261 262 return FALSE; 263 } 264 265 _Function_class_(DRIVER_UNLOAD) 266 #ifdef __REACTOS__ 267 static void NTAPI DriverUnload(_In_ PDRIVER_OBJECT DriverObject) { 268 #else 269 static void DriverUnload(_In_ PDRIVER_OBJECT DriverObject) { 270 #endif 271 UNICODE_STRING dosdevice_nameW; 272 273 TRACE("(%p)\n"); 274 275 free_cache(); 276 277 IoUnregisterFileSystem(DriverObject->DeviceObject); 278 279 if (notification_entry2) 280 #ifdef __REACTOS__ 281 IoUnregisterPlugPlayNotification(notification_entry2); 282 #else 283 IoUnregisterPlugPlayNotificationEx(notification_entry2); 284 #endif 285 286 if (notification_entry3) 287 #ifdef __REACTOS__ 288 IoUnregisterPlugPlayNotification(notification_entry3); 289 #else 290 IoUnregisterPlugPlayNotificationEx(notification_entry3); 291 #endif 292 293 if (notification_entry) 294 #ifdef __REACTOS__ 295 IoUnregisterPlugPlayNotification(notification_entry); 296 #else 297 IoUnregisterPlugPlayNotificationEx(notification_entry); 298 #endif 299 300 dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name; 301 dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) - sizeof(WCHAR); 302 303 IoDeleteSymbolicLink(&dosdevice_nameW); 304 IoDeleteDevice(DriverObject->DeviceObject); 305 306 while (!IsListEmpty(&uid_map_list)) { 307 LIST_ENTRY* le = RemoveHeadList(&uid_map_list); 308 uid_map* um = CONTAINING_RECORD(le, uid_map, listentry); 309 310 ExFreePool(um->sid); 311 312 ExFreePool(um); 313 } 314 315 while (!IsListEmpty(&gid_map_list)) { 316 gid_map* gm = CONTAINING_RECORD(RemoveHeadList(&gid_map_list), gid_map, listentry); 317 318 ExFreePool(gm->sid); 319 ExFreePool(gm); 320 } 321 322 // FIXME - free volumes and their devpaths 323 324 #ifdef _DEBUG 325 if (comfo) 326 ObDereferenceObject(comfo); 327 328 if (log_handle) 329 ZwClose(log_handle); 330 #endif 331 332 ExDeleteResourceLite(&global_loading_lock); 333 ExDeleteResourceLite(&pdo_list_lock); 334 335 if (log_device.Buffer) 336 ExFreePool(log_device.Buffer); 337 338 if (log_file.Buffer) 339 ExFreePool(log_file.Buffer); 340 341 if (registry_path.Buffer) 342 ExFreePool(registry_path.Buffer); 343 344 #ifdef _DEBUG 345 ExDeleteResourceLite(&log_lock); 346 #endif 347 ExDeleteResourceLite(&mapping_lock); 348 } 349 350 static BOOL get_last_inode(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _In_opt_ PIRP Irp) { 351 KEY searchkey; 352 traverse_ptr tp, prev_tp; 353 NTSTATUS Status; 354 355 // get last entry 356 searchkey.obj_id = 0xffffffffffffffff; 357 searchkey.obj_type = 0xff; 358 searchkey.offset = 0xffffffffffffffff; 359 360 Status = find_item(Vcb, r, &tp, &searchkey, FALSE, Irp); 361 if (!NT_SUCCESS(Status)) { 362 ERR("error - find_item returned %08x\n", Status); 363 return FALSE; 364 } 365 366 if (tp.item->key.obj_type == TYPE_INODE_ITEM || (tp.item->key.obj_type == TYPE_ROOT_ITEM && !(tp.item->key.obj_id & 0x8000000000000000))) { 367 r->lastinode = tp.item->key.obj_id; 368 TRACE("last inode for tree %llx is %llx\n", r->id, r->lastinode); 369 return TRUE; 370 } 371 372 while (find_prev_item(Vcb, &tp, &prev_tp, Irp)) { 373 tp = prev_tp; 374 375 TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset); 376 377 if (tp.item->key.obj_type == TYPE_INODE_ITEM || (tp.item->key.obj_type == TYPE_ROOT_ITEM && !(tp.item->key.obj_id & 0x8000000000000000))) { 378 r->lastinode = tp.item->key.obj_id; 379 TRACE("last inode for tree %llx is %llx\n", r->id, r->lastinode); 380 return TRUE; 381 } 382 } 383 384 r->lastinode = SUBVOL_ROOT_INODE; 385 386 WARN("no INODE_ITEMs in tree %llx\n", r->id); 387 388 return TRUE; 389 } 390 391 _Success_(return) 392 static BOOL extract_xattr(_In_reads_bytes_(size) void* item, _In_ USHORT size, _In_z_ char* name, _Out_ UINT8** data, _Out_ UINT16* datalen) { 393 DIR_ITEM* xa = (DIR_ITEM*)item; 394 USHORT xasize; 395 396 while (TRUE) { 397 if (size < sizeof(DIR_ITEM) || size < (sizeof(DIR_ITEM) - 1 + xa->m + xa->n)) { 398 WARN("DIR_ITEM is truncated\n"); 399 return FALSE; 400 } 401 402 if (xa->n == strlen(name) && RtlCompareMemory(name, xa->name, xa->n) == xa->n) { 403 TRACE("found xattr %s\n", name); 404 405 *datalen = xa->m; 406 407 if (xa->m > 0) { 408 *data = ExAllocatePoolWithTag(PagedPool, xa->m, ALLOC_TAG); 409 if (!*data) { 410 ERR("out of memory\n"); 411 return FALSE; 412 } 413 414 RtlCopyMemory(*data, &xa->name[xa->n], xa->m); 415 } else 416 *data = NULL; 417 418 return TRUE; 419 } 420 421 xasize = sizeof(DIR_ITEM) - 1 + xa->m + xa->n; 422 423 if (size > xasize) { 424 size -= xasize; 425 xa = (DIR_ITEM*)&xa->name[xa->m + xa->n]; 426 } else 427 break; 428 } 429 430 TRACE("xattr %s not found\n", name); 431 432 return FALSE; 433 } 434 435 _Success_(return) 436 BOOL get_xattr(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* subvol, _In_ UINT64 inode, _In_z_ char* name, _In_ UINT32 crc32, 437 _Out_ UINT8** data, _Out_ UINT16* datalen, _In_opt_ PIRP Irp) { 438 KEY searchkey; 439 traverse_ptr tp; 440 NTSTATUS Status; 441 442 TRACE("(%p, %llx, %llx, %s, %08x, %p, %p)\n", Vcb, subvol->id, inode, name, crc32, data, datalen); 443 444 searchkey.obj_id = inode; 445 searchkey.obj_type = TYPE_XATTR_ITEM; 446 searchkey.offset = crc32; 447 448 Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp); 449 if (!NT_SUCCESS(Status)) { 450 ERR("error - find_item returned %08x\n", Status); 451 return FALSE; 452 } 453 454 if (keycmp(tp.item->key, searchkey)) { 455 TRACE("could not find item (%llx,%x,%llx)\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset); 456 return FALSE; 457 } 458 459 if (tp.item->size < sizeof(DIR_ITEM)) { 460 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM)); 461 return FALSE; 462 } 463 464 return extract_xattr(tp.item->data, tp.item->size, name, data, datalen); 465 } 466 467 _Dispatch_type_(IRP_MJ_CLOSE) 468 _Function_class_(DRIVER_DISPATCH) 469 #ifdef __REACTOS__ 470 static NTSTATUS NTAPI drv_close(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 471 #else 472 static NTSTATUS drv_close(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 473 #endif 474 NTSTATUS Status; 475 PIO_STACK_LOCATION IrpSp; 476 device_extension* Vcb = DeviceObject->DeviceExtension; 477 BOOL top_level; 478 479 FsRtlEnterFileSystem(); 480 481 TRACE("close\n"); 482 483 top_level = is_top_level(Irp); 484 485 if (DeviceObject == master_devobj) { 486 TRACE("Closing file system\n"); 487 Status = STATUS_SUCCESS; 488 goto end; 489 } else if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 490 Status = vol_close(DeviceObject, Irp); 491 goto end; 492 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 493 Status = STATUS_INVALID_PARAMETER; 494 goto end; 495 } 496 497 IrpSp = IoGetCurrentIrpStackLocation(Irp); 498 499 // FIXME - unmount if called for volume 500 // FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting 501 502 Status = close_file(IrpSp->FileObject, Irp); 503 504 end: 505 Irp->IoStatus.Status = Status; 506 Irp->IoStatus.Information = 0; 507 508 IoCompleteRequest( Irp, IO_DISK_INCREMENT ); 509 510 if (top_level) 511 IoSetTopLevelIrp(NULL); 512 513 TRACE("returning %08x\n", Status); 514 515 FsRtlExitFileSystem(); 516 517 return Status; 518 } 519 520 _Dispatch_type_(IRP_MJ_FLUSH_BUFFERS) 521 _Function_class_(DRIVER_DISPATCH) 522 #ifdef __REACTOS__ 523 static NTSTATUS NTAPI drv_flush_buffers(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 524 #else 525 static NTSTATUS drv_flush_buffers(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 526 #endif 527 NTSTATUS Status; 528 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); 529 PFILE_OBJECT FileObject = IrpSp->FileObject; 530 fcb* fcb = FileObject->FsContext; 531 device_extension* Vcb = DeviceObject->DeviceExtension; 532 BOOL top_level; 533 534 FsRtlEnterFileSystem(); 535 536 TRACE("flush buffers\n"); 537 538 top_level = is_top_level(Irp); 539 540 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 541 Status = vol_flush_buffers(DeviceObject, Irp); 542 goto end; 543 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 544 Status = STATUS_INVALID_PARAMETER; 545 goto end; 546 } 547 548 if (!fcb) { 549 ERR("fcb was NULL\n"); 550 Status = STATUS_INVALID_PARAMETER; 551 goto end; 552 } 553 554 if (fcb == Vcb->volume_fcb) { 555 Status = STATUS_INVALID_PARAMETER; 556 goto end; 557 } 558 559 Irp->IoStatus.Information = 0; 560 561 fcb->Header.IsFastIoPossible = fast_io_possible(fcb); 562 563 Status = STATUS_SUCCESS; 564 Irp->IoStatus.Status = Status; 565 566 if (fcb->type != BTRFS_TYPE_DIRECTORY) { 567 CcFlushCache(&fcb->nonpaged->segment_object, NULL, 0, &Irp->IoStatus); 568 569 if (fcb->Header.PagingIoResource) { 570 ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE); 571 ExReleaseResourceLite(fcb->Header.PagingIoResource); 572 } 573 574 Status = Irp->IoStatus.Status; 575 } 576 577 end: 578 IoCompleteRequest(Irp, IO_NO_INCREMENT); 579 580 TRACE("returning %08x\n", Status); 581 582 if (top_level) 583 IoSetTopLevelIrp(NULL); 584 585 FsRtlExitFileSystem(); 586 587 return Status; 588 } 589 590 static void calculate_total_space(_In_ device_extension* Vcb, _Out_ UINT64* totalsize, _Out_ UINT64* freespace) { 591 UINT64 nfactor, dfactor, sectors_used; 592 593 if (Vcb->data_flags & BLOCK_FLAG_DUPLICATE || Vcb->data_flags & BLOCK_FLAG_RAID1 || Vcb->data_flags & BLOCK_FLAG_RAID10) { 594 nfactor = 1; 595 dfactor = 2; 596 } else if (Vcb->data_flags & BLOCK_FLAG_RAID5) { 597 nfactor = Vcb->superblock.num_devices - 1; 598 dfactor = Vcb->superblock.num_devices; 599 } else if (Vcb->data_flags & BLOCK_FLAG_RAID6) { 600 nfactor = Vcb->superblock.num_devices - 2; 601 dfactor = Vcb->superblock.num_devices; 602 } else { 603 nfactor = 1; 604 dfactor = 1; 605 } 606 607 sectors_used = Vcb->superblock.bytes_used / Vcb->superblock.sector_size; 608 609 *totalsize = (Vcb->superblock.total_bytes / Vcb->superblock.sector_size) * nfactor / dfactor; 610 *freespace = sectors_used > *totalsize ? 0 : (*totalsize - sectors_used); 611 } 612 613 #ifndef __REACTOS__ 614 // This function exists because we have to lie about our FS type in certain situations. 615 // MPR!MprGetConnection queries the FS type, and compares it to a whitelist. If it doesn't match, 616 // it will return ERROR_NO_NET_OR_BAD_PATH, which prevents UAC from working. 617 // The command mklink refuses to create hard links on anything other than NTFS, so we have to 618 // blacklist cmd.exe too. 619 620 static BOOL lie_about_fs_type() { 621 NTSTATUS Status; 622 PROCESS_BASIC_INFORMATION pbi; 623 PPEB peb; 624 LIST_ENTRY* le; 625 ULONG retlen; 626 #ifdef _AMD64_ 627 ULONG_PTR wow64info; 628 #endif 629 630 static const WCHAR mpr[] = L"MPR.DLL"; 631 static const WCHAR cmd[] = L"CMD.EXE"; 632 static const WCHAR fsutil[] = L"FSUTIL.EXE"; 633 UNICODE_STRING mprus, cmdus, fsutilus; 634 635 mprus.Buffer = (WCHAR*)mpr; 636 mprus.Length = mprus.MaximumLength = sizeof(mpr) - sizeof(WCHAR); 637 cmdus.Buffer = (WCHAR*)cmd; 638 cmdus.Length = cmdus.MaximumLength = sizeof(cmd) - sizeof(WCHAR); 639 fsutilus.Buffer = (WCHAR*)fsutil; 640 fsutilus.Length = fsutilus.MaximumLength = sizeof(fsutil) - sizeof(WCHAR); 641 642 if (!PsGetCurrentProcess()) 643 return FALSE; 644 645 #ifdef _AMD64_ 646 Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information, &wow64info, sizeof(wow64info), NULL); 647 648 if (NT_SUCCESS(Status) && wow64info != 0) 649 return TRUE; 650 #endif 651 652 Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &retlen); 653 654 if (!NT_SUCCESS(Status)) { 655 ERR("ZwQueryInformationProcess returned %08x\n", Status); 656 return FALSE; 657 } 658 659 if (!pbi.PebBaseAddress) 660 return FALSE; 661 662 peb = pbi.PebBaseAddress; 663 664 if (!peb->Ldr) 665 return FALSE; 666 667 le = peb->Ldr->InMemoryOrderModuleList.Flink; 668 while (le != &peb->Ldr->InMemoryOrderModuleList) { 669 LDR_DATA_TABLE_ENTRY* entry = CONTAINING_RECORD(le, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); 670 BOOL blacklist = FALSE; 671 672 if (entry->FullDllName.Length >= mprus.Length) { 673 UNICODE_STRING name; 674 675 name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - mprus.Length) / sizeof(WCHAR)]; 676 name.Length = name.MaximumLength = mprus.Length; 677 678 blacklist = FsRtlAreNamesEqual(&name, &mprus, TRUE, NULL); 679 } 680 681 if (!blacklist && entry->FullDllName.Length >= cmdus.Length) { 682 UNICODE_STRING name; 683 684 name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - cmdus.Length) / sizeof(WCHAR)]; 685 name.Length = name.MaximumLength = cmdus.Length; 686 687 blacklist = FsRtlAreNamesEqual(&name, &cmdus, TRUE, NULL); 688 } 689 690 if (!blacklist && entry->FullDllName.Length >= fsutilus.Length) { 691 UNICODE_STRING name; 692 693 name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - fsutilus.Length) / sizeof(WCHAR)]; 694 name.Length = name.MaximumLength = fsutilus.Length; 695 696 blacklist = FsRtlAreNamesEqual(&name, &fsutilus, TRUE, NULL); 697 } 698 699 if (blacklist) { 700 void** frames; 701 ULONG i, num_frames; 702 703 frames = ExAllocatePoolWithTag(PagedPool, 256 * sizeof(void*), ALLOC_TAG); 704 if (!frames) { 705 ERR("out of memory\n"); 706 return FALSE; 707 } 708 709 num_frames = RtlWalkFrameChain(frames, 256, 1); 710 711 for (i = 0; i < num_frames; i++) { 712 // entry->Reserved3[1] appears to be the image size 713 if (frames[i] >= entry->DllBase && (ULONG_PTR)frames[i] <= (ULONG_PTR)entry->DllBase + (ULONG_PTR)entry->Reserved3[1]) { 714 ExFreePool(frames); 715 return TRUE; 716 } 717 } 718 719 ExFreePool(frames); 720 } 721 722 le = le->Flink; 723 } 724 725 return FALSE; 726 } 727 #endif 728 729 _Dispatch_type_(IRP_MJ_QUERY_VOLUME_INFORMATION) 730 _Function_class_(DRIVER_DISPATCH) 731 #ifdef __REACTOS__ 732 static NTSTATUS NTAPI drv_query_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 733 #else 734 static NTSTATUS drv_query_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 735 #endif 736 PIO_STACK_LOCATION IrpSp; 737 NTSTATUS Status; 738 ULONG BytesCopied = 0; 739 device_extension* Vcb = DeviceObject->DeviceExtension; 740 BOOL top_level; 741 742 FsRtlEnterFileSystem(); 743 744 TRACE("query volume information\n"); 745 top_level = is_top_level(Irp); 746 747 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 748 Status = vol_query_volume_information(DeviceObject, Irp); 749 goto end; 750 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 751 Status = STATUS_INVALID_PARAMETER; 752 goto end; 753 } 754 755 IrpSp = IoGetCurrentIrpStackLocation(Irp); 756 757 Status = STATUS_NOT_IMPLEMENTED; 758 759 switch (IrpSp->Parameters.QueryVolume.FsInformationClass) { 760 case FileFsAttributeInformation: 761 { 762 FILE_FS_ATTRIBUTE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer; 763 BOOL overflow = FALSE; 764 #ifndef __REACTOS__ 765 static const WCHAR ntfs[] = L"NTFS"; 766 #endif 767 static const WCHAR btrfs[] = L"Btrfs"; 768 const WCHAR* fs_name; 769 ULONG fs_name_len, orig_fs_name_len; 770 771 #ifndef __REACTOS__ 772 if (Irp->RequestorMode == UserMode && lie_about_fs_type()) { 773 fs_name = ntfs; 774 orig_fs_name_len = fs_name_len = sizeof(ntfs) - sizeof(WCHAR); 775 } else { 776 fs_name = btrfs; 777 orig_fs_name_len = fs_name_len = sizeof(btrfs) - sizeof(WCHAR); 778 } 779 #else 780 fs_name = btrfs; 781 orig_fs_name_len = fs_name_len = sizeof(btrfs) - sizeof(WCHAR); 782 #endif 783 784 TRACE("FileFsAttributeInformation\n"); 785 786 if (IrpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR) + fs_name_len) { 787 if (IrpSp->Parameters.QueryVolume.Length > sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR)) 788 fs_name_len = IrpSp->Parameters.QueryVolume.Length - sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + sizeof(WCHAR); 789 else 790 fs_name_len = 0; 791 792 overflow = TRUE; 793 } 794 795 data->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_CASE_SENSITIVE_SEARCH | 796 FILE_UNICODE_ON_DISK | FILE_NAMED_STREAMS | FILE_SUPPORTS_HARD_LINKS | FILE_PERSISTENT_ACLS | 797 FILE_SUPPORTS_REPARSE_POINTS | FILE_SUPPORTS_SPARSE_FILES | FILE_SUPPORTS_OBJECT_IDS | 798 FILE_SUPPORTS_OPEN_BY_FILE_ID | FILE_SUPPORTS_EXTENDED_ATTRIBUTES | FILE_SUPPORTS_BLOCK_REFCOUNTING; 799 if (Vcb->readonly) 800 data->FileSystemAttributes |= FILE_READ_ONLY_VOLUME; 801 802 // should also be FILE_FILE_COMPRESSION when supported 803 data->MaximumComponentNameLength = 255; // FIXME - check 804 data->FileSystemNameLength = orig_fs_name_len; 805 RtlCopyMemory(data->FileSystemName, fs_name, fs_name_len); 806 807 BytesCopied = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) - sizeof(WCHAR) + fs_name_len; 808 Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS; 809 break; 810 } 811 812 case FileFsDeviceInformation: 813 { 814 FILE_FS_DEVICE_INFORMATION* ffdi = Irp->AssociatedIrp.SystemBuffer; 815 816 TRACE("FileFsDeviceInformation\n"); 817 818 ffdi->DeviceType = FILE_DEVICE_DISK; 819 820 ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); 821 ffdi->Characteristics = Vcb->Vpb->RealDevice->Characteristics; 822 ExReleaseResourceLite(&Vcb->tree_lock); 823 824 if (Vcb->readonly) 825 ffdi->Characteristics |= FILE_READ_ONLY_DEVICE; 826 else 827 ffdi->Characteristics &= ~FILE_READ_ONLY_DEVICE; 828 829 BytesCopied = sizeof(FILE_FS_DEVICE_INFORMATION); 830 Status = STATUS_SUCCESS; 831 832 break; 833 } 834 835 case FileFsFullSizeInformation: 836 { 837 FILE_FS_FULL_SIZE_INFORMATION* ffsi = Irp->AssociatedIrp.SystemBuffer; 838 839 TRACE("FileFsFullSizeInformation\n"); 840 841 calculate_total_space(Vcb, (UINT64*)&ffsi->TotalAllocationUnits.QuadPart, (UINT64*)&ffsi->ActualAvailableAllocationUnits.QuadPart); 842 ffsi->CallerAvailableAllocationUnits.QuadPart = ffsi->ActualAvailableAllocationUnits.QuadPart; 843 ffsi->SectorsPerAllocationUnit = 1; 844 ffsi->BytesPerSector = Vcb->superblock.sector_size; 845 846 BytesCopied = sizeof(FILE_FS_FULL_SIZE_INFORMATION); 847 Status = STATUS_SUCCESS; 848 849 break; 850 } 851 852 case FileFsObjectIdInformation: 853 { 854 FILE_FS_OBJECTID_INFORMATION* ffoi = Irp->AssociatedIrp.SystemBuffer; 855 856 TRACE("FileFsObjectIdInformation\n"); 857 858 RtlCopyMemory(ffoi->ObjectId, &Vcb->superblock.uuid.uuid[0], sizeof(UCHAR) * 16); 859 RtlZeroMemory(ffoi->ExtendedInfo, sizeof(ffoi->ExtendedInfo)); 860 861 BytesCopied = sizeof(FILE_FS_OBJECTID_INFORMATION); 862 Status = STATUS_SUCCESS; 863 864 break; 865 } 866 867 case FileFsSizeInformation: 868 { 869 FILE_FS_SIZE_INFORMATION* ffsi = Irp->AssociatedIrp.SystemBuffer; 870 871 TRACE("FileFsSizeInformation\n"); 872 873 calculate_total_space(Vcb, (UINT64*)&ffsi->TotalAllocationUnits.QuadPart, (UINT64*)&ffsi->AvailableAllocationUnits.QuadPart); 874 ffsi->SectorsPerAllocationUnit = 1; 875 ffsi->BytesPerSector = Vcb->superblock.sector_size; 876 877 BytesCopied = sizeof(FILE_FS_SIZE_INFORMATION); 878 Status = STATUS_SUCCESS; 879 880 break; 881 } 882 883 case FileFsVolumeInformation: 884 { 885 FILE_FS_VOLUME_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer; 886 FILE_FS_VOLUME_INFORMATION ffvi; 887 BOOL overflow = FALSE; 888 ULONG label_len, orig_label_len; 889 890 TRACE("FileFsVolumeInformation\n"); 891 TRACE("max length = %u\n", IrpSp->Parameters.QueryVolume.Length); 892 893 ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE); 894 895 Status = RtlUTF8ToUnicodeN(NULL, 0, &label_len, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label)); 896 if (!NT_SUCCESS(Status)) { 897 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status); 898 ExReleaseResourceLite(&Vcb->tree_lock); 899 break; 900 } 901 902 orig_label_len = label_len; 903 904 if (IrpSp->Parameters.QueryVolume.Length < sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR) + label_len) { 905 if (IrpSp->Parameters.QueryVolume.Length > sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR)) 906 label_len = IrpSp->Parameters.QueryVolume.Length - sizeof(FILE_FS_VOLUME_INFORMATION) + sizeof(WCHAR); 907 else 908 label_len = 0; 909 910 overflow = TRUE; 911 } 912 913 TRACE("label_len = %u\n", label_len); 914 915 ffvi.VolumeCreationTime.QuadPart = 0; // FIXME 916 ffvi.VolumeSerialNumber = Vcb->superblock.uuid.uuid[12] << 24 | Vcb->superblock.uuid.uuid[13] << 16 | Vcb->superblock.uuid.uuid[14] << 8 | Vcb->superblock.uuid.uuid[15]; 917 ffvi.VolumeLabelLength = orig_label_len; 918 ffvi.SupportsObjects = FALSE; 919 920 RtlCopyMemory(data, &ffvi, min(sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR), IrpSp->Parameters.QueryVolume.Length)); 921 922 if (label_len > 0) { 923 ULONG bytecount; 924 925 Status = RtlUTF8ToUnicodeN(&data->VolumeLabel[0], label_len, &bytecount, Vcb->superblock.label, (ULONG)strlen(Vcb->superblock.label)); 926 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) { 927 ERR("RtlUTF8ToUnicodeN returned %08x\n", Status); 928 ExReleaseResourceLite(&Vcb->tree_lock); 929 break; 930 } 931 932 TRACE("label = %.*S\n", label_len / sizeof(WCHAR), data->VolumeLabel); 933 } 934 935 ExReleaseResourceLite(&Vcb->tree_lock); 936 937 BytesCopied = sizeof(FILE_FS_VOLUME_INFORMATION) - sizeof(WCHAR) + label_len; 938 Status = overflow ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS; 939 break; 940 } 941 942 #ifndef __REACTOS__ 943 #ifdef _MSC_VER // not in mingw yet 944 case FileFsSectorSizeInformation: 945 { 946 FILE_FS_SECTOR_SIZE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer; 947 948 data->LogicalBytesPerSector = Vcb->superblock.sector_size; 949 data->PhysicalBytesPerSectorForAtomicity = Vcb->superblock.sector_size; 950 data->PhysicalBytesPerSectorForPerformance = Vcb->superblock.sector_size; 951 data->FileSystemEffectivePhysicalBytesPerSectorForAtomicity = Vcb->superblock.sector_size; 952 data->ByteOffsetForSectorAlignment = 0; 953 data->ByteOffsetForPartitionAlignment = 0; 954 955 data->Flags = SSINFO_FLAGS_ALIGNED_DEVICE | SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE; 956 957 if (Vcb->trim && !Vcb->options.no_trim) 958 data->Flags |= SSINFO_FLAGS_TRIM_ENABLED; 959 960 BytesCopied = sizeof(FILE_FS_SECTOR_SIZE_INFORMATION); 961 962 break; 963 } 964 #endif 965 #endif /* __REACTOS__ */ 966 967 default: 968 Status = STATUS_INVALID_PARAMETER; 969 WARN("unknown FsInformationClass %u\n", IrpSp->Parameters.QueryVolume.FsInformationClass); 970 break; 971 } 972 973 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) 974 Irp->IoStatus.Information = 0; 975 else 976 Irp->IoStatus.Information = BytesCopied; 977 978 end: 979 Irp->IoStatus.Status = Status; 980 981 IoCompleteRequest( Irp, IO_DISK_INCREMENT ); 982 983 if (top_level) 984 IoSetTopLevelIrp(NULL); 985 986 TRACE("query volume information returning %08x\n", Status); 987 988 FsRtlExitFileSystem(); 989 990 return Status; 991 } 992 993 _Function_class_(IO_COMPLETION_ROUTINE) 994 #ifdef __REACTOS__ 995 static NTSTATUS NTAPI read_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) { 996 #else 997 static NTSTATUS read_completion(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp, _In_ PVOID conptr) { 998 #endif 999 read_context* context = conptr; 1000 1001 UNUSED(DeviceObject); 1002 1003 context->iosb = Irp->IoStatus; 1004 KeSetEvent(&context->Event, 0, FALSE); 1005 1006 return STATUS_MORE_PROCESSING_REQUIRED; 1007 } 1008 1009 NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ UINT64 id, 1010 _Out_ root** rootptr, _In_ BOOL no_tree, _In_ UINT64 offset, _In_opt_ PIRP Irp) { 1011 NTSTATUS Status; 1012 root* r; 1013 tree* t = NULL; 1014 ROOT_ITEM* ri; 1015 traverse_ptr tp; 1016 1017 r = ExAllocatePoolWithTag(PagedPool, sizeof(root), ALLOC_TAG); 1018 if (!r) { 1019 ERR("out of memory\n"); 1020 return STATUS_INSUFFICIENT_RESOURCES; 1021 } 1022 1023 r->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(root_nonpaged), ALLOC_TAG); 1024 if (!r->nonpaged) { 1025 ERR("out of memory\n"); 1026 ExFreePool(r); 1027 return STATUS_INSUFFICIENT_RESOURCES; 1028 } 1029 1030 if (!no_tree) { 1031 t = ExAllocatePoolWithTag(PagedPool, sizeof(tree), ALLOC_TAG); 1032 if (!t) { 1033 ERR("out of memory\n"); 1034 ExFreePool(r->nonpaged); 1035 ExFreePool(r); 1036 return STATUS_INSUFFICIENT_RESOURCES; 1037 } 1038 1039 t->nonpaged = NULL; 1040 1041 t->is_unique = TRUE; 1042 t->uniqueness_determined = TRUE; 1043 t->buf = NULL; 1044 } 1045 1046 ri = ExAllocatePoolWithTag(PagedPool, sizeof(ROOT_ITEM), ALLOC_TAG); 1047 if (!ri) { 1048 ERR("out of memory\n"); 1049 1050 if (t) 1051 ExFreePool(t); 1052 1053 ExFreePool(r->nonpaged); 1054 ExFreePool(r); 1055 return STATUS_INSUFFICIENT_RESOURCES; 1056 } 1057 1058 r->id = id; 1059 r->treeholder.address = 0; 1060 r->treeholder.generation = Vcb->superblock.generation; 1061 r->treeholder.tree = t; 1062 r->lastinode = 0; 1063 r->dirty = FALSE; 1064 r->received = FALSE; 1065 r->reserved = NULL; 1066 r->parent = 0; 1067 r->send_ops = 0; 1068 RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM)); 1069 r->root_item.num_references = 1; 1070 r->fcbs_version = 0; 1071 InitializeListHead(&r->fcbs); 1072 RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256); 1073 1074 RtlCopyMemory(ri, &r->root_item, sizeof(ROOT_ITEM)); 1075 1076 // We ask here for a traverse_ptr to the item we're inserting, so we can 1077 // copy some of the tree's variables 1078 1079 Status = insert_tree_item(Vcb, Vcb->root_root, id, TYPE_ROOT_ITEM, offset, ri, sizeof(ROOT_ITEM), &tp, Irp); 1080 if (!NT_SUCCESS(Status)) { 1081 ERR("insert_tree_item returned %08x\n", Status); 1082 ExFreePool(ri); 1083 1084 if (t) 1085 ExFreePool(t); 1086 1087 ExFreePool(r->nonpaged); 1088 ExFreePool(r); 1089 return Status; 1090 } 1091 1092 ExInitializeResourceLite(&r->nonpaged->load_tree_lock); 1093 1094 InsertTailList(&Vcb->roots, &r->list_entry); 1095 1096 if (!no_tree) { 1097 RtlZeroMemory(&t->header, sizeof(tree_header)); 1098 t->header.fs_uuid = tp.tree->header.fs_uuid; 1099 t->header.address = 0; 1100 t->header.flags = HEADER_FLAG_MIXED_BACKREF | 1; // 1 == "written"? Why does the Linux driver record this? 1101 t->header.chunk_tree_uuid = tp.tree->header.chunk_tree_uuid; 1102 t->header.generation = Vcb->superblock.generation; 1103 t->header.tree_id = id; 1104 t->header.num_items = 0; 1105 t->header.level = 0; 1106 1107 t->has_address = FALSE; 1108 t->size = 0; 1109 t->Vcb = Vcb; 1110 t->parent = NULL; 1111 t->paritem = NULL; 1112 t->root = r; 1113 1114 InitializeListHead(&t->itemlist); 1115 1116 t->new_address = 0; 1117 t->has_new_address = FALSE; 1118 t->updated_extents = FALSE; 1119 1120 InsertTailList(&Vcb->trees, &t->list_entry); 1121 t->list_entry_hash.Flink = NULL; 1122 1123 t->write = TRUE; 1124 Vcb->need_write = TRUE; 1125 } 1126 1127 *rootptr = r; 1128 1129 return STATUS_SUCCESS; 1130 } 1131 1132 static NTSTATUS set_label(_In_ device_extension* Vcb, _In_ FILE_FS_LABEL_INFORMATION* ffli) { 1133 ULONG utf8len; 1134 NTSTATUS Status; 1135 ULONG vollen, i; 1136 1137 TRACE("label = %.*S\n", ffli->VolumeLabelLength / sizeof(WCHAR), ffli->VolumeLabel); 1138 1139 vollen = ffli->VolumeLabelLength; 1140 1141 for (i = 0; i < ffli->VolumeLabelLength / sizeof(WCHAR); i++) { 1142 if (ffli->VolumeLabel[i] == 0) { 1143 vollen = i * sizeof(WCHAR); 1144 break; 1145 } else if (ffli->VolumeLabel[i] == '/' || ffli->VolumeLabel[i] == '\\') { 1146 Status = STATUS_INVALID_VOLUME_LABEL; 1147 goto end; 1148 } 1149 } 1150 1151 if (vollen == 0) { 1152 utf8len = 0; 1153 } else { 1154 Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, ffli->VolumeLabel, vollen); 1155 if (!NT_SUCCESS(Status)) 1156 goto end; 1157 1158 if (utf8len > MAX_LABEL_SIZE) { 1159 Status = STATUS_INVALID_VOLUME_LABEL; 1160 goto end; 1161 } 1162 } 1163 1164 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 1165 1166 if (utf8len > 0) { 1167 Status = RtlUnicodeToUTF8N((PCHAR)&Vcb->superblock.label, MAX_LABEL_SIZE, &utf8len, ffli->VolumeLabel, vollen); 1168 if (!NT_SUCCESS(Status)) 1169 goto release; 1170 } else 1171 Status = STATUS_SUCCESS; 1172 1173 if (utf8len < MAX_LABEL_SIZE) 1174 RtlZeroMemory(Vcb->superblock.label + utf8len, MAX_LABEL_SIZE - utf8len); 1175 1176 Vcb->need_write = TRUE; 1177 1178 release: 1179 ExReleaseResourceLite(&Vcb->tree_lock); 1180 1181 end: 1182 TRACE("returning %08x\n", Status); 1183 1184 return Status; 1185 } 1186 1187 _Dispatch_type_(IRP_MJ_SET_VOLUME_INFORMATION) 1188 _Function_class_(DRIVER_DISPATCH) 1189 #ifdef __REACTOS__ 1190 static NTSTATUS NTAPI drv_set_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 1191 #else 1192 static NTSTATUS drv_set_volume_information(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 1193 #endif 1194 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 1195 device_extension* Vcb = DeviceObject->DeviceExtension; 1196 NTSTATUS Status; 1197 BOOL top_level; 1198 1199 FsRtlEnterFileSystem(); 1200 1201 TRACE("set volume information\n"); 1202 1203 top_level = is_top_level(Irp); 1204 1205 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 1206 Status = vol_set_volume_information(DeviceObject, Irp); 1207 goto end; 1208 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 1209 Status = STATUS_INVALID_PARAMETER; 1210 goto end; 1211 } 1212 1213 Status = STATUS_NOT_IMPLEMENTED; 1214 1215 if (Vcb->readonly) { 1216 Status = STATUS_MEDIA_WRITE_PROTECTED; 1217 goto end; 1218 } 1219 1220 if (Vcb->removing || Vcb->locked) { 1221 Status = STATUS_ACCESS_DENIED; 1222 goto end; 1223 } 1224 1225 switch (IrpSp->Parameters.SetVolume.FsInformationClass) { 1226 case FileFsControlInformation: 1227 FIXME("STUB: FileFsControlInformation\n"); 1228 break; 1229 1230 case FileFsLabelInformation: 1231 TRACE("FileFsLabelInformation\n"); 1232 1233 Status = set_label(Vcb, Irp->AssociatedIrp.SystemBuffer); 1234 break; 1235 1236 case FileFsObjectIdInformation: 1237 FIXME("STUB: FileFsObjectIdInformation\n"); 1238 break; 1239 1240 default: 1241 WARN("Unrecognized FsInformationClass 0x%x\n", IrpSp->Parameters.SetVolume.FsInformationClass); 1242 break; 1243 } 1244 1245 end: 1246 Irp->IoStatus.Status = Status; 1247 Irp->IoStatus.Information = 0; 1248 1249 TRACE("returning %08x\n", Status); 1250 1251 IoCompleteRequest( Irp, IO_NO_INCREMENT ); 1252 1253 if (top_level) 1254 IoSetTopLevelIrp(NULL); 1255 1256 FsRtlExitFileSystem(); 1257 1258 return Status; 1259 } 1260 1261 static WCHAR* file_desc_fcb(_In_ fcb* fcb) { 1262 char s[60]; 1263 NTSTATUS Status; 1264 UNICODE_STRING us; 1265 ANSI_STRING as; 1266 1267 if (fcb->debug_desc) 1268 return fcb->debug_desc; 1269 1270 if (fcb == fcb->Vcb->volume_fcb) 1271 return L"volume FCB"; 1272 1273 fcb->debug_desc = ExAllocatePoolWithTag(PagedPool, 60 * sizeof(WCHAR), ALLOC_TAG); 1274 if (!fcb->debug_desc) 1275 return L"(memory error)"; 1276 1277 // I know this is pretty hackish... 1278 // GCC doesn't like %llx in sprintf, and MSVC won't let us use swprintf 1279 // without the CRT, which breaks drivers. 1280 1281 sprintf(s, "subvol %x, inode %x", (UINT32)fcb->subvol->id, (UINT32)fcb->inode); 1282 1283 as.Buffer = s; 1284 as.Length = as.MaximumLength = (USHORT)strlen(s); 1285 1286 us.Buffer = fcb->debug_desc; 1287 us.MaximumLength = 60 * sizeof(WCHAR); 1288 us.Length = 0; 1289 1290 Status = RtlAnsiStringToUnicodeString(&us, &as, FALSE); 1291 if (!NT_SUCCESS(Status)) 1292 return L"(RtlAnsiStringToUnicodeString error)"; 1293 1294 us.Buffer[us.Length / sizeof(WCHAR)] = 0; 1295 1296 return fcb->debug_desc; 1297 } 1298 1299 WCHAR* file_desc_fileref(_In_ file_ref* fileref) { 1300 NTSTATUS Status; 1301 UNICODE_STRING fn; 1302 ULONG reqlen; 1303 1304 if (fileref->debug_desc) 1305 return fileref->debug_desc; 1306 1307 fn.Length = fn.MaximumLength = 0; 1308 Status = fileref_get_filename(fileref, &fn, NULL, &reqlen); 1309 if (Status != STATUS_BUFFER_OVERFLOW) 1310 return L"ERROR"; 1311 1312 if (reqlen > 0xffff - sizeof(WCHAR)) 1313 return L"(too long)"; 1314 1315 fileref->debug_desc = ExAllocatePoolWithTag(PagedPool, reqlen + sizeof(WCHAR), ALLOC_TAG); 1316 if (!fileref->debug_desc) 1317 return L"(memory error)"; 1318 1319 fn.Buffer = fileref->debug_desc; 1320 fn.Length = 0; 1321 fn.MaximumLength = (USHORT)(reqlen + sizeof(WCHAR)); 1322 1323 Status = fileref_get_filename(fileref, &fn, NULL, &reqlen); 1324 if (!NT_SUCCESS(Status)) { 1325 ExFreePool(fileref->debug_desc); 1326 fileref->debug_desc = NULL; 1327 return L"ERROR"; 1328 } 1329 1330 fileref->debug_desc[fn.Length / sizeof(WCHAR)] = 0; 1331 1332 return fileref->debug_desc; 1333 } 1334 1335 _Ret_z_ 1336 WCHAR* file_desc(_In_ PFILE_OBJECT FileObject) { 1337 fcb* fcb = FileObject->FsContext; 1338 ccb* ccb = FileObject->FsContext2; 1339 file_ref* fileref = ccb ? ccb->fileref : NULL; 1340 1341 if (fileref) 1342 return file_desc_fileref(fileref); 1343 else 1344 return file_desc_fcb(fcb); 1345 } 1346 1347 void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) { 1348 UNICODE_STRING fn; 1349 NTSTATUS Status; 1350 ULONG reqlen; 1351 USHORT name_offset; 1352 fcb* fcb = fileref->fcb; 1353 1354 fn.Length = fn.MaximumLength = 0; 1355 Status = fileref_get_filename(fileref, &fn, NULL, &reqlen); 1356 if (Status != STATUS_BUFFER_OVERFLOW) { 1357 ERR("fileref_get_filename returned %08x\n", Status); 1358 return; 1359 } 1360 1361 if (reqlen > 0xffff) { 1362 WARN("reqlen was too long for FsRtlNotifyFilterReportChange\n"); 1363 return; 1364 } 1365 1366 fn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG); 1367 if (!fn.Buffer) { 1368 ERR("out of memory\n"); 1369 return; 1370 } 1371 1372 fn.MaximumLength = (USHORT)reqlen; 1373 fn.Length = 0; 1374 1375 Status = fileref_get_filename(fileref, &fn, &name_offset, &reqlen); 1376 if (!NT_SUCCESS(Status)) { 1377 ERR("fileref_get_filename returned %08x\n", Status); 1378 ExFreePool(fn.Buffer); 1379 return; 1380 } 1381 1382 FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fn, name_offset, 1383 (PSTRING)stream, NULL, filter_match, action, NULL, NULL); 1384 ExFreePool(fn.Buffer); 1385 } 1386 1387 void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream) { 1388 fcb* fcb = fileref->fcb; 1389 LIST_ENTRY* le; 1390 NTSTATUS Status; 1391 1392 // no point looking for hardlinks if st_nlink == 1 1393 if (fileref->fcb->inode_item.st_nlink == 1) { 1394 send_notification_fileref(fileref, filter_match, action, stream); 1395 return; 1396 } 1397 1398 ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE); 1399 1400 le = fcb->hardlinks.Flink; 1401 while (le != &fcb->hardlinks) { 1402 hardlink* hl = CONTAINING_RECORD(le, hardlink, list_entry); 1403 file_ref* parfr; 1404 1405 Status = open_fileref_by_inode(fcb->Vcb, fcb->subvol, hl->parent, &parfr, NULL); 1406 1407 if (!NT_SUCCESS(Status)) 1408 ERR("open_fileref_by_inode returned %08x\n", Status); 1409 else if (!parfr->deleted) { 1410 UNICODE_STRING fn; 1411 ULONG pathlen; 1412 1413 fn.Length = fn.MaximumLength = 0; 1414 Status = fileref_get_filename(parfr, &fn, NULL, &pathlen); 1415 if (Status != STATUS_BUFFER_OVERFLOW) { 1416 ERR("fileref_get_filename returned %08x\n", Status); 1417 free_fileref(parfr); 1418 break; 1419 } 1420 1421 if (parfr != fcb->Vcb->root_fileref) 1422 pathlen += sizeof(WCHAR); 1423 1424 if (pathlen + hl->name.Length > 0xffff) { 1425 WARN("pathlen + hl->name.Length was too long for FsRtlNotifyFilterReportChange\n"); 1426 free_fileref(parfr); 1427 break; 1428 } 1429 1430 fn.MaximumLength = (USHORT)(pathlen + hl->name.Length); 1431 fn.Buffer = ExAllocatePoolWithTag(PagedPool, fn.MaximumLength, ALLOC_TAG); 1432 if (!fn.Buffer) { 1433 ERR("out of memory\n"); 1434 free_fileref(parfr); 1435 break; 1436 } 1437 1438 Status = fileref_get_filename(parfr, &fn, NULL, NULL); 1439 if (!NT_SUCCESS(Status)) { 1440 ERR("fileref_get_filename returned %08x\n", Status); 1441 free_fileref(parfr); 1442 ExFreePool(fn.Buffer); 1443 break; 1444 } 1445 1446 if (parfr != fcb->Vcb->root_fileref) { 1447 fn.Buffer[(pathlen / sizeof(WCHAR)) - 1] = '\\'; 1448 fn.Length += sizeof(WCHAR); 1449 } 1450 1451 RtlCopyMemory(&fn.Buffer[pathlen / sizeof(WCHAR)], hl->name.Buffer, hl->name.Length); 1452 fn.Length += hl->name.Length; 1453 1454 FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&fn, (USHORT)pathlen, 1455 (PSTRING)stream, NULL, filter_match, action, NULL, NULL); 1456 1457 ExFreePool(fn.Buffer); 1458 1459 free_fileref(parfr); 1460 } 1461 1462 le = le->Flink; 1463 } 1464 1465 ExReleaseResourceLite(&fcb->Vcb->fileref_lock); 1466 } 1467 1468 void mark_fcb_dirty(_In_ fcb* fcb) { 1469 if (!fcb->dirty) { 1470 #ifdef DEBUG_FCB_REFCOUNTS 1471 LONG rc; 1472 #endif 1473 fcb->dirty = TRUE; 1474 1475 #ifdef DEBUG_FCB_REFCOUNTS 1476 rc = InterlockedIncrement(&fcb->refcount); 1477 WARN("fcb %p: refcount now %i\n", fcb, rc); 1478 #else 1479 InterlockedIncrement(&fcb->refcount); 1480 #endif 1481 1482 ExAcquireResourceExclusiveLite(&fcb->Vcb->dirty_fcbs_lock, TRUE); 1483 InsertTailList(&fcb->Vcb->dirty_fcbs, &fcb->list_entry_dirty); 1484 ExReleaseResourceLite(&fcb->Vcb->dirty_fcbs_lock); 1485 } 1486 1487 fcb->Vcb->need_write = TRUE; 1488 } 1489 1490 void mark_fileref_dirty(_In_ file_ref* fileref) { 1491 if (!fileref->dirty) { 1492 fileref->dirty = TRUE; 1493 increase_fileref_refcount(fileref); 1494 1495 ExAcquireResourceExclusiveLite(&fileref->fcb->Vcb->dirty_filerefs_lock, TRUE); 1496 InsertTailList(&fileref->fcb->Vcb->dirty_filerefs, &fileref->list_entry_dirty); 1497 ExReleaseResourceLite(&fileref->fcb->Vcb->dirty_filerefs_lock); 1498 } 1499 1500 fileref->fcb->Vcb->need_write = TRUE; 1501 } 1502 1503 #ifdef DEBUG_FCB_REFCOUNTS 1504 void _free_fcb(_Inout_ fcb* fcb, _In_ const char* func) { 1505 LONG rc = InterlockedDecrement(&fcb->refcount); 1506 #else 1507 void free_fcb(_Inout_ fcb* fcb) { 1508 InterlockedDecrement(&fcb->refcount); 1509 #endif 1510 1511 #ifdef DEBUG_FCB_REFCOUNTS 1512 #ifdef DEBUG_LONG_MESSAGES 1513 ERR("fcb %p (%s): refcount now %i (subvol %llx, inode %llx)\n", fcb, func, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode); 1514 #else 1515 ERR("fcb %p (%s): refcount now %i (subvol %llx, inode %llx)\n", fcb, func, rc, fcb->subvol ? fcb->subvol->id : 0, fcb->inode); 1516 #endif 1517 #endif 1518 } 1519 1520 void reap_fcb(fcb* fcb) { 1521 UINT8 c = fcb->hash >> 24; 1522 1523 if (fcb->subvol && fcb->subvol->fcbs_ptrs[c] == &fcb->list_entry) { 1524 if (fcb->list_entry.Flink != &fcb->subvol->fcbs && (CONTAINING_RECORD(fcb->list_entry.Flink, struct _fcb, list_entry)->hash >> 24) == c) 1525 fcb->subvol->fcbs_ptrs[c] = fcb->list_entry.Flink; 1526 else 1527 fcb->subvol->fcbs_ptrs[c] = NULL; 1528 } 1529 1530 if (fcb->list_entry.Flink) 1531 RemoveEntryList(&fcb->list_entry); 1532 1533 if (fcb->list_entry_all.Flink) 1534 RemoveEntryList(&fcb->list_entry_all); 1535 1536 ExDeleteResourceLite(&fcb->nonpaged->resource); 1537 ExDeleteResourceLite(&fcb->nonpaged->paging_resource); 1538 ExDeleteResourceLite(&fcb->nonpaged->dir_children_lock); 1539 1540 ExFreeToNPagedLookasideList(&fcb->Vcb->fcb_np_lookaside, fcb->nonpaged); 1541 1542 if (fcb->sd) 1543 ExFreePool(fcb->sd); 1544 1545 if (fcb->adsxattr.Buffer) 1546 ExFreePool(fcb->adsxattr.Buffer); 1547 1548 if (fcb->reparse_xattr.Buffer) 1549 ExFreePool(fcb->reparse_xattr.Buffer); 1550 1551 if (fcb->ea_xattr.Buffer) 1552 ExFreePool(fcb->ea_xattr.Buffer); 1553 1554 if (fcb->adsdata.Buffer) 1555 ExFreePool(fcb->adsdata.Buffer); 1556 1557 if (fcb->debug_desc) 1558 ExFreePool(fcb->debug_desc); 1559 1560 while (!IsListEmpty(&fcb->extents)) { 1561 LIST_ENTRY* le = RemoveHeadList(&fcb->extents); 1562 extent* ext = CONTAINING_RECORD(le, extent, list_entry); 1563 1564 if (ext->csum) 1565 ExFreePool(ext->csum); 1566 1567 ExFreePool(ext); 1568 } 1569 1570 while (!IsListEmpty(&fcb->hardlinks)) { 1571 LIST_ENTRY* le = RemoveHeadList(&fcb->hardlinks); 1572 hardlink* hl = CONTAINING_RECORD(le, hardlink, list_entry); 1573 1574 if (hl->name.Buffer) 1575 ExFreePool(hl->name.Buffer); 1576 1577 if (hl->utf8.Buffer) 1578 ExFreePool(hl->utf8.Buffer); 1579 1580 ExFreePool(hl); 1581 } 1582 1583 while (!IsListEmpty(&fcb->xattrs)) { 1584 xattr* xa = CONTAINING_RECORD(RemoveHeadList(&fcb->xattrs), xattr, list_entry); 1585 1586 ExFreePool(xa); 1587 } 1588 1589 while (!IsListEmpty(&fcb->dir_children_index)) { 1590 LIST_ENTRY* le = RemoveHeadList(&fcb->dir_children_index); 1591 dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index); 1592 1593 ExFreePool(dc->utf8.Buffer); 1594 ExFreePool(dc->name.Buffer); 1595 ExFreePool(dc->name_uc.Buffer); 1596 ExFreePool(dc); 1597 } 1598 1599 if (fcb->hash_ptrs) 1600 ExFreePool(fcb->hash_ptrs); 1601 1602 if (fcb->hash_ptrs_uc) 1603 ExFreePool(fcb->hash_ptrs_uc); 1604 1605 FsRtlUninitializeFileLock(&fcb->lock); 1606 1607 if (fcb->pool_type == NonPagedPool) 1608 ExFreePool(fcb); 1609 else 1610 ExFreeToPagedLookasideList(&fcb->Vcb->fcb_lookaside, fcb); 1611 } 1612 1613 void reap_fcbs(device_extension* Vcb) { 1614 LIST_ENTRY* le; 1615 1616 le = Vcb->all_fcbs.Flink; 1617 while (le != &Vcb->all_fcbs) { 1618 fcb* fcb = CONTAINING_RECORD(le, struct _fcb, list_entry_all); 1619 LIST_ENTRY* le2 = le->Flink; 1620 1621 if (fcb->refcount == 0) 1622 reap_fcb(fcb); 1623 1624 le = le2; 1625 } 1626 } 1627 1628 void free_fileref(_Inout_ file_ref* fr) { 1629 LONG rc; 1630 1631 rc = InterlockedDecrement(&fr->refcount); 1632 #ifdef __REACTOS__ 1633 (void)rc; 1634 #endif 1635 1636 #ifdef DEBUG_FCB_REFCOUNTS 1637 ERR("fileref %p: refcount now %i\n", fr, rc); 1638 #endif 1639 1640 #ifdef _DEBUG 1641 if (rc < 0) { 1642 ERR("fileref %p: refcount now %i\n", fr, rc); 1643 int3; 1644 } 1645 #endif 1646 } 1647 1648 void reap_fileref(device_extension* Vcb, file_ref* fr) { 1649 // FIXME - do we need a file_ref lock? 1650 1651 // FIXME - do delete if needed 1652 1653 if (fr->debug_desc) 1654 ExFreePool(fr->debug_desc); 1655 1656 ExDeleteResourceLite(&fr->nonpaged->fileref_lock); 1657 1658 ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged); 1659 1660 // FIXME - throw error if children not empty 1661 1662 if (fr->fcb->fileref == fr) 1663 fr->fcb->fileref = NULL; 1664 1665 if (fr->dc) { 1666 if (fr->fcb->ads) 1667 fr->dc->size = fr->fcb->adsdata.Length; 1668 1669 fr->dc->fileref = NULL; 1670 } 1671 1672 if (fr->list_entry.Flink) 1673 RemoveEntryList(&fr->list_entry); 1674 1675 if (fr->parent) 1676 free_fileref(fr->parent); 1677 1678 free_fcb(fr->fcb); 1679 1680 ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr); 1681 } 1682 1683 void reap_filerefs(device_extension* Vcb, file_ref* fr) { 1684 LIST_ENTRY* le; 1685 1686 // FIXME - recursion is a bad idea in kernel mode 1687 1688 le = fr->children.Flink; 1689 while (le != &fr->children) { 1690 file_ref* c = CONTAINING_RECORD(le, file_ref, list_entry); 1691 LIST_ENTRY* le2 = le->Flink; 1692 1693 reap_filerefs(Vcb, c); 1694 1695 le = le2; 1696 } 1697 1698 if (fr->refcount == 0) 1699 reap_fileref(Vcb, fr); 1700 } 1701 1702 static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP Irp) { 1703 fcb* fcb; 1704 ccb* ccb; 1705 file_ref* fileref = NULL; 1706 LONG open_files; 1707 1708 UNUSED(Irp); 1709 1710 TRACE("FileObject = %p\n", FileObject); 1711 1712 fcb = FileObject->FsContext; 1713 if (!fcb) { 1714 TRACE("FCB was NULL, returning success\n"); 1715 return STATUS_SUCCESS; 1716 } 1717 1718 open_files = InterlockedDecrement(&fcb->Vcb->open_files); 1719 1720 ccb = FileObject->FsContext2; 1721 1722 TRACE("close called for %S (fcb == %p)\n", file_desc(FileObject), fcb); 1723 1724 // FIXME - make sure notification gets sent if file is being deleted 1725 1726 if (ccb) { 1727 if (ccb->query_string.Buffer) 1728 RtlFreeUnicodeString(&ccb->query_string); 1729 1730 if (ccb->filename.Buffer) 1731 ExFreePool(ccb->filename.Buffer); 1732 1733 // FIXME - use refcounts for fileref 1734 fileref = ccb->fileref; 1735 1736 if (fcb->Vcb->running_sends > 0) { 1737 BOOL send_cancelled = FALSE; 1738 1739 ExAcquireResourceExclusiveLite(&fcb->Vcb->send_load_lock, TRUE); 1740 1741 if (ccb->send) { 1742 ccb->send->cancelling = TRUE; 1743 send_cancelled = TRUE; 1744 KeSetEvent(&ccb->send->cleared_event, 0, FALSE); 1745 } 1746 1747 ExReleaseResourceLite(&fcb->Vcb->send_load_lock); 1748 1749 if (send_cancelled) { 1750 while (ccb->send) { 1751 ExAcquireResourceExclusiveLite(&fcb->Vcb->send_load_lock, TRUE); 1752 ExReleaseResourceLite(&fcb->Vcb->send_load_lock); 1753 } 1754 } 1755 } 1756 1757 ExFreePool(ccb); 1758 } 1759 1760 CcUninitializeCacheMap(FileObject, NULL, NULL); 1761 1762 if (open_files == 0 && fcb->Vcb->removing) { 1763 uninit(fcb->Vcb); 1764 return STATUS_SUCCESS; 1765 } 1766 1767 if (!(fcb->Vcb->Vpb->Flags & VPB_MOUNTED)) 1768 return STATUS_SUCCESS; 1769 1770 if (fileref) 1771 free_fileref(fileref); 1772 else 1773 free_fcb(fcb); 1774 1775 return STATUS_SUCCESS; 1776 } 1777 1778 void uninit(_In_ device_extension* Vcb) { 1779 UINT64 i; 1780 KIRQL irql; 1781 NTSTATUS Status; 1782 LIST_ENTRY* le; 1783 LARGE_INTEGER time; 1784 1785 if (!Vcb->removing) { 1786 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 1787 Vcb->removing = TRUE; 1788 ExReleaseResourceLite(&Vcb->tree_lock); 1789 } 1790 1791 IoAcquireVpbSpinLock(&irql); 1792 Vcb->Vpb->Flags &= ~VPB_MOUNTED; 1793 Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED; 1794 IoReleaseVpbSpinLock(irql); 1795 1796 RemoveEntryList(&Vcb->list_entry); 1797 1798 if (Vcb->balance.thread) { 1799 Vcb->balance.paused = FALSE; 1800 Vcb->balance.stopping = TRUE; 1801 KeSetEvent(&Vcb->balance.event, 0, FALSE); 1802 KeWaitForSingleObject(&Vcb->balance.finished, Executive, KernelMode, FALSE, NULL); 1803 } 1804 1805 if (Vcb->scrub.thread) { 1806 Vcb->scrub.paused = FALSE; 1807 Vcb->scrub.stopping = TRUE; 1808 KeSetEvent(&Vcb->scrub.event, 0, FALSE); 1809 KeWaitForSingleObject(&Vcb->scrub.finished, Executive, KernelMode, FALSE, NULL); 1810 } 1811 1812 if (Vcb->running_sends != 0) { 1813 BOOL send_cancelled = FALSE; 1814 1815 ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE); 1816 1817 le = Vcb->send_ops.Flink; 1818 while (le != &Vcb->send_ops) { 1819 send_info* send = CONTAINING_RECORD(le, send_info, list_entry); 1820 1821 if (!send->cancelling) { 1822 send->cancelling = TRUE; 1823 send_cancelled = TRUE; 1824 send->ccb = NULL; 1825 KeSetEvent(&send->cleared_event, 0, FALSE); 1826 } 1827 1828 le = le->Flink; 1829 } 1830 1831 ExReleaseResourceLite(&Vcb->send_load_lock); 1832 1833 if (send_cancelled) { 1834 while (Vcb->running_sends != 0) { 1835 ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE); 1836 ExReleaseResourceLite(&Vcb->send_load_lock); 1837 } 1838 } 1839 } 1840 1841 Status = registry_mark_volume_unmounted(&Vcb->superblock.uuid); 1842 if (!NT_SUCCESS(Status) && Status != STATUS_TOO_LATE) 1843 WARN("registry_mark_volume_unmounted returned %08x\n", Status); 1844 1845 for (i = 0; i < Vcb->calcthreads.num_threads; i++) { 1846 Vcb->calcthreads.threads[i].quit = TRUE; 1847 } 1848 1849 KeSetEvent(&Vcb->calcthreads.event, 0, FALSE); 1850 1851 for (i = 0; i < Vcb->calcthreads.num_threads; i++) { 1852 KeWaitForSingleObject(&Vcb->calcthreads.threads[i].finished, Executive, KernelMode, FALSE, NULL); 1853 1854 ZwClose(Vcb->calcthreads.threads[i].handle); 1855 } 1856 1857 ExDeleteResourceLite(&Vcb->calcthreads.lock); 1858 ExFreePool(Vcb->calcthreads.threads); 1859 1860 time.QuadPart = 0; 1861 KeSetTimer(&Vcb->flush_thread_timer, time, NULL); // trigger the timer early 1862 KeWaitForSingleObject(&Vcb->flush_thread_finished, Executive, KernelMode, FALSE, NULL); 1863 1864 reap_fcb(Vcb->volume_fcb); 1865 reap_fcb(Vcb->dummy_fcb); 1866 1867 if (Vcb->root_file) 1868 ObDereferenceObject(Vcb->root_file); 1869 1870 le = Vcb->chunks.Flink; 1871 while (le != &Vcb->chunks) { 1872 chunk* c = CONTAINING_RECORD(le, chunk, list_entry); 1873 1874 if (c->cache) { 1875 reap_fcb(c->cache); 1876 c->cache = NULL; 1877 } 1878 1879 le = le->Flink; 1880 } 1881 1882 while (!IsListEmpty(&Vcb->roots)) { 1883 root* r = CONTAINING_RECORD(RemoveHeadList(&Vcb->roots), root, list_entry); 1884 1885 ExDeleteResourceLite(&r->nonpaged->load_tree_lock); 1886 ExFreePool(r->nonpaged); 1887 ExFreePool(r); 1888 } 1889 1890 while (!IsListEmpty(&Vcb->chunks)) { 1891 chunk* c = CONTAINING_RECORD(RemoveHeadList(&Vcb->chunks), chunk, list_entry); 1892 1893 while (!IsListEmpty(&c->space)) { 1894 LIST_ENTRY* le2 = RemoveHeadList(&c->space); 1895 space* s = CONTAINING_RECORD(le2, space, list_entry); 1896 1897 ExFreePool(s); 1898 } 1899 1900 while (!IsListEmpty(&c->deleting)) { 1901 LIST_ENTRY* le2 = RemoveHeadList(&c->deleting); 1902 space* s = CONTAINING_RECORD(le2, space, list_entry); 1903 1904 ExFreePool(s); 1905 } 1906 1907 if (c->devices) 1908 ExFreePool(c->devices); 1909 1910 if (c->cache) 1911 reap_fcb(c->cache); 1912 1913 ExDeleteResourceLite(&c->range_locks_lock); 1914 ExDeleteResourceLite(&c->partial_stripes_lock); 1915 ExDeleteResourceLite(&c->lock); 1916 ExDeleteResourceLite(&c->changed_extents_lock); 1917 1918 ExFreePool(c->chunk_item); 1919 ExFreePool(c); 1920 } 1921 1922 // FIXME - free any open fcbs? 1923 1924 while (!IsListEmpty(&Vcb->devices)) { 1925 device* dev = CONTAINING_RECORD(RemoveHeadList(&Vcb->devices), device, list_entry); 1926 1927 while (!IsListEmpty(&dev->space)) { 1928 LIST_ENTRY* le2 = RemoveHeadList(&dev->space); 1929 space* s = CONTAINING_RECORD(le2, space, list_entry); 1930 1931 ExFreePool(s); 1932 } 1933 1934 ExFreePool(dev); 1935 } 1936 1937 ExAcquireResourceExclusiveLite(&Vcb->scrub.stats_lock, TRUE); 1938 while (!IsListEmpty(&Vcb->scrub.errors)) { 1939 scrub_error* err = CONTAINING_RECORD(RemoveHeadList(&Vcb->scrub.errors), scrub_error, list_entry); 1940 1941 ExFreePool(err); 1942 } 1943 ExReleaseResourceLite(&Vcb->scrub.stats_lock); 1944 1945 ExDeleteResourceLite(&Vcb->fcb_lock); 1946 ExDeleteResourceLite(&Vcb->fileref_lock); 1947 ExDeleteResourceLite(&Vcb->load_lock); 1948 ExDeleteResourceLite(&Vcb->tree_lock); 1949 ExDeleteResourceLite(&Vcb->chunk_lock); 1950 ExDeleteResourceLite(&Vcb->dirty_fcbs_lock); 1951 ExDeleteResourceLite(&Vcb->dirty_filerefs_lock); 1952 ExDeleteResourceLite(&Vcb->dirty_subvols_lock); 1953 ExDeleteResourceLite(&Vcb->scrub.stats_lock); 1954 ExDeleteResourceLite(&Vcb->send_load_lock); 1955 1956 ExDeletePagedLookasideList(&Vcb->tree_data_lookaside); 1957 ExDeletePagedLookasideList(&Vcb->traverse_ptr_lookaside); 1958 ExDeletePagedLookasideList(&Vcb->batch_item_lookaside); 1959 ExDeletePagedLookasideList(&Vcb->fileref_lookaside); 1960 ExDeletePagedLookasideList(&Vcb->fcb_lookaside); 1961 ExDeletePagedLookasideList(&Vcb->name_bit_lookaside); 1962 ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside); 1963 ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside); 1964 ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside); 1965 1966 ZwClose(Vcb->flush_thread_handle); 1967 } 1968 1969 NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) { 1970 LARGE_INTEGER newlength, time; 1971 BTRFS_TIME now; 1972 NTSTATUS Status; 1973 ULONG utf8len = 0; 1974 1975 KeQuerySystemTime(&time); 1976 win_time_to_unix(time, &now); 1977 1978 ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, TRUE); 1979 1980 if (fileref->deleted) { 1981 ExReleaseResourceLite(fileref->fcb->Header.Resource); 1982 return STATUS_SUCCESS; 1983 } 1984 1985 if (fileref->fcb->subvol->send_ops > 0) { 1986 ExReleaseResourceLite(fileref->fcb->Header.Resource); 1987 return STATUS_ACCESS_DENIED; 1988 } 1989 1990 fileref->deleted = TRUE; 1991 mark_fileref_dirty(fileref); 1992 1993 // delete INODE_ITEM (0x1) 1994 1995 TRACE("nlink = %u\n", fileref->fcb->inode_item.st_nlink); 1996 1997 if (!fileref->fcb->ads) { 1998 if (fileref->parent->fcb->subvol == fileref->fcb->subvol) { 1999 LIST_ENTRY* le; 2000 2001 mark_fcb_dirty(fileref->fcb); 2002 2003 fileref->fcb->inode_item_changed = TRUE; 2004 2005 if (fileref->fcb->inode_item.st_nlink > 1) { 2006 fileref->fcb->inode_item.st_nlink--; 2007 fileref->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation; 2008 fileref->fcb->inode_item.sequence++; 2009 fileref->fcb->inode_item.st_ctime = now; 2010 } else { 2011 // excise extents 2012 2013 if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY && fileref->fcb->inode_item.st_size > 0) { 2014 Status = excise_extents(fileref->fcb->Vcb, fileref->fcb, 0, sector_align(fileref->fcb->inode_item.st_size, fileref->fcb->Vcb->superblock.sector_size), Irp, rollback); 2015 if (!NT_SUCCESS(Status)) { 2016 ERR("excise_extents returned %08x\n", Status); 2017 ExReleaseResourceLite(fileref->fcb->Header.Resource); 2018 return Status; 2019 } 2020 } 2021 2022 fileref->fcb->Header.AllocationSize.QuadPart = 0; 2023 fileref->fcb->Header.FileSize.QuadPart = 0; 2024 fileref->fcb->Header.ValidDataLength.QuadPart = 0; 2025 2026 if (FileObject) { 2027 CC_FILE_SIZES ccfs; 2028 2029 ccfs.AllocationSize = fileref->fcb->Header.AllocationSize; 2030 ccfs.FileSize = fileref->fcb->Header.FileSize; 2031 ccfs.ValidDataLength = fileref->fcb->Header.ValidDataLength; 2032 2033 Status = STATUS_SUCCESS; 2034 2035 _SEH2_TRY { 2036 CcSetFileSizes(FileObject, &ccfs); 2037 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 2038 Status = _SEH2_GetExceptionCode(); 2039 } _SEH2_END; 2040 2041 if (!NT_SUCCESS(Status)) { 2042 ERR("CcSetFileSizes threw exception %08x\n", Status); 2043 ExReleaseResourceLite(fileref->fcb->Header.Resource); 2044 return Status; 2045 } 2046 } 2047 2048 fileref->fcb->deleted = TRUE; 2049 2050 le = fileref->children.Flink; 2051 while (le != &fileref->children) { 2052 file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry); 2053 2054 if (fr2->fcb->ads) { 2055 fr2->fcb->deleted = TRUE; 2056 mark_fcb_dirty(fr2->fcb); 2057 } 2058 2059 le = le->Flink; 2060 } 2061 } 2062 2063 if (fileref->dc) { 2064 le = fileref->fcb->hardlinks.Flink; 2065 while (le != &fileref->fcb->hardlinks) { 2066 hardlink* hl = CONTAINING_RECORD(le, hardlink, list_entry); 2067 2068 if (hl->parent == fileref->parent->fcb->inode && hl->index == fileref->dc->index) { 2069 RemoveEntryList(&hl->list_entry); 2070 2071 if (hl->name.Buffer) 2072 ExFreePool(hl->name.Buffer); 2073 2074 if (hl->utf8.Buffer) 2075 ExFreePool(hl->utf8.Buffer); 2076 2077 ExFreePool(hl); 2078 break; 2079 } 2080 2081 le = le->Flink; 2082 } 2083 } 2084 } else if (fileref->fcb->subvol->parent == fileref->parent->fcb->subvol->id) { // valid subvolume 2085 if (fileref->fcb->subvol->root_item.num_references > 1) { 2086 fileref->fcb->subvol->root_item.num_references--; 2087 2088 mark_fcb_dirty(fileref->fcb); // so ROOT_ITEM gets updated 2089 } else { 2090 LIST_ENTRY* le; 2091 2092 // FIXME - we need a lock here 2093 2094 RemoveEntryList(&fileref->fcb->subvol->list_entry); 2095 2096 InsertTailList(&fileref->fcb->Vcb->drop_roots, &fileref->fcb->subvol->list_entry); 2097 2098 le = fileref->children.Flink; 2099 while (le != &fileref->children) { 2100 file_ref* fr2 = CONTAINING_RECORD(le, file_ref, list_entry); 2101 2102 if (fr2->fcb->ads) { 2103 fr2->fcb->deleted = TRUE; 2104 mark_fcb_dirty(fr2->fcb); 2105 } 2106 2107 le = le->Flink; 2108 } 2109 } 2110 } 2111 } else { 2112 fileref->fcb->deleted = TRUE; 2113 mark_fcb_dirty(fileref->fcb); 2114 } 2115 2116 // remove dir_child from parent 2117 2118 if (fileref->dc) { 2119 TRACE("delete file %.*S\n", fileref->dc->name.Length / sizeof(WCHAR), fileref->dc->name.Buffer); 2120 2121 ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, TRUE); 2122 RemoveEntryList(&fileref->dc->list_entry_index); 2123 2124 if (!fileref->fcb->ads) 2125 remove_dir_child_from_hash_lists(fileref->parent->fcb, fileref->dc); 2126 2127 ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock); 2128 2129 if (!fileref->oldutf8.Buffer) 2130 fileref->oldutf8 = fileref->dc->utf8; 2131 else 2132 ExFreePool(fileref->dc->utf8.Buffer); 2133 2134 utf8len = fileref->dc->utf8.Length; 2135 2136 fileref->oldindex = fileref->dc->index; 2137 2138 ExFreePool(fileref->dc->name.Buffer); 2139 ExFreePool(fileref->dc->name_uc.Buffer); 2140 ExFreePool(fileref->dc); 2141 2142 fileref->dc = NULL; 2143 } 2144 2145 // update INODE_ITEM of parent 2146 2147 ExAcquireResourceExclusiveLite(fileref->parent->fcb->Header.Resource, TRUE); 2148 2149 fileref->parent->fcb->inode_item.transid = fileref->fcb->Vcb->superblock.generation; 2150 fileref->parent->fcb->inode_item.sequence++; 2151 fileref->parent->fcb->inode_item.st_ctime = now; 2152 2153 if (!fileref->fcb->ads) { 2154 TRACE("fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", fileref->parent->fcb->inode, fileref->parent->fcb->inode_item.st_size); 2155 fileref->parent->fcb->inode_item.st_size -= utf8len * 2; 2156 TRACE("fileref->parent->fcb->inode_item.st_size (inode %llx) now %llx\n", fileref->parent->fcb->inode, fileref->parent->fcb->inode_item.st_size); 2157 fileref->parent->fcb->inode_item.st_mtime = now; 2158 } 2159 2160 fileref->parent->fcb->inode_item_changed = TRUE; 2161 ExReleaseResourceLite(fileref->parent->fcb->Header.Resource); 2162 2163 if (!fileref->fcb->ads && fileref->parent->dc) 2164 send_notification_fcb(fileref->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL); 2165 2166 mark_fcb_dirty(fileref->parent->fcb); 2167 2168 fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation; 2169 fileref->fcb->subvol->root_item.ctime = now; 2170 2171 newlength.QuadPart = 0; 2172 2173 if (FileObject && !CcUninitializeCacheMap(FileObject, &newlength, NULL)) 2174 TRACE("CcUninitializeCacheMap failed\n"); 2175 2176 ExReleaseResourceLite(fileref->fcb->Header.Resource); 2177 2178 return STATUS_SUCCESS; 2179 } 2180 2181 _Dispatch_type_(IRP_MJ_CLEANUP) 2182 _Function_class_(DRIVER_DISPATCH) 2183 #ifdef __REACTOS__ 2184 static NTSTATUS NTAPI drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 2185 #else 2186 static NTSTATUS drv_cleanup(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 2187 #endif 2188 NTSTATUS Status; 2189 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 2190 PFILE_OBJECT FileObject = IrpSp->FileObject; 2191 device_extension* Vcb = DeviceObject->DeviceExtension; 2192 fcb* fcb = FileObject->FsContext; 2193 BOOL top_level; 2194 2195 FsRtlEnterFileSystem(); 2196 2197 TRACE("cleanup\n"); 2198 2199 top_level = is_top_level(Irp); 2200 2201 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 2202 Status = vol_cleanup(DeviceObject, Irp); 2203 goto exit; 2204 } else if (DeviceObject == master_devobj) { 2205 TRACE("closing file system\n"); 2206 Status = STATUS_SUCCESS; 2207 goto exit; 2208 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) { 2209 Status = STATUS_INVALID_PARAMETER; 2210 goto exit; 2211 } 2212 2213 if (FileObject->Flags & FO_CLEANUP_COMPLETE) { 2214 TRACE("FileObject %p already cleaned up\n", FileObject); 2215 Status = STATUS_SUCCESS; 2216 goto exit; 2217 } 2218 2219 if (!fcb) { 2220 ERR("fcb was NULL\n"); 2221 Status = STATUS_INVALID_PARAMETER; 2222 goto exit; 2223 } 2224 2225 // We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup 2226 // messages belonging to other devices. 2227 2228 if (FileObject && FileObject->FsContext) { 2229 LONG oc; 2230 ccb* ccb; 2231 file_ref* fileref; 2232 BOOL locked = TRUE; 2233 2234 ccb = FileObject->FsContext2; 2235 fileref = ccb ? ccb->fileref : NULL; 2236 2237 TRACE("cleanup called for FileObject %p\n", FileObject); 2238 TRACE("fileref %p (%S), refcount = %u, open_count = %u\n", fileref, file_desc(FileObject), fileref ? fileref->refcount : 0, fileref ? fileref->open_count : 0); 2239 2240 ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE); 2241 2242 ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE); 2243 2244 IoRemoveShareAccess(FileObject, &fcb->share_access); 2245 2246 if (ccb) 2247 FsRtlNotifyCleanup(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, ccb); 2248 2249 if (fileref) { 2250 oc = InterlockedDecrement(&fileref->open_count); 2251 #ifdef DEBUG_FCB_REFCOUNTS 2252 ERR("fileref %p: open_count now %i\n", fileref, oc); 2253 #endif 2254 } 2255 2256 if (ccb && ccb->options & FILE_DELETE_ON_CLOSE && fileref) 2257 fileref->delete_on_close = TRUE; 2258 2259 if (fileref && fileref->delete_on_close && fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0 && fcb != fcb->Vcb->dummy_fcb) 2260 fileref->delete_on_close = FALSE; 2261 2262 if (fcb->Vcb->locked && fcb->Vcb->locked_fileobj == FileObject) { 2263 TRACE("unlocking volume\n"); 2264 do_unlock_volume(fcb->Vcb); 2265 FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK); 2266 } 2267 2268 if (ccb && ccb->reserving) { 2269 fcb->subvol->reserved = NULL; 2270 ccb->reserving = FALSE; 2271 // FIXME - flush all of subvol's fcbs 2272 } 2273 2274 if (fileref && oc == 0) { 2275 if (!fcb->Vcb->removing) { 2276 if (fileref && fileref->delete_on_close && fileref != fcb->Vcb->root_fileref && fcb != fcb->Vcb->volume_fcb) { 2277 LIST_ENTRY rollback; 2278 2279 InitializeListHead(&rollback); 2280 2281 if (!fileref->fcb->ads || fileref->dc) { 2282 if (fileref->fcb->ads) { 2283 send_notification_fileref(fileref->parent, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, 2284 FILE_ACTION_REMOVED, &fileref->dc->name); 2285 } else 2286 send_notification_fileref(fileref, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED, NULL); 2287 } 2288 2289 ExReleaseResourceLite(fcb->Header.Resource); 2290 locked = FALSE; 2291 2292 // fileref_lock needs to be acquired before fcb->Header.Resource 2293 ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE); 2294 2295 Status = delete_fileref(fileref, FileObject, Irp, &rollback); 2296 if (!NT_SUCCESS(Status)) { 2297 ERR("delete_fileref returned %08x\n", Status); 2298 do_rollback(fcb->Vcb, &rollback); 2299 ExReleaseResourceLite(&fcb->Vcb->fileref_lock); 2300 ExReleaseResourceLite(&fcb->Vcb->tree_lock); 2301 goto exit; 2302 } 2303 2304 ExReleaseResourceLite(&fcb->Vcb->fileref_lock); 2305 2306 clear_rollback(&rollback); 2307 } else if (FileObject->Flags & FO_CACHE_SUPPORTED && fcb->nonpaged->segment_object.DataSectionObject) { 2308 IO_STATUS_BLOCK iosb; 2309 CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb); 2310 2311 if (!NT_SUCCESS(iosb.Status)) { 2312 ERR("CcFlushCache returned %08x\n", iosb.Status); 2313 } 2314 2315 if (!ExIsResourceAcquiredSharedLite(fcb->Header.PagingIoResource)) { 2316 ExAcquireResourceExclusiveLite(fcb->Header.PagingIoResource, TRUE); 2317 ExReleaseResourceLite(fcb->Header.PagingIoResource); 2318 } 2319 2320 CcPurgeCacheSection(&fcb->nonpaged->segment_object, NULL, 0, FALSE); 2321 2322 TRACE("flushed cache on close (FileObject = %p, fcb = %p, AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx)\n", 2323 FileObject, fcb, fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart); 2324 } 2325 } 2326 2327 if (fcb->Vcb && fcb != fcb->Vcb->volume_fcb) 2328 CcUninitializeCacheMap(FileObject, NULL, NULL); 2329 } 2330 2331 if (locked) 2332 ExReleaseResourceLite(fcb->Header.Resource); 2333 2334 ExReleaseResourceLite(&fcb->Vcb->tree_lock); 2335 2336 FileObject->Flags |= FO_CLEANUP_COMPLETE; 2337 } 2338 2339 Status = STATUS_SUCCESS; 2340 2341 exit: 2342 TRACE("returning %08x\n", Status); 2343 2344 Irp->IoStatus.Status = Status; 2345 Irp->IoStatus.Information = 0; 2346 2347 IoCompleteRequest(Irp, IO_NO_INCREMENT); 2348 2349 if (top_level) 2350 IoSetTopLevelIrp(NULL); 2351 2352 FsRtlExitFileSystem(); 2353 2354 return Status; 2355 } 2356 2357 _Success_(return) 2358 BOOL get_file_attributes_from_xattr(_In_reads_bytes_(len) char* val, _In_ UINT16 len, _Out_ ULONG* atts) { 2359 if (len > 2 && val[0] == '0' && val[1] == 'x') { 2360 int i; 2361 ULONG dosnum = 0; 2362 2363 for (i = 2; i < len; i++) { 2364 dosnum *= 0x10; 2365 2366 if (val[i] >= '0' && val[i] <= '9') 2367 dosnum |= val[i] - '0'; 2368 else if (val[i] >= 'a' && val[i] <= 'f') 2369 dosnum |= val[i] + 10 - 'a'; 2370 else if (val[i] >= 'A' && val[i] <= 'F') 2371 dosnum |= val[i] + 10 - 'a'; 2372 } 2373 2374 TRACE("DOSATTRIB: %08x\n", dosnum); 2375 2376 *atts = dosnum; 2377 2378 return TRUE; 2379 } 2380 2381 return FALSE; 2382 } 2383 2384 ULONG get_file_attributes(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ root* r, _In_ UINT64 inode, 2385 _In_ UINT8 type, _In_ BOOL dotfile, _In_ BOOL ignore_xa, _In_opt_ PIRP Irp) { 2386 ULONG att; 2387 char* eaval; 2388 UINT16 ealen; 2389 2390 if (!ignore_xa && get_xattr(Vcb, r, inode, EA_DOSATTRIB, EA_DOSATTRIB_HASH, (UINT8**)&eaval, &ealen, Irp)) { 2391 ULONG dosnum = 0; 2392 2393 if (get_file_attributes_from_xattr(eaval, ealen, &dosnum)) { 2394 ExFreePool(eaval); 2395 2396 if (type == BTRFS_TYPE_DIRECTORY) 2397 dosnum |= FILE_ATTRIBUTE_DIRECTORY; 2398 else if (type == BTRFS_TYPE_SYMLINK) 2399 dosnum |= FILE_ATTRIBUTE_REPARSE_POINT; 2400 2401 if (type != BTRFS_TYPE_DIRECTORY) 2402 dosnum &= ~FILE_ATTRIBUTE_DIRECTORY; 2403 2404 if (inode == SUBVOL_ROOT_INODE) { 2405 if (r->root_item.flags & BTRFS_SUBVOL_READONLY) 2406 dosnum |= FILE_ATTRIBUTE_READONLY; 2407 else 2408 dosnum &= ~FILE_ATTRIBUTE_READONLY; 2409 } 2410 2411 return dosnum; 2412 } 2413 2414 ExFreePool(eaval); 2415 } 2416 2417 switch (type) { 2418 case BTRFS_TYPE_DIRECTORY: 2419 att = FILE_ATTRIBUTE_DIRECTORY; 2420 break; 2421 2422 case BTRFS_TYPE_SYMLINK: 2423 att = FILE_ATTRIBUTE_REPARSE_POINT; 2424 break; 2425 2426 default: 2427 att = 0; 2428 break; 2429 } 2430 2431 if (dotfile) { 2432 att |= FILE_ATTRIBUTE_HIDDEN; 2433 } 2434 2435 att |= FILE_ATTRIBUTE_ARCHIVE; 2436 2437 if (inode == SUBVOL_ROOT_INODE) { 2438 if (r->root_item.flags & BTRFS_SUBVOL_READONLY) 2439 att |= FILE_ATTRIBUTE_READONLY; 2440 else 2441 att &= ~FILE_ATTRIBUTE_READONLY; 2442 } 2443 2444 // FIXME - get READONLY from ii->st_mode 2445 // FIXME - return SYSTEM for block/char devices? 2446 2447 if (att == 0) 2448 att = FILE_ATTRIBUTE_NORMAL; 2449 2450 return att; 2451 } 2452 2453 NTSTATUS sync_read_phys(_In_ PDEVICE_OBJECT DeviceObject, _In_ UINT64 StartingOffset, _In_ ULONG Length, 2454 _Out_writes_bytes_(Length) PUCHAR Buffer, _In_ BOOL override) { 2455 IO_STATUS_BLOCK IoStatus; 2456 LARGE_INTEGER Offset; 2457 PIRP Irp; 2458 PIO_STACK_LOCATION IrpSp; 2459 NTSTATUS Status; 2460 read_context context; 2461 2462 num_reads++; 2463 2464 RtlZeroMemory(&context, sizeof(read_context)); 2465 KeInitializeEvent(&context.Event, NotificationEvent, FALSE); 2466 2467 Offset.QuadPart = (LONGLONG)StartingOffset; 2468 2469 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); 2470 2471 if (!Irp) { 2472 ERR("IoAllocateIrp failed\n"); 2473 return STATUS_INSUFFICIENT_RESOURCES; 2474 } 2475 2476 Irp->Flags |= IRP_NOCACHE; 2477 IrpSp = IoGetNextIrpStackLocation(Irp); 2478 IrpSp->MajorFunction = IRP_MJ_READ; 2479 2480 if (override) 2481 IrpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2482 2483 if (DeviceObject->Flags & DO_BUFFERED_IO) { 2484 Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool, Length, ALLOC_TAG); 2485 if (!Irp->AssociatedIrp.SystemBuffer) { 2486 ERR("out of memory\n"); 2487 Status = STATUS_INSUFFICIENT_RESOURCES; 2488 goto exit; 2489 } 2490 2491 Irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION; 2492 2493 Irp->UserBuffer = Buffer; 2494 } else if (DeviceObject->Flags & DO_DIRECT_IO) { 2495 Irp->MdlAddress = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL); 2496 if (!Irp->MdlAddress) { 2497 ERR("IoAllocateMdl failed\n"); 2498 Status = STATUS_INSUFFICIENT_RESOURCES; 2499 goto exit; 2500 } 2501 2502 Status = STATUS_SUCCESS; 2503 2504 _SEH2_TRY { 2505 MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoWriteAccess); 2506 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 2507 Status = _SEH2_GetExceptionCode(); 2508 } _SEH2_END; 2509 2510 if (!NT_SUCCESS(Status)) { 2511 ERR("MmProbeAndLockPages threw exception %08x\n", Status); 2512 IoFreeMdl(Irp->MdlAddress); 2513 goto exit; 2514 } 2515 } else 2516 Irp->UserBuffer = Buffer; 2517 2518 IrpSp->Parameters.Read.Length = Length; 2519 IrpSp->Parameters.Read.ByteOffset = Offset; 2520 2521 Irp->UserIosb = &IoStatus; 2522 2523 Irp->UserEvent = &context.Event; 2524 2525 IoSetCompletionRoutine(Irp, read_completion, &context, TRUE, TRUE, TRUE); 2526 2527 Status = IoCallDriver(DeviceObject, Irp); 2528 2529 if (Status == STATUS_PENDING) { 2530 KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL); 2531 Status = context.iosb.Status; 2532 } 2533 2534 if (DeviceObject->Flags & DO_DIRECT_IO) { 2535 MmUnlockPages(Irp->MdlAddress); 2536 IoFreeMdl(Irp->MdlAddress); 2537 } 2538 2539 exit: 2540 IoFreeIrp(Irp); 2541 2542 return Status; 2543 } 2544 2545 static NTSTATUS read_superblock(_In_ device_extension* Vcb, _In_ PDEVICE_OBJECT device, _In_ UINT64 length) { 2546 NTSTATUS Status; 2547 superblock* sb; 2548 ULONG i, to_read; 2549 UINT8 valid_superblocks; 2550 2551 to_read = device->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), device->SectorSize); 2552 2553 sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG); 2554 if (!sb) { 2555 ERR("out of memory\n"); 2556 return STATUS_INSUFFICIENT_RESOURCES; 2557 } 2558 2559 if (superblock_addrs[0] + to_read > length) { 2560 WARN("device was too short to have any superblock\n"); 2561 ExFreePool(sb); 2562 return STATUS_UNRECOGNIZED_VOLUME; 2563 } 2564 2565 i = 0; 2566 valid_superblocks = 0; 2567 2568 while (superblock_addrs[i] > 0) { 2569 UINT32 crc32; 2570 2571 if (i > 0 && superblock_addrs[i] + to_read > length) 2572 break; 2573 2574 Status = sync_read_phys(device, superblock_addrs[i], to_read, (PUCHAR)sb, FALSE); 2575 if (!NT_SUCCESS(Status)) { 2576 ERR("Failed to read superblock %u: %08x\n", i, Status); 2577 ExFreePool(sb); 2578 return Status; 2579 } 2580 2581 if (sb->magic != BTRFS_MAGIC) { 2582 if (i == 0) { 2583 TRACE("not a BTRFS volume\n"); 2584 ExFreePool(sb); 2585 return STATUS_UNRECOGNIZED_VOLUME; 2586 } 2587 } else { 2588 TRACE("got superblock %u!\n", i); 2589 2590 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 2591 2592 if (crc32 != *((UINT32*)sb->checksum)) 2593 WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum)); 2594 else if (sb->sector_size == 0) 2595 WARN("superblock sector size was 0\n"); 2596 else if (sb->node_size < sizeof(tree_header) + sizeof(internal_node) || sb->node_size > 0x10000) 2597 WARN("invalid node size %x\n", sb->node_size); 2598 else if ((sb->node_size % sb->sector_size) != 0) 2599 WARN("node size %x was not a multiple of sector_size %x\n", sb->node_size, sb->sector_size); 2600 else if (valid_superblocks == 0 || sb->generation > Vcb->superblock.generation) { 2601 RtlCopyMemory(&Vcb->superblock, sb, sizeof(superblock)); 2602 valid_superblocks++; 2603 } 2604 } 2605 2606 i++; 2607 } 2608 2609 ExFreePool(sb); 2610 2611 if (valid_superblocks == 0) { 2612 ERR("could not find any valid superblocks\n"); 2613 return STATUS_INTERNAL_ERROR; 2614 } 2615 2616 TRACE("label is %s\n", Vcb->superblock.label); 2617 2618 return STATUS_SUCCESS; 2619 } 2620 2621 NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode, _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize, 2622 _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ BOOLEAN Override, _Out_opt_ IO_STATUS_BLOCK* iosb) { 2623 PIRP Irp; 2624 KEVENT Event; 2625 NTSTATUS Status; 2626 PIO_STACK_LOCATION IrpSp; 2627 IO_STATUS_BLOCK IoStatus; 2628 2629 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2630 2631 Irp = IoBuildDeviceIoControlRequest(ControlCode, 2632 DeviceObject, 2633 InputBuffer, 2634 InputBufferSize, 2635 OutputBuffer, 2636 OutputBufferSize, 2637 FALSE, 2638 &Event, 2639 &IoStatus); 2640 2641 if (!Irp) return STATUS_INSUFFICIENT_RESOURCES; 2642 2643 if (Override) { 2644 IrpSp = IoGetNextIrpStackLocation(Irp); 2645 IrpSp->Flags |= SL_OVERRIDE_VERIFY_VOLUME; 2646 } 2647 2648 Status = IoCallDriver(DeviceObject, Irp); 2649 2650 if (Status == STATUS_PENDING) { 2651 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 2652 Status = IoStatus.Status; 2653 } 2654 2655 if (iosb) 2656 *iosb = IoStatus; 2657 2658 return Status; 2659 } 2660 2661 _Requires_exclusive_lock_held_(Vcb->tree_lock) 2662 static NTSTATUS add_root(_Inout_ device_extension* Vcb, _In_ UINT64 id, _In_ UINT64 addr, 2663 _In_ UINT64 generation, _In_opt_ traverse_ptr* tp) { 2664 root* r = ExAllocatePoolWithTag(PagedPool, sizeof(root), ALLOC_TAG); 2665 if (!r) { 2666 ERR("out of memory\n"); 2667 return STATUS_INSUFFICIENT_RESOURCES; 2668 } 2669 2670 r->id = id; 2671 r->dirty = FALSE; 2672 r->received = FALSE; 2673 r->reserved = NULL; 2674 r->treeholder.address = addr; 2675 r->treeholder.tree = NULL; 2676 r->treeholder.generation = generation; 2677 r->parent = 0; 2678 r->send_ops = 0; 2679 r->fcbs_version = 0; 2680 InitializeListHead(&r->fcbs); 2681 RtlZeroMemory(r->fcbs_ptrs, sizeof(LIST_ENTRY*) * 256); 2682 2683 r->nonpaged = ExAllocatePoolWithTag(NonPagedPool, sizeof(root_nonpaged), ALLOC_TAG); 2684 if (!r->nonpaged) { 2685 ERR("out of memory\n"); 2686 ExFreePool(r); 2687 return STATUS_INSUFFICIENT_RESOURCES; 2688 } 2689 2690 ExInitializeResourceLite(&r->nonpaged->load_tree_lock); 2691 2692 r->lastinode = 0; 2693 2694 if (tp) { 2695 RtlCopyMemory(&r->root_item, tp->item->data, min(sizeof(ROOT_ITEM), tp->item->size)); 2696 if (tp->item->size < sizeof(ROOT_ITEM)) 2697 RtlZeroMemory(((UINT8*)&r->root_item) + tp->item->size, sizeof(ROOT_ITEM) - tp->item->size); 2698 } else 2699 RtlZeroMemory(&r->root_item, sizeof(ROOT_ITEM)); 2700 2701 if (!Vcb->readonly && (r->id == BTRFS_ROOT_ROOT || r->id == BTRFS_ROOT_FSTREE || (r->id >= 0x100 && !(r->id & 0xf000000000000000)))) { // FS tree root 2702 // FIXME - don't call this if subvol is readonly (though we will have to if we ever toggle this flag) 2703 get_last_inode(Vcb, r, NULL); 2704 2705 if (r->id == BTRFS_ROOT_ROOT && r->lastinode < 0x100) 2706 r->lastinode = 0x100; 2707 } 2708 2709 InsertTailList(&Vcb->roots, &r->list_entry); 2710 2711 switch (r->id) { 2712 case BTRFS_ROOT_ROOT: 2713 Vcb->root_root = r; 2714 break; 2715 2716 case BTRFS_ROOT_EXTENT: 2717 Vcb->extent_root = r; 2718 break; 2719 2720 case BTRFS_ROOT_CHUNK: 2721 Vcb->chunk_root = r; 2722 break; 2723 2724 case BTRFS_ROOT_DEVTREE: 2725 Vcb->dev_root = r; 2726 break; 2727 2728 case BTRFS_ROOT_CHECKSUM: 2729 Vcb->checksum_root = r; 2730 break; 2731 2732 case BTRFS_ROOT_UUID: 2733 Vcb->uuid_root = r; 2734 break; 2735 2736 case BTRFS_ROOT_FREE_SPACE: 2737 Vcb->space_root = r; 2738 break; 2739 2740 case BTRFS_ROOT_DATA_RELOC: 2741 Vcb->data_reloc_root = r; 2742 break; 2743 } 2744 2745 return STATUS_SUCCESS; 2746 } 2747 2748 static NTSTATUS look_for_roots(_Requires_exclusive_lock_held_(_Curr_->tree_lock) _In_ device_extension* Vcb, _In_opt_ PIRP Irp) { 2749 traverse_ptr tp, next_tp; 2750 KEY searchkey; 2751 BOOL b; 2752 NTSTATUS Status; 2753 2754 searchkey.obj_id = 0; 2755 searchkey.obj_type = 0; 2756 searchkey.offset = 0; 2757 2758 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp); 2759 if (!NT_SUCCESS(Status)) { 2760 ERR("error - find_item returned %08x\n", Status); 2761 return Status; 2762 } 2763 2764 do { 2765 TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset); 2766 2767 if (tp.item->key.obj_type == TYPE_ROOT_ITEM) { 2768 ROOT_ITEM* ri = (ROOT_ITEM*)tp.item->data; 2769 2770 if (tp.item->size < offsetof(ROOT_ITEM, byte_limit)) { 2771 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(ROOT_ITEM, byte_limit)); 2772 } else { 2773 TRACE("root %llx - address %llx\n", tp.item->key.obj_id, ri->block_number); 2774 2775 Status = add_root(Vcb, tp.item->key.obj_id, ri->block_number, ri->generation, &tp); 2776 if (!NT_SUCCESS(Status)) { 2777 ERR("add_root returned %08x\n", Status); 2778 return Status; 2779 } 2780 } 2781 } else if (tp.item->key.obj_type == TYPE_ROOT_BACKREF && !IsListEmpty(&Vcb->roots)) { 2782 root* lastroot = CONTAINING_RECORD(Vcb->roots.Blink, root, list_entry); 2783 2784 if (lastroot->id == tp.item->key.obj_id) 2785 lastroot->parent = tp.item->key.offset; 2786 } 2787 2788 b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp); 2789 2790 if (b) 2791 tp = next_tp; 2792 } while (b); 2793 2794 if (!Vcb->readonly && !Vcb->data_reloc_root) { 2795 root* reloc_root; 2796 INODE_ITEM* ii; 2797 UINT16 irlen; 2798 INODE_REF* ir; 2799 LARGE_INTEGER time; 2800 BTRFS_TIME now; 2801 2802 WARN("data reloc root doesn't exist, creating it\n"); 2803 2804 Status = create_root(Vcb, BTRFS_ROOT_DATA_RELOC, &reloc_root, FALSE, 0, Irp); 2805 2806 if (!NT_SUCCESS(Status)) { 2807 ERR("create_root returned %08x\n", Status); 2808 return Status; 2809 } 2810 2811 reloc_root->root_item.inode.generation = 1; 2812 reloc_root->root_item.inode.st_size = 3; 2813 reloc_root->root_item.inode.st_blocks = Vcb->superblock.node_size; 2814 reloc_root->root_item.inode.st_nlink = 1; 2815 reloc_root->root_item.inode.st_mode = 040755; 2816 reloc_root->root_item.inode.flags = 0xffffffff80000000; 2817 reloc_root->root_item.objid = SUBVOL_ROOT_INODE; 2818 reloc_root->root_item.bytes_used = Vcb->superblock.node_size; 2819 2820 ii = ExAllocatePoolWithTag(PagedPool, sizeof(INODE_ITEM), ALLOC_TAG); 2821 if (!ii) { 2822 ERR("out of memory\n"); 2823 return STATUS_INSUFFICIENT_RESOURCES; 2824 } 2825 2826 KeQuerySystemTime(&time); 2827 win_time_to_unix(time, &now); 2828 2829 RtlZeroMemory(ii, sizeof(INODE_ITEM)); 2830 ii->generation = Vcb->superblock.generation; 2831 ii->st_blocks = Vcb->superblock.node_size; 2832 ii->st_nlink = 1; 2833 ii->st_mode = 040755; 2834 ii->st_atime = now; 2835 ii->st_ctime = now; 2836 ii->st_mtime = now; 2837 2838 Status = insert_tree_item(Vcb, reloc_root, SUBVOL_ROOT_INODE, TYPE_INODE_ITEM, 0, ii, sizeof(INODE_ITEM), NULL, Irp); 2839 if (!NT_SUCCESS(Status)) { 2840 ERR("insert_tree_item returned %08x\n", Status); 2841 ExFreePool(ii); 2842 return Status; 2843 } 2844 2845 irlen = (UINT16)offsetof(INODE_REF, name[0]) + 2; 2846 ir = ExAllocatePoolWithTag(PagedPool, irlen, ALLOC_TAG); 2847 if (!ir) { 2848 ERR("out of memory\n"); 2849 return STATUS_INSUFFICIENT_RESOURCES; 2850 } 2851 2852 ir->index = 0; 2853 ir->n = 2; 2854 ir->name[0] = '.'; 2855 ir->name[1] = '.'; 2856 2857 Status = insert_tree_item(Vcb, reloc_root, SUBVOL_ROOT_INODE, TYPE_INODE_REF, SUBVOL_ROOT_INODE, ir, irlen, NULL, Irp); 2858 if (!NT_SUCCESS(Status)) { 2859 ERR("insert_tree_item returned %08x\n", Status); 2860 ExFreePool(ir); 2861 return Status; 2862 } 2863 2864 Vcb->data_reloc_root = reloc_root; 2865 Vcb->need_write = TRUE; 2866 } 2867 2868 return STATUS_SUCCESS; 2869 } 2870 2871 static NTSTATUS find_disk_holes(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_ device* dev, _In_opt_ PIRP Irp) { 2872 KEY searchkey; 2873 traverse_ptr tp, next_tp; 2874 BOOL b; 2875 UINT64 lastaddr; 2876 NTSTATUS Status; 2877 2878 InitializeListHead(&dev->space); 2879 2880 searchkey.obj_id = 0; 2881 searchkey.obj_type = TYPE_DEV_STATS; 2882 searchkey.offset = dev->devitem.dev_id; 2883 2884 Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp); 2885 if (NT_SUCCESS(Status) && !keycmp(tp.item->key, searchkey)) 2886 RtlCopyMemory(dev->stats, tp.item->data, min(sizeof(UINT64) * 5, tp.item->size)); 2887 2888 searchkey.obj_id = dev->devitem.dev_id; 2889 searchkey.obj_type = TYPE_DEV_EXTENT; 2890 searchkey.offset = 0; 2891 2892 Status = find_item(Vcb, Vcb->dev_root, &tp, &searchkey, FALSE, Irp); 2893 if (!NT_SUCCESS(Status)) { 2894 ERR("error - find_item returned %08x\n", Status); 2895 return Status; 2896 } 2897 2898 lastaddr = 0; 2899 2900 do { 2901 if (tp.item->key.obj_id == dev->devitem.dev_id && tp.item->key.obj_type == TYPE_DEV_EXTENT) { 2902 if (tp.item->size >= sizeof(DEV_EXTENT)) { 2903 DEV_EXTENT* de = (DEV_EXTENT*)tp.item->data; 2904 2905 if (tp.item->key.offset > lastaddr) { 2906 Status = add_space_entry(&dev->space, NULL, lastaddr, tp.item->key.offset - lastaddr); 2907 if (!NT_SUCCESS(Status)) { 2908 ERR("add_space_entry returned %08x\n", Status); 2909 return Status; 2910 } 2911 } 2912 2913 lastaddr = tp.item->key.offset + de->length; 2914 } else { 2915 ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DEV_EXTENT)); 2916 } 2917 } 2918 2919 b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp); 2920 2921 if (b) { 2922 tp = next_tp; 2923 if (tp.item->key.obj_id > searchkey.obj_id || tp.item->key.obj_type > searchkey.obj_type) 2924 break; 2925 } 2926 } while (b); 2927 2928 if (lastaddr < dev->devitem.num_bytes) { 2929 Status = add_space_entry(&dev->space, NULL, lastaddr, dev->devitem.num_bytes - lastaddr); 2930 if (!NT_SUCCESS(Status)) { 2931 ERR("add_space_entry returned %08x\n", Status); 2932 return Status; 2933 } 2934 } 2935 2936 // The Linux driver doesn't like to allocate chunks within the first megabyte of a device. 2937 2938 space_list_subtract2(&dev->space, NULL, 0, 0x100000, NULL, NULL); 2939 2940 return STATUS_SUCCESS; 2941 } 2942 2943 static void add_device_to_list(_In_ device_extension* Vcb, _In_ device* dev) { 2944 LIST_ENTRY* le; 2945 2946 le = Vcb->devices.Flink; 2947 2948 while (le != &Vcb->devices) { 2949 device* dev2 = CONTAINING_RECORD(le, device, list_entry); 2950 2951 if (dev2->devitem.dev_id > dev->devitem.dev_id) { 2952 InsertHeadList(le->Blink, &dev->list_entry); 2953 return; 2954 } 2955 2956 le = le->Flink; 2957 } 2958 2959 InsertTailList(&Vcb->devices, &dev->list_entry); 2960 } 2961 2962 _Ret_maybenull_ 2963 device* find_device_from_uuid(_In_ device_extension* Vcb, _In_ BTRFS_UUID* uuid) { 2964 volume_device_extension* vde; 2965 pdo_device_extension* pdode; 2966 LIST_ENTRY* le; 2967 2968 le = Vcb->devices.Flink; 2969 while (le != &Vcb->devices) { 2970 device* dev = CONTAINING_RECORD(le, device, list_entry); 2971 2972 TRACE("device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", dev->devitem.dev_id, 2973 dev->devitem.device_uuid.uuid[0], dev->devitem.device_uuid.uuid[1], dev->devitem.device_uuid.uuid[2], dev->devitem.device_uuid.uuid[3], dev->devitem.device_uuid.uuid[4], dev->devitem.device_uuid.uuid[5], dev->devitem.device_uuid.uuid[6], dev->devitem.device_uuid.uuid[7], 2974 dev->devitem.device_uuid.uuid[8], dev->devitem.device_uuid.uuid[9], dev->devitem.device_uuid.uuid[10], dev->devitem.device_uuid.uuid[11], dev->devitem.device_uuid.uuid[12], dev->devitem.device_uuid.uuid[13], dev->devitem.device_uuid.uuid[14], dev->devitem.device_uuid.uuid[15]); 2975 2976 if (RtlCompareMemory(&dev->devitem.device_uuid, uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 2977 TRACE("returning device %llx\n", dev->devitem.dev_id); 2978 return dev; 2979 } 2980 2981 le = le->Flink; 2982 } 2983 2984 vde = Vcb->vde; 2985 2986 if (!vde) 2987 goto end; 2988 2989 pdode = vde->pdode; 2990 2991 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 2992 2993 if (Vcb->devices_loaded < Vcb->superblock.num_devices) { 2994 le = pdode->children.Flink; 2995 2996 while (le != &pdode->children) { 2997 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 2998 2999 if (RtlCompareMemory(uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 3000 device* dev; 3001 3002 dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device), ALLOC_TAG); 3003 if (!dev) { 3004 ExReleaseResourceLite(&pdode->child_lock); 3005 ERR("out of memory\n"); 3006 return NULL; 3007 } 3008 3009 RtlZeroMemory(dev, sizeof(device)); 3010 dev->devobj = vc->devobj; 3011 dev->devitem.device_uuid = *uuid; 3012 dev->devitem.dev_id = vc->devid; 3013 dev->devitem.num_bytes = vc->size; 3014 dev->seeding = vc->seeding; 3015 dev->readonly = dev->seeding; 3016 dev->reloc = FALSE; 3017 dev->removable = FALSE; 3018 dev->disk_num = vc->disk_num; 3019 dev->part_num = vc->part_num; 3020 dev->num_trim_entries = 0; 3021 InitializeListHead(&dev->trim_list); 3022 3023 add_device_to_list(Vcb, dev); 3024 Vcb->devices_loaded++; 3025 3026 ExReleaseResourceLite(&pdode->child_lock); 3027 3028 return dev; 3029 } 3030 3031 le = le->Flink; 3032 } 3033 } 3034 3035 ExReleaseResourceLite(&pdode->child_lock); 3036 3037 end: 3038 WARN("could not find device with uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", 3039 uuid->uuid[0], uuid->uuid[1], uuid->uuid[2], uuid->uuid[3], uuid->uuid[4], uuid->uuid[5], uuid->uuid[6], uuid->uuid[7], 3040 uuid->uuid[8], uuid->uuid[9], uuid->uuid[10], uuid->uuid[11], uuid->uuid[12], uuid->uuid[13], uuid->uuid[14], uuid->uuid[15]); 3041 3042 return NULL; 3043 } 3044 3045 static BOOL is_device_removable(_In_ PDEVICE_OBJECT devobj) { 3046 NTSTATUS Status; 3047 STORAGE_HOTPLUG_INFO shi; 3048 3049 Status = dev_ioctl(devobj, IOCTL_STORAGE_GET_HOTPLUG_INFO, NULL, 0, &shi, sizeof(STORAGE_HOTPLUG_INFO), TRUE, NULL); 3050 3051 if (!NT_SUCCESS(Status)) { 3052 ERR("dev_ioctl returned %08x\n", Status); 3053 return FALSE; 3054 } 3055 3056 return shi.MediaRemovable != 0 ? TRUE : FALSE; 3057 } 3058 3059 static ULONG get_device_change_count(_In_ PDEVICE_OBJECT devobj) { 3060 NTSTATUS Status; 3061 ULONG cc; 3062 IO_STATUS_BLOCK iosb; 3063 3064 Status = dev_ioctl(devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), TRUE, &iosb); 3065 3066 if (!NT_SUCCESS(Status)) { 3067 ERR("dev_ioctl returned %08x\n", Status); 3068 return 0; 3069 } 3070 3071 if (iosb.Information < sizeof(ULONG)) { 3072 ERR("iosb.Information was too short\n"); 3073 return 0; 3074 } 3075 3076 return cc; 3077 } 3078 3079 void init_device(_In_ device_extension* Vcb, _Inout_ device* dev, _In_ BOOL get_nums) { 3080 NTSTATUS Status; 3081 ULONG aptelen; 3082 ATA_PASS_THROUGH_EX* apte; 3083 STORAGE_PROPERTY_QUERY spq; 3084 DEVICE_TRIM_DESCRIPTOR dtd; 3085 3086 dev->removable = is_device_removable(dev->devobj); 3087 dev->change_count = dev->removable ? get_device_change_count(dev->devobj) : 0; 3088 3089 if (get_nums) { 3090 STORAGE_DEVICE_NUMBER sdn; 3091 3092 Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, 3093 &sdn, sizeof(STORAGE_DEVICE_NUMBER), TRUE, NULL); 3094 3095 if (!NT_SUCCESS(Status)) { 3096 WARN("IOCTL_STORAGE_GET_DEVICE_NUMBER returned %08x\n", Status); 3097 dev->disk_num = 0xffffffff; 3098 dev->part_num = 0xffffffff; 3099 } else { 3100 dev->disk_num = sdn.DeviceNumber; 3101 dev->part_num = sdn.PartitionNumber; 3102 } 3103 } 3104 3105 dev->trim = FALSE; 3106 dev->readonly = dev->seeding; 3107 dev->reloc = FALSE; 3108 dev->num_trim_entries = 0; 3109 dev->stats_changed = FALSE; 3110 InitializeListHead(&dev->trim_list); 3111 3112 if (!dev->readonly) { 3113 Status = dev_ioctl(dev->devobj, IOCTL_DISK_IS_WRITABLE, NULL, 0, 3114 NULL, 0, TRUE, NULL); 3115 if (Status == STATUS_MEDIA_WRITE_PROTECTED) 3116 dev->readonly = TRUE; 3117 } 3118 3119 aptelen = sizeof(ATA_PASS_THROUGH_EX) + 512; 3120 apte = ExAllocatePoolWithTag(NonPagedPool, aptelen, ALLOC_TAG); 3121 if (!apte) { 3122 ERR("out of memory\n"); 3123 return; 3124 } 3125 3126 RtlZeroMemory(apte, aptelen); 3127 3128 apte->Length = sizeof(ATA_PASS_THROUGH_EX); 3129 apte->AtaFlags = ATA_FLAGS_DATA_IN; 3130 apte->DataTransferLength = aptelen - sizeof(ATA_PASS_THROUGH_EX); 3131 apte->TimeOutValue = 3; 3132 apte->DataBufferOffset = apte->Length; 3133 apte->CurrentTaskFile[6] = IDE_COMMAND_IDENTIFY; 3134 3135 Status = dev_ioctl(dev->devobj, IOCTL_ATA_PASS_THROUGH, apte, aptelen, 3136 apte, aptelen, TRUE, NULL); 3137 3138 if (!NT_SUCCESS(Status)) 3139 TRACE("IOCTL_ATA_PASS_THROUGH returned %08x for IDENTIFY DEVICE\n", Status); 3140 else { 3141 IDENTIFY_DEVICE_DATA* idd = (IDENTIFY_DEVICE_DATA*)((UINT8*)apte + sizeof(ATA_PASS_THROUGH_EX)); 3142 3143 if (idd->CommandSetSupport.FlushCache) { 3144 dev->can_flush = TRUE; 3145 TRACE("FLUSH CACHE supported\n"); 3146 } else 3147 TRACE("FLUSH CACHE not supported\n"); 3148 } 3149 3150 ExFreePool(apte); 3151 3152 spq.PropertyId = StorageDeviceTrimProperty; 3153 spq.QueryType = PropertyStandardQuery; 3154 spq.AdditionalParameters[0] = 0; 3155 3156 Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(STORAGE_PROPERTY_QUERY), 3157 &dtd, sizeof(DEVICE_TRIM_DESCRIPTOR), TRUE, NULL); 3158 3159 if (NT_SUCCESS(Status)) { 3160 if (dtd.TrimEnabled) { 3161 dev->trim = TRUE; 3162 Vcb->trim = TRUE; 3163 TRACE("TRIM supported\n"); 3164 } else 3165 TRACE("TRIM not supported\n"); 3166 } 3167 3168 RtlZeroMemory(dev->stats, sizeof(UINT64) * 5); 3169 } 3170 3171 static NTSTATUS load_chunk_root(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { 3172 traverse_ptr tp, next_tp; 3173 KEY searchkey; 3174 BOOL b; 3175 chunk* c; 3176 NTSTATUS Status; 3177 3178 searchkey.obj_id = 0; 3179 searchkey.obj_type = 0; 3180 searchkey.offset = 0; 3181 3182 Vcb->data_flags = 0; 3183 Vcb->metadata_flags = 0; 3184 Vcb->system_flags = 0; 3185 3186 Status = find_item(Vcb, Vcb->chunk_root, &tp, &searchkey, FALSE, Irp); 3187 if (!NT_SUCCESS(Status)) { 3188 ERR("error - find_item returned %08x\n", Status); 3189 return Status; 3190 } 3191 3192 do { 3193 TRACE("(%llx,%x,%llx)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset); 3194 3195 if (tp.item->key.obj_id == 1 && tp.item->key.obj_type == TYPE_DEV_ITEM) { 3196 if (tp.item->size < sizeof(DEV_ITEM)) { 3197 ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DEV_ITEM)); 3198 } else { 3199 DEV_ITEM* di = (DEV_ITEM*)tp.item->data; 3200 LIST_ENTRY* le; 3201 BOOL done = FALSE; 3202 3203 le = Vcb->devices.Flink; 3204 while (le != &Vcb->devices) { 3205 device* dev = CONTAINING_RECORD(le, device, list_entry); 3206 3207 if (dev->devobj && RtlCompareMemory(&dev->devitem.device_uuid, &di->device_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 3208 RtlCopyMemory(&dev->devitem, tp.item->data, min(tp.item->size, sizeof(DEV_ITEM))); 3209 3210 if (le != Vcb->devices.Flink) 3211 init_device(Vcb, dev, TRUE); 3212 3213 done = TRUE; 3214 break; 3215 } 3216 3217 le = le->Flink; 3218 } 3219 3220 if (!done && Vcb->vde) { 3221 volume_device_extension* vde = Vcb->vde; 3222 pdo_device_extension* pdode = vde->pdode; 3223 3224 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 3225 3226 if (Vcb->devices_loaded < Vcb->superblock.num_devices) { 3227 le = pdode->children.Flink; 3228 3229 while (le != &pdode->children) { 3230 volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry); 3231 3232 if (RtlCompareMemory(&di->device_uuid, &vc->uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 3233 device* dev; 3234 3235 dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device), ALLOC_TAG); 3236 if (!dev) { 3237 ExReleaseResourceLite(&pdode->child_lock); 3238 ERR("out of memory\n"); 3239 return STATUS_INSUFFICIENT_RESOURCES; 3240 } 3241 3242 RtlZeroMemory(dev, sizeof(device)); 3243 3244 dev->devobj = vc->devobj; 3245 RtlCopyMemory(&dev->devitem, di, min(tp.item->size, sizeof(DEV_ITEM))); 3246 dev->seeding = vc->seeding; 3247 init_device(Vcb, dev, FALSE); 3248 3249 if (dev->devitem.num_bytes > vc->size) { 3250 WARN("device %llx: DEV_ITEM says %llx bytes, but Windows only reports %llx\n", tp.item->key.offset, 3251 dev->devitem.num_bytes, vc->size); 3252 3253 dev->devitem.num_bytes = vc->size; 3254 } 3255 3256 dev->disk_num = vc->disk_num; 3257 dev->part_num = vc->part_num; 3258 add_device_to_list(Vcb, dev); 3259 Vcb->devices_loaded++; 3260 3261 done = TRUE; 3262 break; 3263 } 3264 3265 le = le->Flink; 3266 } 3267 3268 if (!done) { 3269 if (!Vcb->options.allow_degraded) { 3270 ERR("volume not found: device %llx, uuid %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", tp.item->key.offset, 3271 di->device_uuid.uuid[0], di->device_uuid.uuid[1], di->device_uuid.uuid[2], di->device_uuid.uuid[3], di->device_uuid.uuid[4], di->device_uuid.uuid[5], di->device_uuid.uuid[6], di->device_uuid.uuid[7], 3272 di->device_uuid.uuid[8], di->device_uuid.uuid[9], di->device_uuid.uuid[10], di->device_uuid.uuid[11], di->device_uuid.uuid[12], di->device_uuid.uuid[13], di->device_uuid.uuid[14], di->device_uuid.uuid[15]); 3273 } else { 3274 device* dev; 3275 3276 dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device), ALLOC_TAG); 3277 if (!dev) { 3278 ExReleaseResourceLite(&pdode->child_lock); 3279 ERR("out of memory\n"); 3280 return STATUS_INSUFFICIENT_RESOURCES; 3281 } 3282 3283 RtlZeroMemory(dev, sizeof(device)); 3284 3285 // Missing device, so we keep dev->devobj as NULL 3286 RtlCopyMemory(&dev->devitem, di, min(tp.item->size, sizeof(DEV_ITEM))); 3287 InitializeListHead(&dev->trim_list); 3288 3289 add_device_to_list(Vcb, dev); 3290 Vcb->devices_loaded++; 3291 } 3292 } 3293 } else 3294 ERR("unexpected device %llx found\n", tp.item->key.offset); 3295 3296 ExReleaseResourceLite(&pdode->child_lock); 3297 } 3298 } 3299 } else if (tp.item->key.obj_type == TYPE_CHUNK_ITEM) { 3300 if (tp.item->size < sizeof(CHUNK_ITEM)) { 3301 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(CHUNK_ITEM)); 3302 } else { 3303 c = ExAllocatePoolWithTag(NonPagedPool, sizeof(chunk), ALLOC_TAG); 3304 3305 if (!c) { 3306 ERR("out of memory\n"); 3307 return STATUS_INSUFFICIENT_RESOURCES; 3308 } 3309 3310 c->size = tp.item->size; 3311 c->offset = tp.item->key.offset; 3312 c->used = c->oldused = 0; 3313 c->cache = c->old_cache = NULL; 3314 c->created = FALSE; 3315 c->readonly = FALSE; 3316 c->reloc = FALSE; 3317 c->cache_loaded = FALSE; 3318 c->changed = FALSE; 3319 c->space_changed = FALSE; 3320 c->balance_num = 0; 3321 3322 c->chunk_item = ExAllocatePoolWithTag(NonPagedPool, tp.item->size, ALLOC_TAG); 3323 3324 if (!c->chunk_item) { 3325 ERR("out of memory\n"); 3326 ExFreePool(c); 3327 return STATUS_INSUFFICIENT_RESOURCES; 3328 } 3329 3330 RtlCopyMemory(c->chunk_item, tp.item->data, tp.item->size); 3331 3332 if (c->chunk_item->type & BLOCK_FLAG_DATA && c->chunk_item->type > Vcb->data_flags) 3333 Vcb->data_flags = c->chunk_item->type; 3334 3335 if (c->chunk_item->type & BLOCK_FLAG_METADATA && c->chunk_item->type > Vcb->metadata_flags) 3336 Vcb->metadata_flags = c->chunk_item->type; 3337 3338 if (c->chunk_item->type & BLOCK_FLAG_SYSTEM && c->chunk_item->type > Vcb->system_flags) 3339 Vcb->system_flags = c->chunk_item->type; 3340 3341 if (c->chunk_item->type & BLOCK_FLAG_RAID10) { 3342 if (c->chunk_item->sub_stripes == 0 || c->chunk_item->sub_stripes > c->chunk_item->num_stripes) { 3343 ERR("chunk %llx: invalid stripes (num_stripes %u, sub_stripes %u)\n", c->offset, c->chunk_item->num_stripes, c->chunk_item->sub_stripes); 3344 ExFreePool(c->chunk_item); 3345 ExFreePool(c); 3346 return STATUS_INTERNAL_ERROR; 3347 } 3348 } 3349 3350 if (c->chunk_item->num_stripes > 0) { 3351 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1]; 3352 UINT16 i; 3353 3354 c->devices = ExAllocatePoolWithTag(NonPagedPool, sizeof(device*) * c->chunk_item->num_stripes, ALLOC_TAG); 3355 3356 if (!c->devices) { 3357 ERR("out of memory\n"); 3358 ExFreePool(c->chunk_item); 3359 ExFreePool(c); 3360 return STATUS_INSUFFICIENT_RESOURCES; 3361 } 3362 3363 for (i = 0; i < c->chunk_item->num_stripes; i++) { 3364 c->devices[i] = find_device_from_uuid(Vcb, &cis[i].dev_uuid); 3365 TRACE("device %llu = %p\n", i, c->devices[i]); 3366 3367 if (!c->devices[i]) { 3368 ERR("missing device\n"); 3369 ExFreePool(c->chunk_item); 3370 ExFreePool(c); 3371 return STATUS_INTERNAL_ERROR; 3372 } 3373 3374 if (c->devices[i]->readonly) 3375 c->readonly = TRUE; 3376 } 3377 } else { 3378 ERR("chunk %llx: number of stripes is 0\n", c->offset); 3379 ExFreePool(c->chunk_item); 3380 ExFreePool(c); 3381 return STATUS_INTERNAL_ERROR; 3382 } 3383 3384 ExInitializeResourceLite(&c->lock); 3385 ExInitializeResourceLite(&c->changed_extents_lock); 3386 3387 InitializeListHead(&c->space); 3388 InitializeListHead(&c->space_size); 3389 InitializeListHead(&c->deleting); 3390 InitializeListHead(&c->changed_extents); 3391 3392 InitializeListHead(&c->range_locks); 3393 ExInitializeResourceLite(&c->range_locks_lock); 3394 KeInitializeEvent(&c->range_locks_event, NotificationEvent, FALSE); 3395 3396 InitializeListHead(&c->partial_stripes); 3397 ExInitializeResourceLite(&c->partial_stripes_lock); 3398 3399 c->last_alloc_set = FALSE; 3400 3401 c->last_stripe = 0; 3402 3403 InsertTailList(&Vcb->chunks, &c->list_entry); 3404 3405 c->list_entry_balance.Flink = NULL; 3406 } 3407 } 3408 3409 b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp); 3410 3411 if (b) 3412 tp = next_tp; 3413 } while (b); 3414 3415 Vcb->log_to_phys_loaded = TRUE; 3416 3417 if (Vcb->data_flags == 0) 3418 Vcb->data_flags = BLOCK_FLAG_DATA | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID0 : 0); 3419 3420 if (Vcb->metadata_flags == 0) 3421 Vcb->metadata_flags = BLOCK_FLAG_METADATA | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE); 3422 3423 if (Vcb->system_flags == 0) 3424 Vcb->system_flags = BLOCK_FLAG_SYSTEM | (Vcb->superblock.num_devices > 1 ? BLOCK_FLAG_RAID1 : BLOCK_FLAG_DUPLICATE); 3425 3426 if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS) { 3427 Vcb->metadata_flags |= BLOCK_FLAG_DATA; 3428 Vcb->data_flags = Vcb->metadata_flags; 3429 } 3430 3431 return STATUS_SUCCESS; 3432 } 3433 3434 void protect_superblocks(_Inout_ chunk* c) { 3435 UINT16 i = 0, j; 3436 UINT64 off_start, off_end; 3437 3438 // The Linux driver also protects all the space before the first superblock. 3439 // I realize this confuses physical and logical addresses, but this is what btrfs-progs does - 3440 // evidently Linux assumes the chunk at 0 is always SINGLE. 3441 if (c->offset < superblock_addrs[0]) 3442 space_list_subtract(c, FALSE, c->offset, superblock_addrs[0] - c->offset, NULL); 3443 3444 while (superblock_addrs[i] != 0) { 3445 CHUNK_ITEM* ci = c->chunk_item; 3446 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&ci[1]; 3447 3448 if (ci->type & BLOCK_FLAG_RAID0 || ci->type & BLOCK_FLAG_RAID10) { 3449 for (j = 0; j < ci->num_stripes; j++) { 3450 UINT16 sub_stripes = max(ci->sub_stripes, 1); 3451 3452 if (cis[j].offset + (ci->size * ci->num_stripes / sub_stripes) > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) { 3453 #ifdef _DEBUG 3454 UINT64 startoff; 3455 UINT16 startoffstripe; 3456 #endif 3457 3458 TRACE("cut out superblock in chunk %llx\n", c->offset); 3459 3460 off_start = superblock_addrs[i] - cis[j].offset; 3461 off_start -= off_start % ci->stripe_length; 3462 off_start *= ci->num_stripes / sub_stripes; 3463 off_start += (j / sub_stripes) * ci->stripe_length; 3464 3465 off_end = off_start + ci->stripe_length; 3466 3467 #ifdef _DEBUG 3468 get_raid0_offset(off_start, ci->stripe_length, ci->num_stripes / sub_stripes, &startoff, &startoffstripe); 3469 TRACE("j = %u, startoffstripe = %u\n", j, startoffstripe); 3470 TRACE("startoff = %llx, superblock = %llx\n", startoff + cis[j].offset, superblock_addrs[i]); 3471 #endif 3472 3473 space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL); 3474 } 3475 } 3476 } else if (ci->type & BLOCK_FLAG_RAID5) { 3477 UINT64 stripe_size = ci->size / (ci->num_stripes - 1); 3478 3479 for (j = 0; j < ci->num_stripes; j++) { 3480 if (cis[j].offset + stripe_size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) { 3481 TRACE("cut out superblock in chunk %llx\n", c->offset); 3482 3483 off_start = superblock_addrs[i] - cis[j].offset; 3484 off_start -= off_start % ci->stripe_length; 3485 off_start *= ci->num_stripes - 1; 3486 3487 off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), ci->stripe_length); 3488 off_end *= ci->num_stripes - 1; 3489 3490 TRACE("cutting out %llx, size %llx\n", c->offset + off_start, off_end - off_start); 3491 3492 space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL); 3493 } 3494 } 3495 } else if (ci->type & BLOCK_FLAG_RAID6) { 3496 UINT64 stripe_size = ci->size / (ci->num_stripes - 2); 3497 3498 for (j = 0; j < ci->num_stripes; j++) { 3499 if (cis[j].offset + stripe_size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) { 3500 TRACE("cut out superblock in chunk %llx\n", c->offset); 3501 3502 off_start = superblock_addrs[i] - cis[j].offset; 3503 off_start -= off_start % ci->stripe_length; 3504 off_start *= ci->num_stripes - 2; 3505 3506 off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), ci->stripe_length); 3507 off_end *= ci->num_stripes - 2; 3508 3509 TRACE("cutting out %llx, size %llx\n", c->offset + off_start, off_end - off_start); 3510 3511 space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL); 3512 } 3513 } 3514 } else { // SINGLE, DUPLICATE, RAID1 3515 for (j = 0; j < ci->num_stripes; j++) { 3516 if (cis[j].offset + ci->size > superblock_addrs[i] && cis[j].offset <= superblock_addrs[i] + sizeof(superblock)) { 3517 TRACE("cut out superblock in chunk %llx\n", c->offset); 3518 3519 // The Linux driver protects the whole stripe in which the superblock lives 3520 3521 off_start = ((superblock_addrs[i] - cis[j].offset) / c->chunk_item->stripe_length) * c->chunk_item->stripe_length; 3522 off_end = sector_align(superblock_addrs[i] - cis[j].offset + sizeof(superblock), c->chunk_item->stripe_length); 3523 3524 space_list_subtract(c, FALSE, c->offset + off_start, off_end - off_start, NULL); 3525 } 3526 } 3527 } 3528 3529 i++; 3530 } 3531 } 3532 3533 NTSTATUS find_chunk_usage(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { 3534 LIST_ENTRY* le = Vcb->chunks.Flink; 3535 chunk* c; 3536 KEY searchkey; 3537 traverse_ptr tp; 3538 BLOCK_GROUP_ITEM* bgi; 3539 NTSTATUS Status; 3540 3541 searchkey.obj_type = TYPE_BLOCK_GROUP_ITEM; 3542 3543 while (le != &Vcb->chunks) { 3544 c = CONTAINING_RECORD(le, chunk, list_entry); 3545 3546 searchkey.obj_id = c->offset; 3547 searchkey.offset = c->chunk_item->size; 3548 3549 Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE, Irp); 3550 if (!NT_SUCCESS(Status)) { 3551 ERR("error - find_item returned %08x\n", Status); 3552 return Status; 3553 } 3554 3555 if (!keycmp(searchkey, tp.item->key)) { 3556 if (tp.item->size >= sizeof(BLOCK_GROUP_ITEM)) { 3557 bgi = (BLOCK_GROUP_ITEM*)tp.item->data; 3558 3559 c->used = c->oldused = bgi->used; 3560 3561 TRACE("chunk %llx has %llx bytes used\n", c->offset, c->used); 3562 } else { 3563 ERR("(%llx;%llx,%x,%llx) is %u bytes, expected %u\n", 3564 Vcb->extent_root->id, tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(BLOCK_GROUP_ITEM)); 3565 } 3566 } 3567 3568 le = le->Flink; 3569 } 3570 3571 Vcb->chunk_usage_found = TRUE; 3572 3573 return STATUS_SUCCESS; 3574 } 3575 3576 static NTSTATUS load_sys_chunks(_In_ device_extension* Vcb) { 3577 KEY key; 3578 ULONG n = Vcb->superblock.n; 3579 3580 while (n > 0) { 3581 if (n > sizeof(KEY)) { 3582 RtlCopyMemory(&key, &Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n], sizeof(KEY)); 3583 n -= sizeof(KEY); 3584 } else 3585 return STATUS_SUCCESS; 3586 3587 TRACE("bootstrap: %llx,%x,%llx\n", key.obj_id, key.obj_type, key.offset); 3588 3589 if (key.obj_type == TYPE_CHUNK_ITEM) { 3590 CHUNK_ITEM* ci; 3591 USHORT cisize; 3592 sys_chunk* sc; 3593 3594 if (n < sizeof(CHUNK_ITEM)) 3595 return STATUS_SUCCESS; 3596 3597 ci = (CHUNK_ITEM*)&Vcb->superblock.sys_chunk_array[Vcb->superblock.n - n]; 3598 cisize = sizeof(CHUNK_ITEM) + (ci->num_stripes * sizeof(CHUNK_ITEM_STRIPE)); 3599 3600 if (n < cisize) 3601 return STATUS_SUCCESS; 3602 3603 sc = ExAllocatePoolWithTag(PagedPool, sizeof(sys_chunk), ALLOC_TAG); 3604 3605 if (!sc) { 3606 ERR("out of memory\n"); 3607 return STATUS_INSUFFICIENT_RESOURCES; 3608 } 3609 3610 sc->key = key; 3611 sc->size = cisize; 3612 sc->data = ExAllocatePoolWithTag(PagedPool, sc->size, ALLOC_TAG); 3613 3614 if (!sc->data) { 3615 ERR("out of memory\n"); 3616 ExFreePool(sc); 3617 return STATUS_INSUFFICIENT_RESOURCES; 3618 } 3619 3620 RtlCopyMemory(sc->data, ci, sc->size); 3621 InsertTailList(&Vcb->sys_chunks, &sc->list_entry); 3622 3623 n -= cisize; 3624 } else { 3625 ERR("unexpected item %llx,%x,%llx in bootstrap\n", key.obj_id, key.obj_type, key.offset); 3626 return STATUS_INTERNAL_ERROR; 3627 } 3628 } 3629 3630 return STATUS_SUCCESS; 3631 } 3632 3633 _Ret_maybenull_ 3634 static root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, _In_opt_ PIRP Irp) { 3635 LIST_ENTRY* le; 3636 3637 static const char fn[] = "default"; 3638 static UINT32 crc32 = 0x8dbfc2d2; 3639 3640 if (Vcb->options.subvol_id != 0) { 3641 le = Vcb->roots.Flink; 3642 while (le != &Vcb->roots) { 3643 root* r = CONTAINING_RECORD(le, root, list_entry); 3644 3645 if (r->id == Vcb->options.subvol_id) 3646 return r; 3647 3648 le = le->Flink; 3649 } 3650 } 3651 3652 if (Vcb->superblock.incompat_flags & BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL) { 3653 NTSTATUS Status; 3654 KEY searchkey; 3655 traverse_ptr tp; 3656 DIR_ITEM* di; 3657 3658 searchkey.obj_id = Vcb->superblock.root_dir_objectid; 3659 searchkey.obj_type = TYPE_DIR_ITEM; 3660 searchkey.offset = crc32; 3661 3662 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, FALSE, Irp); 3663 if (!NT_SUCCESS(Status)) { 3664 ERR("error - find_item returned %08x\n", Status); 3665 goto end; 3666 } 3667 3668 if (keycmp(tp.item->key, searchkey)) { 3669 ERR("could not find (%llx,%x,%llx) in root tree\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset); 3670 goto end; 3671 } 3672 3673 if (tp.item->size < sizeof(DIR_ITEM)) { 3674 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM)); 3675 goto end; 3676 } 3677 3678 di = (DIR_ITEM*)tp.item->data; 3679 3680 if (tp.item->size < sizeof(DIR_ITEM) - 1 + di->n) { 3681 ERR("(%llx,%x,%llx) was %u bytes, expected %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM) - 1 + di->n); 3682 goto end; 3683 } 3684 3685 if (di->n != strlen(fn) || RtlCompareMemory(di->name, fn, di->n) != di->n) { 3686 ERR("root DIR_ITEM had same CRC32, but was not \"default\"\n"); 3687 goto end; 3688 } 3689 3690 if (di->key.obj_type != TYPE_ROOT_ITEM) { 3691 ERR("default root has key (%llx,%x,%llx), expected subvolume\n", di->key.obj_id, di->key.obj_type, di->key.offset); 3692 goto end; 3693 } 3694 3695 le = Vcb->roots.Flink; 3696 while (le != &Vcb->roots) { 3697 root* r = CONTAINING_RECORD(le, root, list_entry); 3698 3699 if (r->id == di->key.obj_id) 3700 return r; 3701 3702 le = le->Flink; 3703 } 3704 3705 ERR("could not find root %llx, using default instead\n", di->key.obj_id); 3706 } 3707 3708 end: 3709 le = Vcb->roots.Flink; 3710 while (le != &Vcb->roots) { 3711 root* r = CONTAINING_RECORD(le, root, list_entry); 3712 3713 if (r->id == BTRFS_ROOT_FSTREE) 3714 return r; 3715 3716 le = le->Flink; 3717 } 3718 3719 return NULL; 3720 } 3721 3722 void init_file_cache(_In_ PFILE_OBJECT FileObject, _In_ CC_FILE_SIZES* ccfs) { 3723 TRACE("(%p, %p)\n", FileObject, ccfs); 3724 3725 CcInitializeCacheMap(FileObject, ccfs, FALSE, cache_callbacks, FileObject); 3726 3727 if (diskacc) 3728 fCcSetAdditionalCacheAttributesEx(FileObject, CC_ENABLE_DISK_IO_ACCOUNTING); 3729 3730 CcSetReadAheadGranularity(FileObject, READ_AHEAD_GRANULARITY); 3731 } 3732 3733 static NTSTATUS create_calc_threads(_In_ PDEVICE_OBJECT DeviceObject) { 3734 device_extension* Vcb = DeviceObject->DeviceExtension; 3735 ULONG i; 3736 3737 Vcb->calcthreads.num_threads = KeQueryActiveProcessorCount(NULL); 3738 3739 Vcb->calcthreads.threads = ExAllocatePoolWithTag(NonPagedPool, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads, ALLOC_TAG); 3740 if (!Vcb->calcthreads.threads) { 3741 ERR("out of memory\n"); 3742 return STATUS_INSUFFICIENT_RESOURCES; 3743 } 3744 3745 InitializeListHead(&Vcb->calcthreads.job_list); 3746 ExInitializeResourceLite(&Vcb->calcthreads.lock); 3747 KeInitializeEvent(&Vcb->calcthreads.event, NotificationEvent, FALSE); 3748 3749 RtlZeroMemory(Vcb->calcthreads.threads, sizeof(drv_calc_thread) * Vcb->calcthreads.num_threads); 3750 3751 for (i = 0; i < Vcb->calcthreads.num_threads; i++) { 3752 NTSTATUS Status; 3753 3754 Vcb->calcthreads.threads[i].DeviceObject = DeviceObject; 3755 KeInitializeEvent(&Vcb->calcthreads.threads[i].finished, NotificationEvent, FALSE); 3756 3757 Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0, NULL, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]); 3758 if (!NT_SUCCESS(Status)) { 3759 ULONG j; 3760 3761 ERR("PsCreateSystemThread returned %08x\n", Status); 3762 3763 for (j = 0; j < i; j++) { 3764 Vcb->calcthreads.threads[i].quit = TRUE; 3765 } 3766 3767 KeSetEvent(&Vcb->calcthreads.event, 0, FALSE); 3768 3769 return Status; 3770 } 3771 } 3772 3773 return STATUS_SUCCESS; 3774 } 3775 3776 static BOOL is_btrfs_volume(_In_ PDEVICE_OBJECT DeviceObject) { 3777 NTSTATUS Status; 3778 MOUNTDEV_NAME mdn, *mdn2; 3779 ULONG mdnsize; 3780 3781 Status = dev_ioctl(DeviceObject, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &mdn, sizeof(MOUNTDEV_NAME), TRUE, NULL); 3782 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { 3783 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status); 3784 return FALSE; 3785 } 3786 3787 mdnsize = (ULONG)offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength; 3788 3789 mdn2 = ExAllocatePoolWithTag(PagedPool, mdnsize, ALLOC_TAG); 3790 if (!mdn2) { 3791 ERR("out of memory\n"); 3792 return FALSE; 3793 } 3794 3795 Status = dev_ioctl(DeviceObject, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, mdn2, mdnsize, TRUE, NULL); 3796 if (!NT_SUCCESS(Status)) { 3797 ERR("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME returned %08x\n", Status); 3798 ExFreePool(mdn2); 3799 return FALSE; 3800 } 3801 3802 if (mdn2->NameLength > (sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) && 3803 RtlCompareMemory(mdn2->Name, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) == sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) { 3804 ExFreePool(mdn2); 3805 return TRUE; 3806 } 3807 3808 ExFreePool(mdn2); 3809 3810 return FALSE; 3811 } 3812 3813 static NTSTATUS get_device_pnp_name_guid(_In_ PDEVICE_OBJECT DeviceObject, _Out_ PUNICODE_STRING pnp_name, _In_ const GUID* guid) { 3814 NTSTATUS Status; 3815 WCHAR *list = NULL, *s; 3816 3817 Status = IoGetDeviceInterfaces((PVOID)guid, NULL, 0, &list); 3818 if (!NT_SUCCESS(Status)) { 3819 ERR("IoGetDeviceInterfaces returned %08x\n", Status); 3820 return Status; 3821 } 3822 3823 s = list; 3824 while (s[0] != 0) { 3825 PFILE_OBJECT FileObject; 3826 PDEVICE_OBJECT devobj; 3827 UNICODE_STRING name; 3828 3829 name.Length = name.MaximumLength = (USHORT)wcslen(s) * sizeof(WCHAR); 3830 name.Buffer = s; 3831 3832 if (NT_SUCCESS(IoGetDeviceObjectPointer(&name, FILE_READ_ATTRIBUTES, &FileObject, &devobj))) { 3833 if (DeviceObject == devobj || DeviceObject == FileObject->DeviceObject) { 3834 ObDereferenceObject(FileObject); 3835 3836 pnp_name->Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG); 3837 if (!pnp_name->Buffer) { 3838 ERR("out of memory\n"); 3839 Status = STATUS_INSUFFICIENT_RESOURCES; 3840 goto end; 3841 } 3842 3843 RtlCopyMemory(pnp_name->Buffer, name.Buffer, name.Length); 3844 pnp_name->Length = pnp_name->MaximumLength = name.Length; 3845 3846 Status = STATUS_SUCCESS; 3847 goto end; 3848 } 3849 3850 ObDereferenceObject(FileObject); 3851 } 3852 3853 s = &s[wcslen(s) + 1]; 3854 } 3855 3856 pnp_name->Length = pnp_name->MaximumLength = 0; 3857 pnp_name->Buffer = 0; 3858 3859 Status = STATUS_NOT_FOUND; 3860 3861 end: 3862 if (list) 3863 ExFreePool(list); 3864 3865 return Status; 3866 } 3867 3868 NTSTATUS get_device_pnp_name(_In_ PDEVICE_OBJECT DeviceObject, _Out_ PUNICODE_STRING pnp_name, _Out_ const GUID** guid) { 3869 NTSTATUS Status; 3870 3871 Status = get_device_pnp_name_guid(DeviceObject, pnp_name, &GUID_DEVINTERFACE_VOLUME); 3872 if (NT_SUCCESS(Status)) { 3873 *guid = &GUID_DEVINTERFACE_VOLUME; 3874 return Status; 3875 } 3876 3877 Status = get_device_pnp_name_guid(DeviceObject, pnp_name, &GUID_DEVINTERFACE_HIDDEN_VOLUME); 3878 if (NT_SUCCESS(Status)) { 3879 *guid = &GUID_DEVINTERFACE_HIDDEN_VOLUME; 3880 return Status; 3881 } 3882 3883 Status = get_device_pnp_name_guid(DeviceObject, pnp_name, &GUID_DEVINTERFACE_DISK); 3884 if (NT_SUCCESS(Status)) { 3885 *guid = &GUID_DEVINTERFACE_DISK; 3886 return Status; 3887 } 3888 3889 return STATUS_NOT_FOUND; 3890 } 3891 3892 _Success_(return>=0) 3893 static NTSTATUS check_mount_device(_In_ PDEVICE_OBJECT DeviceObject, _Out_ BOOL* no_pnp) { 3894 NTSTATUS Status; 3895 ULONG to_read; 3896 superblock* sb; 3897 UINT32 crc32; 3898 UNICODE_STRING pnp_name; 3899 const GUID* guid; 3900 3901 to_read = DeviceObject->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), DeviceObject->SectorSize); 3902 3903 sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG); 3904 if (!sb) { 3905 ERR("out of memory\n"); 3906 return STATUS_INSUFFICIENT_RESOURCES; 3907 } 3908 3909 Status = sync_read_phys(DeviceObject, superblock_addrs[0], to_read, (PUCHAR)sb, TRUE); 3910 if (!NT_SUCCESS(Status)) { 3911 ERR("sync_read_phys returned %08x\n", Status); 3912 goto end; 3913 } 3914 3915 if (sb->magic != BTRFS_MAGIC) { 3916 Status = STATUS_SUCCESS; 3917 goto end; 3918 } 3919 3920 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 3921 3922 if (crc32 != *((UINT32*)sb->checksum)) { 3923 WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum)); 3924 Status = STATUS_SUCCESS; 3925 goto end; 3926 } 3927 3928 DeviceObject->Flags &= ~DO_VERIFY_VOLUME; 3929 3930 pnp_name.Buffer = NULL; 3931 3932 Status = get_device_pnp_name(DeviceObject, &pnp_name, &guid); 3933 if (!NT_SUCCESS(Status)) { 3934 WARN("get_device_pnp_name returned %08x\n", Status); 3935 pnp_name.Length = 0; 3936 } 3937 3938 if (pnp_name.Length == 0) 3939 *no_pnp = TRUE; 3940 else { 3941 *no_pnp = FALSE; 3942 volume_arrival(drvobj, &pnp_name); 3943 } 3944 3945 if (pnp_name.Buffer) 3946 ExFreePool(pnp_name.Buffer); 3947 3948 Status = STATUS_SUCCESS; 3949 3950 end: 3951 ExFreePool(sb); 3952 3953 return Status; 3954 } 3955 3956 static BOOL still_has_superblock(_In_ PDEVICE_OBJECT device) { 3957 NTSTATUS Status; 3958 ULONG to_read; 3959 superblock* sb; 3960 PDEVICE_OBJECT device2; 3961 3962 if (!device) 3963 return FALSE; 3964 3965 to_read = device->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), device->SectorSize); 3966 3967 sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG); 3968 if (!sb) { 3969 ERR("out of memory\n"); 3970 return FALSE; 3971 } 3972 3973 Status = sync_read_phys(device, superblock_addrs[0], to_read, (PUCHAR)sb, TRUE); 3974 if (!NT_SUCCESS(Status)) { 3975 ERR("Failed to read superblock: %08x\n", Status); 3976 ExFreePool(sb); 3977 return FALSE; 3978 } 3979 3980 if (sb->magic != BTRFS_MAGIC) { 3981 TRACE("not a BTRFS volume\n"); 3982 ExFreePool(sb); 3983 return FALSE; 3984 } else { 3985 UINT32 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 3986 3987 if (crc32 != *((UINT32*)sb->checksum)) { 3988 WARN("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum)); 3989 ExFreePool(sb); 3990 return FALSE; 3991 } 3992 } 3993 3994 device2 = device; 3995 3996 do { 3997 device2->Flags &= ~DO_VERIFY_VOLUME; 3998 device2 = IoGetLowerDeviceObject(device2); 3999 } while (device2); 4000 4001 ExFreePool(sb); 4002 return TRUE; 4003 } 4004 4005 static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4006 PIO_STACK_LOCATION IrpSp; 4007 PDEVICE_OBJECT NewDeviceObject = NULL; 4008 PDEVICE_OBJECT DeviceToMount, readobj; 4009 NTSTATUS Status; 4010 device_extension* Vcb = NULL; 4011 LIST_ENTRY *le, batchlist; 4012 KEY searchkey; 4013 traverse_ptr tp; 4014 fcb* root_fcb = NULL; 4015 ccb* root_ccb = NULL; 4016 BOOL init_lookaside = FALSE; 4017 device* dev; 4018 volume_device_extension* vde = NULL; 4019 pdo_device_extension* pdode = NULL; 4020 volume_child* vc; 4021 BOOL no_pnp = FALSE; 4022 UINT64 readobjsize; 4023 4024 TRACE("(%p, %p)\n", DeviceObject, Irp); 4025 4026 if (DeviceObject != master_devobj) { 4027 Status = STATUS_INVALID_DEVICE_REQUEST; 4028 goto exit; 4029 } 4030 4031 IrpSp = IoGetCurrentIrpStackLocation(Irp); 4032 DeviceToMount = IrpSp->Parameters.MountVolume.DeviceObject; 4033 4034 if (!is_btrfs_volume(DeviceToMount)) { 4035 Status = check_mount_device(DeviceToMount, &no_pnp); 4036 if (!NT_SUCCESS(Status)) 4037 WARN("check_mount_device returned %08x\n", Status); 4038 4039 if (!no_pnp) { 4040 Status = STATUS_UNRECOGNIZED_VOLUME; 4041 goto exit2; 4042 } 4043 } else { 4044 PDEVICE_OBJECT pdo; 4045 4046 pdo = DeviceToMount; 4047 4048 while (IoGetLowerDeviceObject(pdo)) { 4049 pdo = IoGetLowerDeviceObject(pdo); 4050 } 4051 4052 ExAcquireResourceSharedLite(&pdo_list_lock, TRUE); 4053 4054 le = pdo_list.Flink; 4055 while (le != &pdo_list) { 4056 pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 4057 4058 if (pdode->pdo == pdo) { 4059 vde = pdode->vde; 4060 break; 4061 } 4062 4063 le = le->Flink; 4064 } 4065 4066 ExReleaseResourceLite(&pdo_list_lock); 4067 4068 if (!vde || vde->type != VCB_TYPE_VOLUME) { 4069 vde = NULL; 4070 Status = STATUS_UNRECOGNIZED_VOLUME; 4071 goto exit2; 4072 } 4073 } 4074 4075 if (vde) { 4076 pdode = vde->pdode; 4077 4078 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); 4079 4080 le = pdode->children.Flink; 4081 while (le != &pdode->children) { 4082 LIST_ENTRY* le2 = le->Flink; 4083 4084 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry); 4085 4086 if (!still_has_superblock(vc->devobj)) { 4087 remove_volume_child(vde, vc, FALSE); 4088 4089 if (pdode->num_children == 0) { 4090 ERR("error - number of devices is zero\n"); 4091 Status = STATUS_INTERNAL_ERROR; 4092 goto exit2; 4093 } 4094 4095 Status = STATUS_DEVICE_NOT_READY; 4096 goto exit2; 4097 } 4098 4099 le = le2; 4100 } 4101 4102 if (pdode->num_children == 0 || pdode->children_loaded == 0) { 4103 ERR("error - number of devices is zero\n"); 4104 Status = STATUS_INTERNAL_ERROR; 4105 goto exit; 4106 } 4107 4108 ExConvertExclusiveToSharedLite(&pdode->child_lock); 4109 4110 vc = CONTAINING_RECORD(pdode->children.Flink, volume_child, list_entry); 4111 4112 readobj = vc->devobj; 4113 readobjsize = vc->size; 4114 4115 vde->device->Characteristics &= ~FILE_DEVICE_SECURE_OPEN; 4116 } else { 4117 GET_LENGTH_INFORMATION gli; 4118 4119 vc = NULL; 4120 readobj = DeviceToMount; 4121 4122 Status = dev_ioctl(readobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, 4123 &gli, sizeof(gli), TRUE, NULL); 4124 4125 if (!NT_SUCCESS(Status)) { 4126 ERR("error reading length information: %08x\n", Status); 4127 goto exit; 4128 } 4129 4130 readobjsize = gli.Length.QuadPart; 4131 } 4132 4133 Status = IoCreateDevice(drvobj, sizeof(device_extension), NULL, FILE_DEVICE_DISK_FILE_SYSTEM, 0, FALSE, &NewDeviceObject); 4134 if (!NT_SUCCESS(Status)) { 4135 ERR("IoCreateDevice returned %08x\n", Status); 4136 Status = STATUS_UNRECOGNIZED_VOLUME; 4137 goto exit; 4138 } 4139 4140 NewDeviceObject->Flags |= DO_DIRECT_IO; 4141 4142 // Some programs seem to expect that the sector size will be 512, for 4143 // FILE_NO_INTERMEDIATE_BUFFERING and the like. 4144 NewDeviceObject->SectorSize = min(DeviceToMount->SectorSize, 512); 4145 4146 Vcb = (PVOID)NewDeviceObject->DeviceExtension; 4147 RtlZeroMemory(Vcb, sizeof(device_extension)); 4148 Vcb->type = VCB_TYPE_FS; 4149 Vcb->vde = vde; 4150 4151 ExInitializeResourceLite(&Vcb->tree_lock); 4152 Vcb->need_write = FALSE; 4153 4154 ExInitializeResourceLite(&Vcb->fcb_lock); 4155 ExInitializeResourceLite(&Vcb->fileref_lock); 4156 ExInitializeResourceLite(&Vcb->chunk_lock); 4157 ExInitializeResourceLite(&Vcb->dirty_fcbs_lock); 4158 ExInitializeResourceLite(&Vcb->dirty_filerefs_lock); 4159 ExInitializeResourceLite(&Vcb->dirty_subvols_lock); 4160 ExInitializeResourceLite(&Vcb->scrub.stats_lock); 4161 4162 ExInitializeResourceLite(&Vcb->load_lock); 4163 ExAcquireResourceExclusiveLite(&Vcb->load_lock, TRUE); 4164 4165 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 4166 4167 DeviceToMount->Flags |= DO_DIRECT_IO; 4168 4169 Status = read_superblock(Vcb, readobj, readobjsize); 4170 if (!NT_SUCCESS(Status)) { 4171 if (!IoIsErrorUserInduced(Status)) 4172 Status = STATUS_UNRECOGNIZED_VOLUME; 4173 else if (Irp->Tail.Overlay.Thread) 4174 IoSetHardErrorOrVerifyDevice(Irp, readobj); 4175 4176 goto exit; 4177 } 4178 4179 if (!vde && Vcb->superblock.num_devices > 1) { 4180 ERR("cannot mount multi-device FS with non-PNP device\n"); 4181 Status = STATUS_UNRECOGNIZED_VOLUME; 4182 goto exit; 4183 } 4184 4185 Status = registry_load_volume_options(Vcb); 4186 if (!NT_SUCCESS(Status)) { 4187 ERR("registry_load_volume_options returned %08x\n", Status); 4188 goto exit; 4189 } 4190 4191 if (pdode && pdode->children_loaded < pdode->num_children && (!Vcb->options.allow_degraded || !finished_probing || degraded_wait)) { 4192 ERR("could not mount as %u device(s) missing\n", pdode->num_children - pdode->children_loaded); 4193 Status = STATUS_DEVICE_NOT_READY; 4194 goto exit; 4195 } 4196 4197 if (Vcb->options.ignore) { 4198 TRACE("ignoring volume\n"); 4199 Status = STATUS_UNRECOGNIZED_VOLUME; 4200 goto exit; 4201 } 4202 4203 if (Vcb->superblock.incompat_flags & ~INCOMPAT_SUPPORTED) { 4204 WARN("cannot mount because of unsupported incompat flags (%llx)\n", Vcb->superblock.incompat_flags & ~INCOMPAT_SUPPORTED); 4205 Status = STATUS_UNRECOGNIZED_VOLUME; 4206 goto exit; 4207 } 4208 4209 Vcb->readonly = FALSE; 4210 if (Vcb->superblock.compat_ro_flags & ~COMPAT_RO_SUPPORTED) { 4211 WARN("mounting read-only because of unsupported flags (%llx)\n", Vcb->superblock.compat_ro_flags & ~COMPAT_RO_SUPPORTED); 4212 Vcb->readonly = TRUE; 4213 } 4214 4215 if (Vcb->options.readonly) 4216 Vcb->readonly = TRUE; 4217 4218 Vcb->superblock.generation++; 4219 Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF; 4220 4221 InitializeListHead(&Vcb->devices); 4222 dev = ExAllocatePoolWithTag(NonPagedPool, sizeof(device), ALLOC_TAG); 4223 if (!dev) { 4224 ERR("out of memory\n"); 4225 Status = STATUS_INSUFFICIENT_RESOURCES; 4226 goto exit; 4227 } 4228 4229 dev->devobj = readobj; 4230 RtlCopyMemory(&dev->devitem, &Vcb->superblock.dev_item, sizeof(DEV_ITEM)); 4231 4232 if (dev->devitem.num_bytes > readobjsize) { 4233 WARN("device %llx: DEV_ITEM says %llx bytes, but Windows only reports %llx\n", dev->devitem.dev_id, 4234 dev->devitem.num_bytes, readobjsize); 4235 4236 dev->devitem.num_bytes = readobjsize; 4237 } 4238 4239 dev->seeding = Vcb->superblock.flags & BTRFS_SUPERBLOCK_FLAGS_SEEDING ? TRUE : FALSE; 4240 4241 init_device(Vcb, dev, TRUE); 4242 4243 InsertTailList(&Vcb->devices, &dev->list_entry); 4244 Vcb->devices_loaded = 1; 4245 4246 if (DeviceToMount->Flags & DO_SYSTEM_BOOT_PARTITION) 4247 Vcb->disallow_dismount = TRUE; 4248 4249 TRACE("DeviceToMount = %p\n", DeviceToMount); 4250 TRACE("IrpSp->Parameters.MountVolume.Vpb = %p\n", IrpSp->Parameters.MountVolume.Vpb); 4251 4252 NewDeviceObject->StackSize = DeviceToMount->StackSize + 1; 4253 NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 4254 4255 InitializeListHead(&Vcb->roots); 4256 InitializeListHead(&Vcb->drop_roots); 4257 4258 Vcb->log_to_phys_loaded = FALSE; 4259 4260 add_root(Vcb, BTRFS_ROOT_CHUNK, Vcb->superblock.chunk_tree_addr, Vcb->superblock.chunk_root_generation, NULL); 4261 4262 if (!Vcb->chunk_root) { 4263 ERR("Could not load chunk root.\n"); 4264 Status = STATUS_INTERNAL_ERROR; 4265 goto exit; 4266 } 4267 4268 InitializeListHead(&Vcb->sys_chunks); 4269 Status = load_sys_chunks(Vcb); 4270 if (!NT_SUCCESS(Status)) { 4271 ERR("load_sys_chunks returned %08x\n", Status); 4272 goto exit; 4273 } 4274 4275 InitializeListHead(&Vcb->chunks); 4276 InitializeListHead(&Vcb->trees); 4277 InitializeListHead(&Vcb->trees_hash); 4278 InitializeListHead(&Vcb->all_fcbs); 4279 InitializeListHead(&Vcb->dirty_fcbs); 4280 InitializeListHead(&Vcb->dirty_filerefs); 4281 InitializeListHead(&Vcb->dirty_subvols); 4282 InitializeListHead(&Vcb->send_ops); 4283 4284 ExInitializeFastMutex(&Vcb->trees_list_mutex); 4285 4286 InitializeListHead(&Vcb->DirNotifyList); 4287 InitializeListHead(&Vcb->scrub.errors); 4288 4289 FsRtlNotifyInitializeSync(&Vcb->NotifySync); 4290 4291 ExInitializePagedLookasideList(&Vcb->tree_data_lookaside, NULL, NULL, 0, sizeof(tree_data), ALLOC_TAG, 0); 4292 ExInitializePagedLookasideList(&Vcb->traverse_ptr_lookaside, NULL, NULL, 0, sizeof(traverse_ptr), ALLOC_TAG, 0); 4293 ExInitializePagedLookasideList(&Vcb->batch_item_lookaside, NULL, NULL, 0, sizeof(batch_item), ALLOC_TAG, 0); 4294 ExInitializePagedLookasideList(&Vcb->fileref_lookaside, NULL, NULL, 0, sizeof(file_ref), ALLOC_TAG, 0); 4295 ExInitializePagedLookasideList(&Vcb->fcb_lookaside, NULL, NULL, 0, sizeof(fcb), ALLOC_TAG, 0); 4296 ExInitializePagedLookasideList(&Vcb->name_bit_lookaside, NULL, NULL, 0, sizeof(name_bit), ALLOC_TAG, 0); 4297 ExInitializeNPagedLookasideList(&Vcb->range_lock_lookaside, NULL, NULL, 0, sizeof(range_lock), ALLOC_TAG, 0); 4298 ExInitializeNPagedLookasideList(&Vcb->fileref_np_lookaside, NULL, NULL, 0, sizeof(file_ref_nonpaged), ALLOC_TAG, 0); 4299 ExInitializeNPagedLookasideList(&Vcb->fcb_np_lookaside, NULL, NULL, 0, sizeof(fcb_nonpaged), ALLOC_TAG, 0); 4300 init_lookaside = TRUE; 4301 4302 Vcb->Vpb = IrpSp->Parameters.MountVolume.Vpb; 4303 4304 Status = load_chunk_root(Vcb, Irp); 4305 if (!NT_SUCCESS(Status)) { 4306 ERR("load_chunk_root returned %08x\n", Status); 4307 goto exit; 4308 } 4309 4310 if (Vcb->superblock.num_devices > 1) { 4311 if (Vcb->devices_loaded < Vcb->superblock.num_devices && (!Vcb->options.allow_degraded || !finished_probing)) { 4312 ERR("could not mount as %u device(s) missing\n", Vcb->superblock.num_devices - Vcb->devices_loaded); 4313 4314 IoRaiseInformationalHardError(IO_ERR_INTERNAL_ERROR, NULL, NULL); 4315 4316 Status = STATUS_INTERNAL_ERROR; 4317 goto exit; 4318 } 4319 4320 if (dev->readonly && !Vcb->readonly) { 4321 Vcb->readonly = TRUE; 4322 4323 le = Vcb->devices.Flink; 4324 while (le != &Vcb->devices) { 4325 device* dev2 = CONTAINING_RECORD(le, device, list_entry); 4326 4327 if (dev2->readonly && !dev2->seeding) 4328 break; 4329 4330 if (!dev2->readonly) { 4331 Vcb->readonly = FALSE; 4332 break; 4333 } 4334 4335 le = le->Flink; 4336 } 4337 4338 if (Vcb->readonly) 4339 WARN("setting volume to readonly\n"); 4340 } 4341 } else { 4342 if (dev->readonly) { 4343 WARN("setting volume to readonly as device is readonly\n"); 4344 Vcb->readonly = TRUE; 4345 } 4346 } 4347 4348 add_root(Vcb, BTRFS_ROOT_ROOT, Vcb->superblock.root_tree_addr, Vcb->superblock.generation - 1, NULL); 4349 4350 if (!Vcb->root_root) { 4351 ERR("Could not load root of roots.\n"); 4352 Status = STATUS_INTERNAL_ERROR; 4353 goto exit; 4354 } 4355 4356 Status = look_for_roots(Vcb, Irp); 4357 if (!NT_SUCCESS(Status)) { 4358 ERR("look_for_roots returned %08x\n", Status); 4359 goto exit; 4360 } 4361 4362 if (!Vcb->readonly) { 4363 Status = find_chunk_usage(Vcb, Irp); 4364 if (!NT_SUCCESS(Status)) { 4365 ERR("find_chunk_usage returned %08x\n", Status); 4366 goto exit; 4367 } 4368 } 4369 4370 InitializeListHead(&batchlist); 4371 4372 // We've already increased the generation by one 4373 if (!Vcb->readonly && ( 4374 Vcb->options.clear_cache || 4375 (!(Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE) && Vcb->superblock.generation - 1 != Vcb->superblock.cache_generation) || 4376 (Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE && !(Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID)))) { 4377 if (Vcb->options.clear_cache) 4378 WARN("ClearCache option was set, clearing cache...\n"); 4379 else if (Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE && !(Vcb->superblock.compat_ro_flags & BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID)) 4380 WARN("clearing free-space tree created by buggy Linux driver\n"); 4381 else 4382 WARN("generation was %llx, free-space cache generation was %llx; clearing cache...\n", Vcb->superblock.generation - 1, Vcb->superblock.cache_generation); 4383 4384 Status = clear_free_space_cache(Vcb, &batchlist, Irp); 4385 if (!NT_SUCCESS(Status)) { 4386 ERR("clear_free_space_cache returned %08x\n", Status); 4387 clear_batch_list(Vcb, &batchlist); 4388 goto exit; 4389 } 4390 } 4391 4392 Status = commit_batch_list(Vcb, &batchlist, Irp); 4393 if (!NT_SUCCESS(Status)) { 4394 ERR("commit_batch_list returned %08x\n", Status); 4395 goto exit; 4396 } 4397 4398 Vcb->volume_fcb = create_fcb(Vcb, NonPagedPool); 4399 if (!Vcb->volume_fcb) { 4400 ERR("out of memory\n"); 4401 Status = STATUS_INSUFFICIENT_RESOURCES; 4402 goto exit; 4403 } 4404 4405 Vcb->volume_fcb->Vcb = Vcb; 4406 Vcb->volume_fcb->sd = NULL; 4407 4408 Vcb->dummy_fcb = create_fcb(Vcb, NonPagedPool); 4409 if (!Vcb->dummy_fcb) { 4410 ERR("out of memory\n"); 4411 Status = STATUS_INSUFFICIENT_RESOURCES; 4412 goto exit; 4413 } 4414 4415 Vcb->dummy_fcb->Vcb = Vcb; 4416 Vcb->dummy_fcb->type = BTRFS_TYPE_DIRECTORY; 4417 Vcb->dummy_fcb->inode = 2; 4418 Vcb->dummy_fcb->subvol = Vcb->root_root; 4419 Vcb->dummy_fcb->atts = FILE_ATTRIBUTE_DIRECTORY; 4420 Vcb->dummy_fcb->inode_item.st_nlink = 1; 4421 Vcb->dummy_fcb->inode_item.st_mode = __S_IFDIR; 4422 4423 Vcb->dummy_fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); 4424 if (!Vcb->dummy_fcb->hash_ptrs) { 4425 ERR("out of memory\n"); 4426 Status = STATUS_INSUFFICIENT_RESOURCES; 4427 goto exit; 4428 } 4429 4430 RtlZeroMemory(Vcb->dummy_fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256); 4431 4432 Vcb->dummy_fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG); 4433 if (!Vcb->dummy_fcb->hash_ptrs_uc) { 4434 ERR("out of memory\n"); 4435 Status = STATUS_INSUFFICIENT_RESOURCES; 4436 goto exit; 4437 } 4438 4439 RtlZeroMemory(Vcb->dummy_fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256); 4440 4441 root_fcb = create_fcb(Vcb, NonPagedPool); 4442 if (!root_fcb) { 4443 ERR("out of memory\n"); 4444 Status = STATUS_INSUFFICIENT_RESOURCES; 4445 goto exit; 4446 } 4447 4448 root_fcb->Vcb = Vcb; 4449 root_fcb->inode = SUBVOL_ROOT_INODE; 4450 root_fcb->hash = calc_crc32c(0xffffffff, (UINT8*)&root_fcb->inode, sizeof(UINT64)); 4451 root_fcb->type = BTRFS_TYPE_DIRECTORY; 4452 4453 #ifdef DEBUG_FCB_REFCOUNTS 4454 WARN("volume FCB = %p\n", Vcb->volume_fcb); 4455 WARN("root FCB = %p\n", root_fcb); 4456 #endif 4457 4458 root_fcb->subvol = find_default_subvol(Vcb, Irp); 4459 4460 if (!root_fcb->subvol) { 4461 ERR("could not find top subvol\n"); 4462 Status = STATUS_INTERNAL_ERROR; 4463 goto exit; 4464 } 4465 4466 Status = load_dir_children(Vcb, root_fcb, TRUE, Irp); 4467 if (!NT_SUCCESS(Status)) { 4468 ERR("load_dir_children returned %08x\n", Status); 4469 goto exit; 4470 } 4471 4472 searchkey.obj_id = root_fcb->inode; 4473 searchkey.obj_type = TYPE_INODE_ITEM; 4474 searchkey.offset = 0xffffffffffffffff; 4475 4476 Status = find_item(Vcb, root_fcb->subvol, &tp, &searchkey, FALSE, Irp); 4477 if (!NT_SUCCESS(Status)) { 4478 ERR("error - find_item returned %08x\n", Status); 4479 goto exit; 4480 } 4481 4482 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) { 4483 ERR("couldn't find INODE_ITEM for root directory\n"); 4484 Status = STATUS_INTERNAL_ERROR; 4485 goto exit; 4486 } 4487 4488 if (tp.item->size > 0) 4489 RtlCopyMemory(&root_fcb->inode_item, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size)); 4490 4491 fcb_get_sd(root_fcb, NULL, TRUE, Irp); 4492 4493 root_fcb->atts = get_file_attributes(Vcb, root_fcb->subvol, root_fcb->inode, root_fcb->type, FALSE, FALSE, Irp); 4494 4495 Vcb->root_fileref = create_fileref(Vcb); 4496 if (!Vcb->root_fileref) { 4497 ERR("out of memory\n"); 4498 Status = STATUS_INSUFFICIENT_RESOURCES; 4499 goto exit; 4500 } 4501 4502 Vcb->root_fileref->fcb = root_fcb; 4503 InsertTailList(&root_fcb->subvol->fcbs, &root_fcb->list_entry); 4504 InsertTailList(&Vcb->all_fcbs, &root_fcb->list_entry_all); 4505 4506 root_fcb->subvol->fcbs_ptrs[root_fcb->hash >> 24] = &root_fcb->list_entry; 4507 4508 root_fcb->fileref = Vcb->root_fileref; 4509 4510 root_ccb = ExAllocatePoolWithTag(PagedPool, sizeof(ccb), ALLOC_TAG); 4511 if (!root_ccb) { 4512 ERR("out of memory\n"); 4513 Status = STATUS_INSUFFICIENT_RESOURCES; 4514 goto exit; 4515 } 4516 4517 /* HACK: stream file object seems to get deleted at some point 4518 * leading to use after free when installing ReactOS on 4519 * BtrFS. 4520 * Workaround: leak a handle to the fileobject 4521 * XXX: Could be improved by storing it somewhere and releasing it 4522 * on dismount. Or even by referencing again the file object. 4523 */ 4524 #ifndef __REACTOS__ 4525 Vcb->root_file = IoCreateStreamFileObject(NULL, DeviceToMount); 4526 #else 4527 { 4528 HANDLE Dummy; 4529 Vcb->root_file = IoCreateStreamFileObjectEx(NULL, DeviceToMount, &Dummy); 4530 } 4531 #endif 4532 Vcb->root_file->FsContext = root_fcb; 4533 Vcb->root_file->SectionObjectPointer = &root_fcb->nonpaged->segment_object; 4534 Vcb->root_file->Vpb = DeviceObject->Vpb; 4535 4536 RtlZeroMemory(root_ccb, sizeof(ccb)); 4537 root_ccb->NodeType = BTRFS_NODE_TYPE_CCB; 4538 root_ccb->NodeSize = sizeof(ccb); 4539 4540 Vcb->root_file->FsContext2 = root_ccb; 4541 4542 _SEH2_TRY { 4543 CcInitializeCacheMap(Vcb->root_file, (PCC_FILE_SIZES)(&root_fcb->Header.AllocationSize), FALSE, cache_callbacks, Vcb->root_file); 4544 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 4545 Status = _SEH2_GetExceptionCode(); 4546 goto exit; 4547 } _SEH2_END; 4548 4549 le = Vcb->devices.Flink; 4550 while (le != &Vcb->devices) { 4551 device* dev2 = CONTAINING_RECORD(le, device, list_entry); 4552 4553 Status = find_disk_holes(Vcb, dev2, Irp); 4554 if (!NT_SUCCESS(Status)) { 4555 ERR("find_disk_holes returned %08x\n", Status); 4556 goto exit; 4557 } 4558 4559 le = le->Flink; 4560 } 4561 4562 NewDeviceObject->Vpb = IrpSp->Parameters.MountVolume.Vpb; 4563 IrpSp->Parameters.MountVolume.Vpb->DeviceObject = NewDeviceObject; 4564 IrpSp->Parameters.MountVolume.Vpb->Flags |= VPB_MOUNTED; 4565 NewDeviceObject->Vpb->VolumeLabelLength = 4; // FIXME 4566 NewDeviceObject->Vpb->VolumeLabel[0] = '?'; 4567 NewDeviceObject->Vpb->VolumeLabel[1] = 0; 4568 NewDeviceObject->Vpb->ReferenceCount++; // FIXME - should we deref this at any point? 4569 4570 KeInitializeEvent(&Vcb->flush_thread_finished, NotificationEvent, FALSE); 4571 4572 Status = PsCreateSystemThread(&Vcb->flush_thread_handle, 0, NULL, NULL, NULL, flush_thread, NewDeviceObject); 4573 if (!NT_SUCCESS(Status)) { 4574 ERR("PsCreateSystemThread returned %08x\n", Status); 4575 goto exit; 4576 } 4577 4578 Status = create_calc_threads(NewDeviceObject); 4579 if (!NT_SUCCESS(Status)) { 4580 ERR("create_calc_threads returned %08x\n", Status); 4581 goto exit; 4582 } 4583 4584 Status = registry_mark_volume_mounted(&Vcb->superblock.uuid); 4585 if (!NT_SUCCESS(Status)) 4586 WARN("registry_mark_volume_mounted returned %08x\n", Status); 4587 4588 Status = look_for_balance_item(Vcb); 4589 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND) 4590 WARN("look_for_balance_item returned %08x\n", Status); 4591 4592 Status = STATUS_SUCCESS; 4593 4594 if (vde) 4595 vde->mounted_device = NewDeviceObject; 4596 4597 ExInitializeResourceLite(&Vcb->send_load_lock); 4598 4599 exit: 4600 if (pdode) 4601 ExReleaseResourceLite(&pdode->child_lock); 4602 4603 exit2: 4604 if (Vcb) { 4605 ExReleaseResourceLite(&Vcb->tree_lock); 4606 ExReleaseResourceLite(&Vcb->load_lock); 4607 } 4608 4609 if (!NT_SUCCESS(Status)) { 4610 if (Vcb) { 4611 if (init_lookaside) { 4612 ExDeletePagedLookasideList(&Vcb->tree_data_lookaside); 4613 ExDeletePagedLookasideList(&Vcb->traverse_ptr_lookaside); 4614 ExDeletePagedLookasideList(&Vcb->batch_item_lookaside); 4615 ExDeletePagedLookasideList(&Vcb->fileref_lookaside); 4616 ExDeletePagedLookasideList(&Vcb->fcb_lookaside); 4617 ExDeletePagedLookasideList(&Vcb->name_bit_lookaside); 4618 ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside); 4619 ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside); 4620 ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside); 4621 } 4622 4623 if (Vcb->root_file) 4624 ObDereferenceObject(Vcb->root_file); 4625 else if (Vcb->root_fileref) 4626 free_fileref(Vcb->root_fileref); 4627 else if (root_fcb) 4628 free_fcb(root_fcb); 4629 4630 if (root_fcb && root_fcb->refcount == 0) 4631 reap_fcb(root_fcb); 4632 4633 if (Vcb->volume_fcb) 4634 reap_fcb(Vcb->volume_fcb); 4635 4636 ExDeleteResourceLite(&Vcb->tree_lock); 4637 ExDeleteResourceLite(&Vcb->load_lock); 4638 ExDeleteResourceLite(&Vcb->fcb_lock); 4639 ExDeleteResourceLite(&Vcb->fileref_lock); 4640 ExDeleteResourceLite(&Vcb->chunk_lock); 4641 ExDeleteResourceLite(&Vcb->dirty_fcbs_lock); 4642 ExDeleteResourceLite(&Vcb->dirty_filerefs_lock); 4643 ExDeleteResourceLite(&Vcb->dirty_subvols_lock); 4644 ExDeleteResourceLite(&Vcb->scrub.stats_lock); 4645 4646 if (Vcb->devices.Flink) { 4647 while (!IsListEmpty(&Vcb->devices)) { 4648 device* dev2 = CONTAINING_RECORD(RemoveHeadList(&Vcb->devices), device, list_entry); 4649 4650 ExFreePool(dev2); 4651 } 4652 } 4653 } 4654 4655 if (NewDeviceObject) 4656 IoDeleteDevice(NewDeviceObject); 4657 } else { 4658 ExAcquireResourceExclusiveLite(&global_loading_lock, TRUE); 4659 InsertTailList(&VcbList, &Vcb->list_entry); 4660 ExReleaseResourceLite(&global_loading_lock); 4661 4662 FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_MOUNT); 4663 } 4664 4665 TRACE("mount_vol done (status: %lx)\n", Status); 4666 4667 return Status; 4668 } 4669 4670 static NTSTATUS verify_device(_In_ device_extension* Vcb, _Inout_ device* dev) { 4671 NTSTATUS Status; 4672 superblock* sb; 4673 UINT32 crc32; 4674 ULONG to_read, cc; 4675 4676 if (!dev->devobj) 4677 return STATUS_WRONG_VOLUME; 4678 4679 if (dev->removable) { 4680 IO_STATUS_BLOCK iosb; 4681 4682 Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), TRUE, &iosb); 4683 4684 if (IoIsErrorUserInduced(Status)) { 4685 ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08x (user-induced)\n", Status); 4686 4687 if (Vcb->vde) { 4688 pdo_device_extension* pdode = Vcb->vde->pdode; 4689 LIST_ENTRY* le2; 4690 BOOL changed = FALSE; 4691 4692 ExAcquireResourceExclusiveLite(&pdode->child_lock, TRUE); 4693 4694 le2 = pdode->children.Flink; 4695 while (le2 != &pdode->children) { 4696 volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry); 4697 4698 if (vc->devobj == dev->devobj) { 4699 TRACE("removing device\n"); 4700 4701 remove_volume_child(Vcb->vde, vc, TRUE); 4702 changed = TRUE; 4703 4704 break; 4705 } 4706 4707 le2 = le2->Flink; 4708 } 4709 4710 if (!changed) 4711 ExReleaseResourceLite(&pdode->child_lock); 4712 } 4713 } else if (!NT_SUCCESS(Status)) { 4714 ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08x\n", Status); 4715 return Status; 4716 } else if (iosb.Information < sizeof(ULONG)) { 4717 ERR("iosb.Information was too short\n"); 4718 return STATUS_INTERNAL_ERROR; 4719 } 4720 4721 dev->change_count = cc; 4722 } 4723 4724 to_read = dev->devobj->SectorSize == 0 ? sizeof(superblock) : (ULONG)sector_align(sizeof(superblock), dev->devobj->SectorSize); 4725 4726 sb = ExAllocatePoolWithTag(NonPagedPool, to_read, ALLOC_TAG); 4727 if (!sb) { 4728 ERR("out of memory\n"); 4729 return STATUS_INSUFFICIENT_RESOURCES; 4730 } 4731 4732 Status = sync_read_phys(dev->devobj, superblock_addrs[0], to_read, (PUCHAR)sb, TRUE); 4733 if (!NT_SUCCESS(Status)) { 4734 ERR("Failed to read superblock: %08x\n", Status); 4735 ExFreePool(sb); 4736 return Status; 4737 } 4738 4739 if (sb->magic != BTRFS_MAGIC) { 4740 ERR("not a BTRFS volume\n"); 4741 ExFreePool(sb); 4742 return STATUS_WRONG_VOLUME; 4743 } 4744 4745 crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 4746 TRACE("crc32 was %08x, expected %08x\n", crc32, *((UINT32*)sb->checksum)); 4747 4748 if (crc32 != *((UINT32*)sb->checksum)) { 4749 ERR("checksum error\n"); 4750 ExFreePool(sb); 4751 return STATUS_WRONG_VOLUME; 4752 } 4753 4754 if (RtlCompareMemory(&sb->uuid, &Vcb->superblock.uuid, sizeof(BTRFS_UUID)) != sizeof(BTRFS_UUID)) { 4755 ERR("different UUIDs\n"); 4756 ExFreePool(sb); 4757 return STATUS_WRONG_VOLUME; 4758 } 4759 4760 ExFreePool(sb); 4761 4762 dev->devobj->Flags &= ~DO_VERIFY_VOLUME; 4763 4764 return STATUS_SUCCESS; 4765 } 4766 4767 static NTSTATUS verify_volume(_In_ PDEVICE_OBJECT devobj) { 4768 device_extension* Vcb = devobj->DeviceExtension; 4769 NTSTATUS Status; 4770 LIST_ENTRY* le; 4771 UINT64 failed_devices = 0; 4772 BOOL locked = FALSE, remove = FALSE; 4773 4774 if (!(Vcb->Vpb->Flags & VPB_MOUNTED)) 4775 return STATUS_WRONG_VOLUME; 4776 4777 if (!ExIsResourceAcquiredExclusive(&Vcb->tree_lock)) { 4778 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 4779 locked = TRUE; 4780 } 4781 4782 if (Vcb->removing) { 4783 if (locked) ExReleaseResourceLite(&Vcb->tree_lock); 4784 return STATUS_WRONG_VOLUME; 4785 } 4786 4787 InterlockedIncrement(&Vcb->open_files); // so pnp_surprise_removal doesn't uninit the device while we're still using it 4788 4789 le = Vcb->devices.Flink; 4790 while (le != &Vcb->devices) { 4791 device* dev = CONTAINING_RECORD(le, device, list_entry); 4792 4793 Status = verify_device(Vcb, dev); 4794 if (!NT_SUCCESS(Status)) { 4795 failed_devices++; 4796 4797 if (dev->devobj && Vcb->options.allow_degraded) 4798 dev->devobj = NULL; 4799 } 4800 4801 le = le->Flink; 4802 } 4803 4804 InterlockedDecrement(&Vcb->open_files); 4805 4806 if (Vcb->removing && Vcb->open_files == 0) 4807 remove = TRUE; 4808 4809 if (locked) 4810 ExReleaseResourceLite(&Vcb->tree_lock); 4811 4812 if (remove) { 4813 uninit(Vcb); 4814 return Status; 4815 } 4816 4817 if (failed_devices == 0 || (Vcb->options.allow_degraded && failed_devices < Vcb->superblock.num_devices)) { 4818 Vcb->Vpb->RealDevice->Flags &= ~DO_VERIFY_VOLUME; 4819 4820 return STATUS_SUCCESS; 4821 } 4822 4823 return Status; 4824 } 4825 4826 _Dispatch_type_(IRP_MJ_FILE_SYSTEM_CONTROL) 4827 _Function_class_(DRIVER_DISPATCH) 4828 #ifdef __REACTOS__ 4829 static NTSTATUS NTAPI drv_file_system_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4830 #else 4831 static NTSTATUS drv_file_system_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4832 #endif 4833 PIO_STACK_LOCATION IrpSp; 4834 NTSTATUS Status; 4835 device_extension* Vcb = DeviceObject->DeviceExtension; 4836 BOOL top_level; 4837 4838 FsRtlEnterFileSystem(); 4839 4840 TRACE("file system control\n"); 4841 4842 top_level = is_top_level(Irp); 4843 4844 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 4845 Status = vol_file_system_control(DeviceObject, Irp); 4846 goto end; 4847 } else if (!Vcb || (Vcb->type != VCB_TYPE_FS && Vcb->type != VCB_TYPE_CONTROL)) { 4848 Status = STATUS_INVALID_PARAMETER; 4849 goto end; 4850 } 4851 4852 Status = STATUS_NOT_IMPLEMENTED; 4853 4854 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 4855 4856 Irp->IoStatus.Information = 0; 4857 4858 switch (IrpSp->MinorFunction) { 4859 case IRP_MN_MOUNT_VOLUME: 4860 TRACE("IRP_MN_MOUNT_VOLUME\n"); 4861 4862 Status = mount_vol(DeviceObject, Irp); 4863 break; 4864 4865 case IRP_MN_KERNEL_CALL: 4866 TRACE("IRP_MN_KERNEL_CALL\n"); 4867 4868 Status = fsctl_request(DeviceObject, &Irp, IrpSp->Parameters.FileSystemControl.FsControlCode); 4869 break; 4870 4871 case IRP_MN_USER_FS_REQUEST: 4872 TRACE("IRP_MN_USER_FS_REQUEST\n"); 4873 4874 Status = fsctl_request(DeviceObject, &Irp, IrpSp->Parameters.FileSystemControl.FsControlCode); 4875 break; 4876 4877 case IRP_MN_VERIFY_VOLUME: 4878 TRACE("IRP_MN_VERIFY_VOLUME\n"); 4879 4880 Status = verify_volume(DeviceObject); 4881 4882 if (!NT_SUCCESS(Status) && Vcb->Vpb->Flags & VPB_MOUNTED) { 4883 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 4884 Vcb->removing = TRUE; 4885 ExReleaseResourceLite(&Vcb->tree_lock); 4886 } 4887 4888 break; 4889 4890 default: 4891 break; 4892 } 4893 4894 end: 4895 TRACE("returning %08x\n", Status); 4896 4897 if (Irp) { 4898 Irp->IoStatus.Status = Status; 4899 4900 IoCompleteRequest(Irp, IO_NO_INCREMENT); 4901 } 4902 4903 if (top_level) 4904 IoSetTopLevelIrp(NULL); 4905 4906 FsRtlExitFileSystem(); 4907 4908 return Status; 4909 } 4910 4911 _Dispatch_type_(IRP_MJ_LOCK_CONTROL) 4912 _Function_class_(DRIVER_DISPATCH) 4913 #ifdef __REACTOS__ 4914 static NTSTATUS NTAPI drv_lock_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4915 #else 4916 static NTSTATUS drv_lock_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4917 #endif 4918 NTSTATUS Status; 4919 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 4920 fcb* fcb = IrpSp->FileObject->FsContext; 4921 device_extension* Vcb = DeviceObject->DeviceExtension; 4922 BOOL top_level; 4923 4924 FsRtlEnterFileSystem(); 4925 4926 top_level = is_top_level(Irp); 4927 4928 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 4929 Status = vol_lock_control(DeviceObject, Irp); 4930 4931 Irp->IoStatus.Status = Status; 4932 IoCompleteRequest(Irp, IO_NO_INCREMENT); 4933 4934 goto exit; 4935 } 4936 4937 TRACE("lock control\n"); 4938 4939 Status = FsRtlProcessFileLock(&fcb->lock, Irp, NULL); 4940 4941 fcb->Header.IsFastIoPossible = fast_io_possible(fcb); 4942 4943 exit: 4944 TRACE("returning %08x\n", Status); 4945 4946 if (top_level) 4947 IoSetTopLevelIrp(NULL); 4948 4949 FsRtlExitFileSystem(); 4950 4951 return Status; 4952 } 4953 4954 _Dispatch_type_(IRP_MJ_SHUTDOWN) 4955 _Function_class_(DRIVER_DISPATCH) 4956 #ifdef __REACTOS__ 4957 static NTSTATUS NTAPI drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4958 #else 4959 static NTSTATUS drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 4960 #endif 4961 NTSTATUS Status; 4962 BOOL top_level; 4963 device_extension* Vcb = DeviceObject->DeviceExtension; 4964 LIST_ENTRY* le; 4965 4966 FsRtlEnterFileSystem(); 4967 4968 TRACE("shutdown\n"); 4969 4970 top_level = is_top_level(Irp); 4971 4972 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 4973 Status = vol_shutdown(DeviceObject, Irp); 4974 goto end; 4975 } 4976 4977 Status = STATUS_SUCCESS; 4978 4979 shutting_down = TRUE; 4980 KeSetEvent(&mountmgr_thread_event, 0, FALSE); 4981 4982 le = VcbList.Flink; 4983 while (le != &VcbList) { 4984 BOOL open_files; 4985 LIST_ENTRY* le2 = le->Flink; 4986 4987 Vcb = CONTAINING_RECORD(le, device_extension, list_entry); 4988 4989 TRACE("shutting down Vcb %p\n", Vcb); 4990 4991 ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE); 4992 Vcb->removing = TRUE; 4993 open_files = Vcb->open_files > 0; 4994 4995 if (Vcb->need_write && !Vcb->readonly) { 4996 Status = do_write(Vcb, Irp); 4997 if (!NT_SUCCESS(Status)) 4998 ERR("do_write returned %08x\n", Status); 4999 } 5000 5001 free_trees(Vcb); 5002 5003 ExReleaseResourceLite(&Vcb->tree_lock); 5004 5005 if (!open_files) 5006 uninit(Vcb); 5007 5008 le = le2; 5009 } 5010 5011 #ifdef _DEBUG 5012 if (comfo) { 5013 ObDereferenceObject(comfo); 5014 comdo = NULL; 5015 comfo = NULL; 5016 } 5017 #endif 5018 5019 end: 5020 Irp->IoStatus.Status = Status; 5021 Irp->IoStatus.Information = 0; 5022 5023 IoCompleteRequest( Irp, IO_NO_INCREMENT ); 5024 5025 if (top_level) 5026 IoSetTopLevelIrp(NULL); 5027 5028 FsRtlExitFileSystem(); 5029 5030 return Status; 5031 } 5032 5033 _Dispatch_type_(IRP_MJ_POWER) 5034 _Function_class_(DRIVER_DISPATCH) 5035 #ifdef __REACTOS__ 5036 static NTSTATUS NTAPI drv_power(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 5037 #else 5038 static NTSTATUS drv_power(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 5039 #endif 5040 NTSTATUS Status; 5041 device_extension* Vcb = DeviceObject->DeviceExtension; 5042 BOOL top_level; 5043 5044 FsRtlEnterFileSystem(); 5045 5046 top_level = is_top_level(Irp); 5047 5048 Irp->IoStatus.Information = 0; 5049 5050 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 5051 Status = vol_power(DeviceObject, Irp); 5052 5053 Irp->IoStatus.Status = Status; 5054 IoCompleteRequest(Irp, IO_NO_INCREMENT); 5055 5056 goto exit; 5057 } else if (Vcb && Vcb->type == VCB_TYPE_FS) { 5058 IoSkipCurrentIrpStackLocation(Irp); 5059 5060 Status = IoCallDriver(Vcb->Vpb->RealDevice, Irp); 5061 5062 goto exit; 5063 } 5064 5065 Status = STATUS_INVALID_DEVICE_REQUEST; 5066 Irp->IoStatus.Status = Status; 5067 IoCompleteRequest(Irp, IO_NO_INCREMENT); 5068 5069 exit: 5070 if (top_level) 5071 IoSetTopLevelIrp(NULL); 5072 5073 FsRtlExitFileSystem(); 5074 5075 return Status; 5076 } 5077 5078 _Dispatch_type_(IRP_MJ_SYSTEM_CONTROL) 5079 _Function_class_(DRIVER_DISPATCH) 5080 #ifdef __REACTOS__ 5081 static NTSTATUS NTAPI drv_system_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 5082 #else 5083 static NTSTATUS drv_system_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp) { 5084 #endif 5085 NTSTATUS Status; 5086 device_extension* Vcb = DeviceObject->DeviceExtension; 5087 BOOL top_level; 5088 5089 FsRtlEnterFileSystem(); 5090 5091 top_level = is_top_level(Irp); 5092 5093 Irp->IoStatus.Information = 0; 5094 5095 if (Vcb && Vcb->type == VCB_TYPE_VOLUME) { 5096 volume_device_extension* vde = DeviceObject->DeviceExtension; 5097 5098 IoSkipCurrentIrpStackLocation(Irp); 5099 5100 Status = IoCallDriver(vde->pdo, Irp); 5101 5102 goto exit; 5103 } else if (Vcb && Vcb->type == VCB_TYPE_FS) { 5104 IoSkipCurrentIrpStackLocation(Irp); 5105 5106 Status = IoCallDriver(Vcb->Vpb->RealDevice, Irp); 5107 5108 goto exit; 5109 } 5110 5111 Status = Irp->IoStatus.Status; 5112 IoCompleteRequest(Irp, IO_NO_INCREMENT); 5113 5114 exit: 5115 if (top_level) 5116 IoSetTopLevelIrp(NULL); 5117 5118 FsRtlExitFileSystem(); 5119 5120 return Status; 5121 } 5122 5123 BOOL is_file_name_valid(_In_ PUNICODE_STRING us, _In_ BOOL posix) { 5124 ULONG i; 5125 5126 if (us->Length < sizeof(WCHAR)) 5127 return FALSE; 5128 5129 if (us->Length > 255 * sizeof(WCHAR)) 5130 return FALSE; 5131 5132 for (i = 0; i < us->Length / sizeof(WCHAR); i++) { 5133 if (us->Buffer[i] == '/' || us->Buffer[i] == 0 || 5134 (!posix && (us->Buffer[i] == '<' || us->Buffer[i] == '>' || us->Buffer[i] == ':' || us->Buffer[i] == '"' || 5135 us->Buffer[i] == '|' || us->Buffer[i] == '?' || us->Buffer[i] == '*' || (us->Buffer[i] >= 1 && us->Buffer[i] <= 31)))) 5136 return FALSE; 5137 } 5138 5139 if (us->Buffer[0] == '.' && (us->Length == sizeof(WCHAR) || (us->Length == 2 * sizeof(WCHAR) && us->Buffer[1] == '.'))) 5140 return FALSE; 5141 5142 return TRUE; 5143 } 5144 5145 void chunk_lock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ UINT64 start, _In_ UINT64 length) { 5146 LIST_ENTRY* le; 5147 BOOL locked; 5148 range_lock* rl; 5149 5150 rl = ExAllocateFromNPagedLookasideList(&Vcb->range_lock_lookaside); 5151 if (!rl) { 5152 ERR("out of memory\n"); 5153 return; 5154 } 5155 5156 rl->start = start; 5157 rl->length = length; 5158 rl->thread = PsGetCurrentThread(); 5159 5160 while (TRUE) { 5161 locked = FALSE; 5162 5163 ExAcquireResourceExclusiveLite(&c->range_locks_lock, TRUE); 5164 5165 le = c->range_locks.Flink; 5166 while (le != &c->range_locks) { 5167 range_lock* rl2 = CONTAINING_RECORD(le, range_lock, list_entry); 5168 5169 if (rl2->start < start + length && rl2->start + rl2->length > start && rl2->thread != PsGetCurrentThread()) { 5170 locked = TRUE; 5171 break; 5172 } 5173 5174 le = le->Flink; 5175 } 5176 5177 if (!locked) { 5178 InsertTailList(&c->range_locks, &rl->list_entry); 5179 5180 ExReleaseResourceLite(&c->range_locks_lock); 5181 return; 5182 } 5183 5184 KeClearEvent(&c->range_locks_event); 5185 5186 ExReleaseResourceLite(&c->range_locks_lock); 5187 5188 KeWaitForSingleObject(&c->range_locks_event, UserRequest, KernelMode, FALSE, NULL); 5189 } 5190 } 5191 5192 void chunk_unlock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ UINT64 start, _In_ UINT64 length) { 5193 LIST_ENTRY* le; 5194 5195 ExAcquireResourceExclusiveLite(&c->range_locks_lock, TRUE); 5196 5197 le = c->range_locks.Flink; 5198 while (le != &c->range_locks) { 5199 range_lock* rl = CONTAINING_RECORD(le, range_lock, list_entry); 5200 5201 if (rl->start == start && rl->length == length) { 5202 RemoveEntryList(&rl->list_entry); 5203 ExFreeToNPagedLookasideList(&Vcb->range_lock_lookaside, rl); 5204 break; 5205 } 5206 5207 le = le->Flink; 5208 } 5209 5210 KeSetEvent(&c->range_locks_event, 0, FALSE); 5211 5212 ExReleaseResourceLite(&c->range_locks_lock); 5213 } 5214 5215 void log_device_error(_In_ device_extension* Vcb, _Inout_ device* dev, _In_ int error) { 5216 dev->stats[error]++; 5217 dev->stats_changed = TRUE; 5218 Vcb->stats_changed = TRUE; 5219 } 5220 5221 #ifdef _DEBUG 5222 _Function_class_(KSTART_ROUTINE) 5223 static void serial_thread(void* context) { 5224 LARGE_INTEGER due_time; 5225 KTIMER timer; 5226 5227 UNUSED(context); 5228 5229 KeInitializeTimer(&timer); 5230 5231 due_time.QuadPart = (UINT64)-10000000; 5232 5233 KeSetTimer(&timer, due_time, NULL); 5234 5235 while (TRUE) { 5236 KeWaitForSingleObject(&timer, Executive, KernelMode, FALSE, NULL); 5237 5238 init_serial(FALSE); 5239 5240 if (comdo) 5241 break; 5242 5243 KeSetTimer(&timer, due_time, NULL); 5244 } 5245 5246 KeCancelTimer(&timer); 5247 5248 PsTerminateSystemThread(STATUS_SUCCESS); 5249 5250 serial_thread_handle = NULL; 5251 } 5252 5253 static void init_serial(BOOL first_time) { 5254 NTSTATUS Status; 5255 5256 Status = IoGetDeviceObjectPointer(&log_device, FILE_WRITE_DATA, &comfo, &comdo); 5257 if (!NT_SUCCESS(Status)) { 5258 ERR("IoGetDeviceObjectPointer returned %08x\n", Status); 5259 5260 if (first_time) { 5261 NTSTATUS Status; 5262 5263 Status = PsCreateSystemThread(&serial_thread_handle, 0, NULL, NULL, NULL, serial_thread, NULL); 5264 if (!NT_SUCCESS(Status)) { 5265 ERR("PsCreateSystemThread returned %08x\n", Status); 5266 return; 5267 } 5268 } 5269 } 5270 } 5271 #endif 5272 5273 #ifndef __REACTOS__ 5274 static void check_cpu() { 5275 unsigned int cpuInfo[4]; 5276 #ifndef _MSC_VER 5277 __get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3]); 5278 have_sse42 = cpuInfo[2] & bit_SSE4_2; 5279 have_sse2 = cpuInfo[3] & bit_SSE2; 5280 #else 5281 __cpuid(cpuInfo, 1); 5282 have_sse42 = cpuInfo[2] & (1 << 20); 5283 have_sse2 = cpuInfo[3] & (1 << 26); 5284 #endif 5285 5286 if (have_sse42) 5287 TRACE("SSE4.2 is supported\n"); 5288 else 5289 TRACE("SSE4.2 not supported\n"); 5290 5291 if (have_sse2) 5292 TRACE("SSE2 is supported\n"); 5293 else 5294 TRACE("SSE2 is not supported\n"); 5295 } 5296 #endif 5297 5298 #ifdef _DEBUG 5299 static void init_logging() { 5300 ExAcquireResourceExclusiveLite(&log_lock, TRUE); 5301 5302 if (log_device.Length > 0) 5303 init_serial(TRUE); 5304 else if (log_file.Length > 0) { 5305 NTSTATUS Status; 5306 OBJECT_ATTRIBUTES oa; 5307 IO_STATUS_BLOCK iosb; 5308 char* dateline; 5309 LARGE_INTEGER time; 5310 TIME_FIELDS tf; 5311 5312 InitializeObjectAttributes(&oa, &log_file, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); 5313 5314 Status = ZwCreateFile(&log_handle, FILE_WRITE_DATA, &oa, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, 5315 FILE_OPEN_IF, FILE_NON_DIRECTORY_FILE | FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_ALERT, NULL, 0); 5316 5317 if (!NT_SUCCESS(Status)) { 5318 ERR("ZwCreateFile returned %08x\n", Status); 5319 goto end; 5320 } 5321 5322 if (iosb.Information == FILE_OPENED) { // already exists 5323 FILE_STANDARD_INFORMATION fsi; 5324 FILE_POSITION_INFORMATION fpi; 5325 5326 static const char delim[] = "\n---\n"; 5327 5328 // move to end of file 5329 5330 Status = ZwQueryInformationFile(log_handle, &iosb, &fsi, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); 5331 5332 if (!NT_SUCCESS(Status)) { 5333 ERR("ZwQueryInformationFile returned %08x\n", Status); 5334 goto end; 5335 } 5336 5337 fpi.CurrentByteOffset = fsi.EndOfFile; 5338 5339 Status = ZwSetInformationFile(log_handle, &iosb, &fpi, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation); 5340 5341 if (!NT_SUCCESS(Status)) { 5342 ERR("ZwSetInformationFile returned %08x\n", Status); 5343 goto end; 5344 } 5345 5346 Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, (void*)delim, sizeof(delim) - 1, NULL, NULL); 5347 5348 if (!NT_SUCCESS(Status)) { 5349 ERR("ZwWriteFile returned %08x\n", Status); 5350 goto end; 5351 } 5352 } 5353 5354 dateline = ExAllocatePoolWithTag(PagedPool, 256, ALLOC_TAG); 5355 5356 if (!dateline) { 5357 ERR("out of memory\n"); 5358 goto end; 5359 } 5360 5361 KeQuerySystemTime(&time); 5362 5363 RtlTimeToTimeFields(&time, &tf); 5364 5365 sprintf(dateline, "Starting logging at %04i-%02i-%02i %02i:%02i:%02i\n", tf.Year, tf.Month, tf.Day, tf.Hour, tf.Minute, tf.Second); 5366 5367 Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, dateline, (ULONG)strlen(dateline), NULL, NULL); 5368 5369 ExFreePool(dateline); 5370 5371 if (!NT_SUCCESS(Status)) { 5372 ERR("ZwWriteFile returned %08x\n", Status); 5373 goto end; 5374 } 5375 } 5376 5377 end: 5378 ExReleaseResourceLite(&log_lock); 5379 } 5380 #endif 5381 5382 _Function_class_(KSTART_ROUTINE) 5383 #ifdef __REACTOS__ 5384 static void NTAPI degraded_wait_thread(_In_ void* context) { 5385 #else 5386 static void degraded_wait_thread(_In_ void* context) { 5387 #endif 5388 KTIMER timer; 5389 LARGE_INTEGER delay; 5390 5391 UNUSED(context); 5392 5393 KeInitializeTimer(&timer); 5394 5395 delay.QuadPart = -30000000; // wait three seconds 5396 KeSetTimer(&timer, delay, NULL); 5397 KeWaitForSingleObject(&timer, Executive, KernelMode, FALSE, NULL); 5398 5399 TRACE("timer expired\n"); 5400 5401 degraded_wait = FALSE; 5402 5403 ZwClose(degraded_wait_handle); 5404 degraded_wait_handle = NULL; 5405 5406 PsTerminateSystemThread(STATUS_SUCCESS); 5407 } 5408 5409 #ifdef __REACTOS__ 5410 NTSTATUS NTAPI AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject) { 5411 #else 5412 NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject) { 5413 #endif 5414 LIST_ENTRY* le; 5415 NTSTATUS Status; 5416 UNICODE_STRING volname; 5417 ULONG i, j; 5418 pdo_device_extension* pdode = NULL; 5419 PDEVICE_OBJECT voldev; 5420 volume_device_extension* vde; 5421 5422 TRACE("(%p, %p)\n", DriverObject, PhysicalDeviceObject); 5423 5424 ExAcquireResourceSharedLite(&pdo_list_lock, TRUE); 5425 5426 le = pdo_list.Flink; 5427 while (le != &pdo_list) { 5428 pdo_device_extension* pdode2 = CONTAINING_RECORD(le, pdo_device_extension, list_entry); 5429 5430 if (pdode2->pdo == PhysicalDeviceObject) { 5431 pdode = pdode2; 5432 break; 5433 } 5434 5435 le = le->Flink; 5436 } 5437 5438 if (!pdode) { 5439 WARN("unrecognized PDO %p\n", PhysicalDeviceObject); 5440 Status = STATUS_NOT_SUPPORTED; 5441 goto end; 5442 } 5443 5444 ExAcquireResourceSharedLite(&pdode->child_lock, TRUE); 5445 5446 volname.Length = volname.MaximumLength = (sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) + ((36 + 1) * sizeof(WCHAR)); 5447 volname.Buffer = ExAllocatePoolWithTag(PagedPool, volname.MaximumLength, ALLOC_TAG); // FIXME - when do we free this? 5448 5449 if (!volname.Buffer) { 5450 ERR("out of memory\n"); 5451 Status = STATUS_INSUFFICIENT_RESOURCES; 5452 goto end2; 5453 } 5454 5455 RtlCopyMemory(volname.Buffer, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)); 5456 5457 j = (sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1; 5458 for (i = 0; i < 16; i++) { 5459 volname.Buffer[j] = hex_digit(pdode->uuid.uuid[i] >> 4); j++; 5460 volname.Buffer[j] = hex_digit(pdode->uuid.uuid[i] & 0xf); j++; 5461 5462 if (i == 3 || i == 5 || i == 7 || i == 9) { 5463 volname.Buffer[j] = '-'; 5464 j++; 5465 } 5466 } 5467 5468 volname.Buffer[j] = '}'; 5469 5470 Status = IoCreateDevice(drvobj, sizeof(volume_device_extension), &volname, FILE_DEVICE_DISK, 5471 RtlIsNtDdiVersionAvailable(NTDDI_WIN8) ? FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL : 0, FALSE, &voldev); 5472 if (!NT_SUCCESS(Status)) { 5473 ERR("IoCreateDevice returned %08x\n", Status); 5474 goto end2; 5475 } 5476 5477 voldev->SectorSize = PhysicalDeviceObject->SectorSize; 5478 voldev->Flags |= DO_DIRECT_IO; 5479 5480 vde = voldev->DeviceExtension; 5481 vde->type = VCB_TYPE_VOLUME; 5482 vde->name = volname; 5483 vde->device = voldev; 5484 vde->mounted_device = NULL; 5485 vde->pdo = PhysicalDeviceObject; 5486 vde->pdode = pdode; 5487 vde->removing = FALSE; 5488 vde->open_count = 0; 5489 5490 Status = IoRegisterDeviceInterface(PhysicalDeviceObject, &GUID_DEVINTERFACE_VOLUME, NULL, &vde->bus_name); 5491 if (!NT_SUCCESS(Status)) 5492 WARN("IoRegisterDeviceInterface returned %08x\n", Status); 5493 5494 vde->attached_device = IoAttachDeviceToDeviceStack(voldev, PhysicalDeviceObject); 5495 5496 pdode->vde = vde; 5497 5498 if (pdode->removable) 5499 voldev->Characteristics |= FILE_REMOVABLE_MEDIA; 5500 5501 voldev->Flags &= ~DO_DEVICE_INITIALIZING; 5502 5503 Status = IoSetDeviceInterfaceState(&vde->bus_name, TRUE); 5504 if (!NT_SUCCESS(Status)) 5505 WARN("IoSetDeviceInterfaceState returned %08x\n", Status); 5506 5507 Status = STATUS_SUCCESS; 5508 5509 end2: 5510 ExReleaseResourceLite(&pdode->child_lock); 5511 5512 end: 5513 ExReleaseResourceLite(&pdo_list_lock); 5514 5515 return Status; 5516 } 5517 5518 _Function_class_(DRIVER_INITIALIZE) 5519 #ifdef __REACTOS__ 5520 NTSTATUS NTAPI DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { 5521 #else 5522 NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) { 5523 #endif 5524 NTSTATUS Status; 5525 PDEVICE_OBJECT DeviceObject; 5526 UNICODE_STRING device_nameW; 5527 UNICODE_STRING dosdevice_nameW; 5528 control_device_extension* cde; 5529 HANDLE regh; 5530 OBJECT_ATTRIBUTES oa; 5531 ULONG dispos; 5532 5533 InitializeListHead(&uid_map_list); 5534 InitializeListHead(&gid_map_list); 5535 5536 #ifdef _DEBUG 5537 ExInitializeResourceLite(&log_lock); 5538 #endif 5539 ExInitializeResourceLite(&mapping_lock); 5540 5541 log_device.Buffer = NULL; 5542 log_device.Length = log_device.MaximumLength = 0; 5543 log_file.Buffer = NULL; 5544 log_file.Length = log_file.MaximumLength = 0; 5545 5546 registry_path.Length = registry_path.MaximumLength = RegistryPath->Length; 5547 registry_path.Buffer = ExAllocatePoolWithTag(PagedPool, registry_path.Length, ALLOC_TAG); 5548 5549 if (!registry_path.Buffer) { 5550 ERR("out of memory\n"); 5551 return STATUS_INSUFFICIENT_RESOURCES; 5552 } 5553 5554 RtlCopyMemory(registry_path.Buffer, RegistryPath->Buffer, registry_path.Length); 5555 5556 read_registry(®istry_path, FALSE); 5557 5558 #ifdef _DEBUG 5559 if (debug_log_level > 0) 5560 init_logging(); 5561 5562 log_started = TRUE; 5563 #endif 5564 5565 TRACE("DriverEntry\n"); 5566 5567 #ifndef __REACTOS__ 5568 check_cpu(); 5569 #endif 5570 5571 if (RtlIsNtDdiVersionAvailable(NTDDI_WIN8)) { 5572 UNICODE_STRING name; 5573 tPsIsDiskCountersEnabled fPsIsDiskCountersEnabled; 5574 5575 RtlInitUnicodeString(&name, L"PsIsDiskCountersEnabled"); 5576 fPsIsDiskCountersEnabled = (tPsIsDiskCountersEnabled)MmGetSystemRoutineAddress(&name); 5577 5578 if (fPsIsDiskCountersEnabled) { 5579 diskacc = fPsIsDiskCountersEnabled(); 5580 5581 RtlInitUnicodeString(&name, L"PsUpdateDiskCounters"); 5582 fPsUpdateDiskCounters = (tPsUpdateDiskCounters)MmGetSystemRoutineAddress(&name); 5583 5584 if (!fPsUpdateDiskCounters) 5585 diskacc = FALSE; 5586 5587 RtlInitUnicodeString(&name, L"FsRtlUpdateDiskCounters"); 5588 fFsRtlUpdateDiskCounters = (tFsRtlUpdateDiskCounters)MmGetSystemRoutineAddress(&name); 5589 } 5590 5591 RtlInitUnicodeString(&name, L"CcCopyReadEx"); 5592 fCcCopyReadEx = (tCcCopyReadEx)MmGetSystemRoutineAddress(&name); 5593 5594 RtlInitUnicodeString(&name, L"CcCopyWriteEx"); 5595 fCcCopyWriteEx = (tCcCopyWriteEx)MmGetSystemRoutineAddress(&name); 5596 5597 RtlInitUnicodeString(&name, L"CcSetAdditionalCacheAttributesEx"); 5598 fCcSetAdditionalCacheAttributesEx = (tCcSetAdditionalCacheAttributesEx)MmGetSystemRoutineAddress(&name); 5599 } else { 5600 fPsUpdateDiskCounters = NULL; 5601 fCcCopyReadEx = NULL; 5602 fCcCopyWriteEx = NULL; 5603 fCcSetAdditionalCacheAttributesEx = NULL; 5604 fFsRtlUpdateDiskCounters = NULL; 5605 } 5606 5607 drvobj = DriverObject; 5608 5609 DriverObject->DriverUnload = DriverUnload; 5610 5611 DriverObject->DriverExtension->AddDevice = AddDevice; 5612 5613 #ifdef __REACTOS__ 5614 DriverObject->MajorFunction[IRP_MJ_CREATE] = drv_create; 5615 DriverObject->MajorFunction[IRP_MJ_CLOSE] = drv_close; 5616 DriverObject->MajorFunction[IRP_MJ_READ] = drv_read; 5617 DriverObject->MajorFunction[IRP_MJ_WRITE] = drv_write; 5618 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = drv_query_information; 5619 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = drv_set_information; 5620 DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = drv_query_ea; 5621 DriverObject->MajorFunction[IRP_MJ_SET_EA] = drv_set_ea; 5622 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = drv_flush_buffers; 5623 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = drv_query_volume_information; 5624 DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = drv_set_volume_information; 5625 DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = drv_directory_control; 5626 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = drv_file_system_control; 5627 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = drv_device_control; 5628 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = drv_shutdown; 5629 DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = drv_lock_control; 5630 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = drv_cleanup; 5631 DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = drv_query_security; 5632 DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = drv_set_security; 5633 DriverObject->MajorFunction[IRP_MJ_POWER] = drv_power; 5634 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = drv_system_control; 5635 DriverObject->MajorFunction[IRP_MJ_PNP] = drv_pnp; 5636 #else 5637 DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)drv_create; 5638 DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)drv_close; 5639 DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)drv_read; 5640 DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)drv_write; 5641 DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)drv_query_information; 5642 DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)drv_set_information; 5643 DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = (PDRIVER_DISPATCH)drv_query_ea; 5644 DriverObject->MajorFunction[IRP_MJ_SET_EA] = (PDRIVER_DISPATCH)drv_set_ea; 5645 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = (PDRIVER_DISPATCH)drv_flush_buffers; 5646 DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)drv_query_volume_information; 5647 DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)drv_set_volume_information; 5648 DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = (PDRIVER_DISPATCH)drv_directory_control; 5649 DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)drv_file_system_control; 5650 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)drv_device_control; 5651 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = (PDRIVER_DISPATCH)drv_shutdown; 5652 DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = (PDRIVER_DISPATCH)drv_lock_control; 5653 DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)drv_cleanup; 5654 DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = (PDRIVER_DISPATCH)drv_query_security; 5655 DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = (PDRIVER_DISPATCH)drv_set_security; 5656 DriverObject->MajorFunction[IRP_MJ_POWER] = (PDRIVER_DISPATCH)drv_power; 5657 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)drv_system_control; 5658 DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)drv_pnp; 5659 #endif 5660 5661 init_fast_io_dispatch(&DriverObject->FastIoDispatch); 5662 5663 device_nameW.Buffer = (WCHAR*)device_name; 5664 device_nameW.Length = device_nameW.MaximumLength = sizeof(device_name) - sizeof(WCHAR); 5665 dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name; 5666 dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) - sizeof(WCHAR); 5667 5668 Status = IoCreateDevice(DriverObject, sizeof(control_device_extension), &device_nameW, FILE_DEVICE_DISK_FILE_SYSTEM, 5669 FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject); 5670 if (!NT_SUCCESS(Status)) { 5671 ERR("IoCreateDevice returned %08x\n", Status); 5672 return Status; 5673 } 5674 5675 master_devobj = DeviceObject; 5676 cde = (control_device_extension*)master_devobj->DeviceExtension; 5677 5678 RtlZeroMemory(cde, sizeof(control_device_extension)); 5679 5680 cde->type = VCB_TYPE_CONTROL; 5681 5682 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 5683 5684 Status = IoCreateSymbolicLink(&dosdevice_nameW, &device_nameW); 5685 if (!NT_SUCCESS(Status)) { 5686 ERR("IoCreateSymbolicLink returned %08x\n", Status); 5687 return Status; 5688 } 5689 5690 Status = init_cache(); 5691 if (!NT_SUCCESS(Status)) { 5692 ERR("init_cache returned %08x\n", Status); 5693 return Status; 5694 } 5695 5696 InitializeListHead(&VcbList); 5697 ExInitializeResourceLite(&global_loading_lock); 5698 ExInitializeResourceLite(&pdo_list_lock); 5699 5700 InitializeListHead(&pdo_list); 5701 5702 InitializeObjectAttributes(&oa, RegistryPath, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); 5703 Status = ZwCreateKey(®h, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS | KEY_NOTIFY, &oa, 0, NULL, REG_OPTION_NON_VOLATILE, &dispos); 5704 /* ReactOS specific hack: allow BtrFS driver to start in 1st stage with no hive */ 5705 #ifndef __REACTOS__ 5706 if (!NT_SUCCESS(Status)) { 5707 ERR("ZwCreateKey returned %08x\n", Status); 5708 return Status; 5709 } 5710 5711 watch_registry(regh); 5712 #else 5713 if (NT_SUCCESS(Status)) { 5714 watch_registry(regh); 5715 } 5716 #endif 5717 5718 Status = IoReportDetectedDevice(drvobj, InterfaceTypeUndefined, 0xFFFFFFFF, 0xFFFFFFFF, 5719 NULL, NULL, 0, &cde->buspdo); 5720 if (!NT_SUCCESS(Status)) { 5721 ERR("IoReportDetectedDevice returned %08x\n", Status); 5722 return Status; 5723 } 5724 5725 Status = IoRegisterDeviceInterface(cde->buspdo, &BtrfsBusInterface, NULL, &cde->bus_name); 5726 if (!NT_SUCCESS(Status)) 5727 WARN("IoRegisterDeviceInterface returned %08x\n", Status); 5728 5729 cde->attached_device = IoAttachDeviceToDeviceStack(DeviceObject, cde->buspdo); 5730 5731 Status = IoSetDeviceInterfaceState(&cde->bus_name, TRUE); 5732 if (!NT_SUCCESS(Status)) 5733 WARN("IoSetDeviceInterfaceState returned %08x\n", Status); 5734 5735 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 5736 5737 IoInvalidateDeviceRelations(cde->buspdo, BusRelations); 5738 5739 Status = PsCreateSystemThread(°raded_wait_handle, 0, NULL, NULL, NULL, degraded_wait_thread, NULL); 5740 if (!NT_SUCCESS(Status)) 5741 WARN("PsCreateSystemThread returned %08x\n", Status); 5742 5743 Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, 5744 (PVOID)&GUID_DEVINTERFACE_VOLUME, DriverObject, volume_notification, DriverObject, ¬ification_entry2); 5745 if (!NT_SUCCESS(Status)) 5746 ERR("IoRegisterPlugPlayNotification returned %08x\n", Status); 5747 5748 Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, 5749 (PVOID)&GUID_DEVINTERFACE_HIDDEN_VOLUME, DriverObject, volume_notification, DriverObject, ¬ification_entry3); 5750 if (!NT_SUCCESS(Status)) 5751 ERR("IoRegisterPlugPlayNotification returned %08x\n", Status); 5752 5753 Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, 5754 (PVOID)&GUID_DEVINTERFACE_DISK, DriverObject, pnp_notification, DriverObject, ¬ification_entry); 5755 if (!NT_SUCCESS(Status)) 5756 ERR("IoRegisterPlugPlayNotification returned %08x\n", Status); 5757 5758 finished_probing = TRUE; 5759 5760 KeInitializeEvent(&mountmgr_thread_event, NotificationEvent, FALSE); 5761 5762 #ifndef __REACTOS__ 5763 Status = PsCreateSystemThread(&mountmgr_thread_handle, 0, NULL, NULL, NULL, mountmgr_thread, NULL); 5764 if (!NT_SUCCESS(Status)) 5765 WARN("PsCreateSystemThread returned %08x\n", Status); 5766 #endif 5767 5768 IoRegisterFileSystem(DeviceObject); 5769 5770 return STATUS_SUCCESS; 5771 } 5772