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