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