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