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 #define ISOLATION_AWARE_ENABLED 1 19 #define STRSAFE_NO_DEPRECATE 20 21 #include "shellext.h" 22 #ifndef __REACTOS__ 23 #include <windows.h> 24 #include <strsafe.h> 25 #include <winternl.h> 26 #else 27 #define WIN32_NO_STATUS 28 #include <windef.h> 29 #include <winbase.h> 30 #include <strsafe.h> 31 #include <ndk/iofuncs.h> 32 #include <ndk/iotypes.h> 33 #endif 34 35 #define NO_SHLWAPI_STRFCNS 36 #include <shlwapi.h> 37 #include <uxtheme.h> 38 39 #include "volpropsheet.h" 40 #include "resource.h" 41 42 HRESULT __stdcall BtrfsVolPropSheet::QueryInterface(REFIID riid, void **ppObj) { 43 if (riid == IID_IUnknown || riid == IID_IShellPropSheetExt) { 44 *ppObj = static_cast<IShellPropSheetExt*>(this); 45 AddRef(); 46 return S_OK; 47 } else if (riid == IID_IShellExtInit) { 48 *ppObj = static_cast<IShellExtInit*>(this); 49 AddRef(); 50 return S_OK; 51 } 52 53 *ppObj = nullptr; 54 return E_NOINTERFACE; 55 } 56 57 HRESULT __stdcall BtrfsVolPropSheet::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgID) { 58 ULONG num_files; 59 FORMATETC format = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 60 HDROP hdrop; 61 WCHAR fnbuf[MAX_PATH]; 62 63 if (pidlFolder) 64 return E_FAIL; 65 66 if (!pdtobj) 67 return E_FAIL; 68 69 stgm.tymed = TYMED_HGLOBAL; 70 71 if (FAILED(pdtobj->GetData(&format, &stgm))) 72 return E_INVALIDARG; 73 74 stgm_set = true; 75 76 hdrop = (HDROP)GlobalLock(stgm.hGlobal); 77 78 if (!hdrop) { 79 ReleaseStgMedium(&stgm); 80 stgm_set = false; 81 return E_INVALIDARG; 82 } 83 84 num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, nullptr, 0); 85 86 if (num_files > 1) { 87 GlobalUnlock(hdrop); 88 return E_FAIL; 89 } 90 91 if (DragQueryFileW((HDROP)stgm.hGlobal, 0, fnbuf, sizeof(fnbuf) / sizeof(MAX_PATH))) { 92 fn = fnbuf; 93 94 win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 95 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 96 97 if (h != INVALID_HANDLE_VALUE) { 98 NTSTATUS Status; 99 IO_STATUS_BLOCK iosb; 100 ULONG devsize, i; 101 102 i = 0; 103 devsize = 1024; 104 105 devices = (btrfs_device*)malloc(devsize); 106 107 while (true) { 108 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_DEVICES, nullptr, 0, devices, devsize); 109 if (Status == STATUS_BUFFER_OVERFLOW) { 110 if (i < 8) { 111 devsize += 1024; 112 113 free(devices); 114 devices = (btrfs_device*)malloc(devsize); 115 116 i++; 117 } else { 118 GlobalUnlock(hdrop); 119 return E_FAIL; 120 } 121 } else 122 break; 123 } 124 125 if (!NT_SUCCESS(Status)) { 126 GlobalUnlock(hdrop); 127 return E_FAIL; 128 } 129 130 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_UUID, nullptr, 0, &uuid, sizeof(BTRFS_UUID)); 131 uuid_set = NT_SUCCESS(Status); 132 133 ignore = false; 134 balance = new BtrfsBalance(fn); 135 } else { 136 GlobalUnlock(hdrop); 137 return E_FAIL; 138 } 139 } else { 140 GlobalUnlock(hdrop); 141 return E_FAIL; 142 } 143 144 GlobalUnlock(hdrop); 145 146 return S_OK; 147 } 148 149 typedef struct { 150 uint64_t dev_id; 151 wstring name; 152 uint64_t alloc; 153 uint64_t size; 154 } dev; 155 156 void BtrfsVolPropSheet::FormatUsage(HWND hwndDlg, wstring& s, btrfs_usage* usage) { 157 uint8_t i, j; 158 uint64_t num_devs, dev_size, dev_alloc, data_size, data_alloc, metadata_size, metadata_alloc; 159 btrfs_device* bd; 160 vector<dev> devs; 161 btrfs_usage* bue; 162 wstring t, u, v; 163 164 static const uint64_t types[] = { BLOCK_FLAG_DATA, BLOCK_FLAG_DATA | BLOCK_FLAG_METADATA, BLOCK_FLAG_METADATA, BLOCK_FLAG_SYSTEM }; 165 static const ULONG typestrings[] = { IDS_USAGE_DATA, IDS_USAGE_MIXED, IDS_USAGE_METADATA, IDS_USAGE_SYSTEM }; 166 static const uint64_t duptypes[] = { 0, BLOCK_FLAG_DUPLICATE, BLOCK_FLAG_RAID0, BLOCK_FLAG_RAID1, BLOCK_FLAG_RAID10, BLOCK_FLAG_RAID5, BLOCK_FLAG_RAID6 }; 167 static const ULONG dupstrings[] = { IDS_SINGLE, IDS_DUP, IDS_RAID0, IDS_RAID1, IDS_RAID10, IDS_RAID5, IDS_RAID6 }; 168 169 s = L""; 170 171 num_devs = 0; 172 bd = devices; 173 174 while (true) { 175 num_devs++; 176 177 if (bd->next_entry > 0) 178 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 179 else 180 break; 181 } 182 183 bd = devices; 184 185 dev_size = 0; 186 187 while (true) { 188 dev d; 189 190 if (bd->missing) { 191 if (!load_string(module, IDS_MISSING, d.name)) 192 throw last_error(GetLastError()); 193 } else if (bd->device_number == 0xffffffff) 194 d.name = wstring(bd->name, bd->namelen / sizeof(WCHAR)); 195 else if (bd->partition_number == 0) { 196 if (!load_string(module, IDS_DISK_NUM, u)) 197 throw last_error(GetLastError()); 198 199 wstring_sprintf(d.name, u, bd->device_number); 200 } else { 201 if (!load_string(module, IDS_DISK_PART_NUM, u)) 202 throw last_error(GetLastError()); 203 204 wstring_sprintf(d.name, u, bd->device_number, bd->partition_number); 205 } 206 207 d.dev_id = bd->dev_id; 208 d.alloc = 0; 209 d.size = bd->size; 210 211 devs.push_back(d); 212 213 dev_size += bd->size; 214 215 if (bd->next_entry > 0) 216 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 217 else 218 break; 219 } 220 221 dev_alloc = 0; 222 data_size = data_alloc = 0; 223 metadata_size = metadata_alloc = 0; 224 225 bue = usage; 226 while (true) { 227 for (uint64_t k = 0; k < bue->num_devices; k++) { 228 dev_alloc += bue->devices[k].alloc; 229 230 if (bue->type & BLOCK_FLAG_DATA) { 231 data_alloc += bue->devices[k].alloc; 232 } 233 234 if (bue->type & BLOCK_FLAG_METADATA) { 235 metadata_alloc += bue->devices[k].alloc; 236 } 237 } 238 239 if (bue->type & BLOCK_FLAG_DATA) 240 data_size += bue->size; 241 242 if (bue->type & BLOCK_FLAG_METADATA) 243 metadata_size += bue->size; 244 245 if (bue->next_entry > 0) 246 bue = (btrfs_usage*)((uint8_t*)bue + bue->next_entry); 247 else 248 break; 249 } 250 251 // device size 252 253 if (!load_string(module, IDS_USAGE_DEV_SIZE, u)) 254 throw last_error(GetLastError()); 255 256 format_size(dev_size, v, false); 257 258 wstring_sprintf(t, u, v.c_str()); 259 260 s += t + L"\r\n"; 261 262 // device allocated 263 264 if (!load_string(module, IDS_USAGE_DEV_ALLOC, u)) 265 throw last_error(GetLastError()); 266 267 format_size(dev_alloc, v, false); 268 269 wstring_sprintf(t, u, v.c_str()); 270 271 #ifndef __REACTOS__ 272 s += t + L"\r\n"s; 273 #else 274 s += t + L"\r\n"; 275 #endif 276 277 // device unallocated 278 279 if (!load_string(module, IDS_USAGE_DEV_UNALLOC, u)) 280 throw last_error(GetLastError()); 281 282 format_size(dev_size - dev_alloc, v, false); 283 284 wstring_sprintf(t, u, v.c_str()); 285 286 #ifndef __REACTOS__ 287 s += t + L"\r\n"s; 288 #else 289 s += t + L"\r\n"; 290 #endif 291 292 // data ratio 293 294 if (data_alloc > 0) { 295 if (!load_string(module, IDS_USAGE_DATA_RATIO, u)) 296 throw last_error(GetLastError()); 297 298 wstring_sprintf(t, u, (float)data_alloc / (float)data_size); 299 300 #ifndef __REACTOS__ 301 s += t + L"\r\n"s; 302 #else 303 s += t + L"\r\n"; 304 #endif 305 } 306 307 // metadata ratio 308 309 if (!load_string(module, IDS_USAGE_METADATA_RATIO, u)) 310 throw last_error(GetLastError()); 311 312 wstring_sprintf(t, u, (float)metadata_alloc / (float)metadata_size); 313 314 s += t + L"\r\n\r\n"; 315 316 for (i = 0; i < sizeof(types) / sizeof(types[0]); i++) { 317 for (j = 0; j < sizeof(duptypes) / sizeof(duptypes[0]); j++) { 318 bue = usage; 319 320 while (true) { 321 if ((bue->type & types[i]) == types[i] && 322 ((duptypes[j] == 0 && (bue->type & (BLOCK_FLAG_DUPLICATE | BLOCK_FLAG_RAID0 | BLOCK_FLAG_RAID1 | BLOCK_FLAG_RAID10 | BLOCK_FLAG_RAID5 | BLOCK_FLAG_RAID6)) == 0) 323 || bue->type & duptypes[j])) { 324 wstring sizestring, usedstring, typestring, dupstring; 325 326 if (bue->type & BLOCK_FLAG_DATA && bue->type & BLOCK_FLAG_METADATA && (types[i] == BLOCK_FLAG_DATA || types[i] == BLOCK_FLAG_METADATA)) 327 break; 328 329 if (!load_string(module, typestrings[i], typestring)) 330 throw last_error(GetLastError()); 331 332 if (!load_string(module, dupstrings[j], dupstring)) 333 throw last_error(GetLastError()); 334 335 format_size(bue->size, sizestring, false); 336 format_size(bue->used, usedstring, false); 337 338 wstring_sprintf(t, typestring, dupstring.c_str(), sizestring.c_str(), usedstring.c_str()); 339 340 s += t + L"\r\n"; 341 342 for (uint64_t k = 0; k < bue->num_devices; k++) { 343 bool found = false; 344 345 format_size(bue->devices[k].alloc, sizestring, false); 346 347 for (size_t l = 0; l < min((uint64_t)SIZE_MAX, num_devs); l++) { 348 if (devs[l].dev_id == bue->devices[k].dev_id) { 349 s += devs[l].name + L"\t" + sizestring + L"\r\n"; 350 351 devs[l].alloc += bue->devices[k].alloc; 352 353 found = true; 354 break; 355 } 356 } 357 358 if (!found) { 359 if (!load_string(module, IDS_UNKNOWN_DEVICE, typestring)) 360 throw last_error(GetLastError()); 361 362 wstring_sprintf(t, typestring, bue->devices[k].dev_id); 363 364 #ifndef __REACTOS__ 365 s += t + L"\t"s + sizestring + L"\r\n"s; 366 #else 367 s += t + L"\t" + sizestring + L"\r\n"; 368 #endif 369 } 370 } 371 372 s += L"\r\n"; 373 374 break; 375 } 376 377 if (bue->next_entry > 0) 378 bue = (btrfs_usage*)((uint8_t*)bue + bue->next_entry); 379 else 380 break; 381 } 382 } 383 } 384 385 if (!load_string(module, IDS_USAGE_UNALLOC, t)) 386 throw last_error(GetLastError()); 387 388 #ifndef __REACTOS__ 389 s += t + L"\r\n"s; 390 #else 391 s += t + L"\r\n"; 392 #endif 393 394 for (size_t k = 0; k < min((uint64_t)SIZE_MAX, num_devs); k++) { 395 wstring sizestring; 396 397 format_size(devs[k].size - devs[k].alloc, sizestring, false); 398 399 s += devs[k].name + L"\t" + sizestring + L"\r\n"; 400 } 401 } 402 403 void BtrfsVolPropSheet::RefreshUsage(HWND hwndDlg) { 404 wstring s; 405 btrfs_usage* usage; 406 407 win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 408 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 409 410 if (h != INVALID_HANDLE_VALUE) { 411 NTSTATUS Status; 412 IO_STATUS_BLOCK iosb; 413 ULONG devsize, usagesize, i; 414 415 i = 0; 416 devsize = 1024; 417 418 devices = (btrfs_device*)malloc(devsize); 419 420 while (true) { 421 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_DEVICES, nullptr, 0, devices, devsize); 422 if (Status == STATUS_BUFFER_OVERFLOW) { 423 if (i < 8) { 424 devsize += 1024; 425 426 free(devices); 427 devices = (btrfs_device*)malloc(devsize); 428 429 i++; 430 } else 431 return; 432 } else 433 break; 434 } 435 436 if (!NT_SUCCESS(Status)) 437 return; 438 439 i = 0; 440 usagesize = 1024; 441 442 usage = (btrfs_usage*)malloc(usagesize); 443 444 while (true) { 445 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_USAGE, nullptr, 0, usage, usagesize); 446 if (Status == STATUS_BUFFER_OVERFLOW) { 447 if (i < 8) { 448 usagesize += 1024; 449 450 free(usage); 451 usage = (btrfs_usage*)malloc(usagesize); 452 453 i++; 454 } else 455 return; 456 } else 457 break; 458 } 459 460 if (!NT_SUCCESS(Status)) { 461 free(usage); 462 return; 463 } 464 465 ignore = false; 466 } else 467 return; 468 469 FormatUsage(hwndDlg, s, usage); 470 471 SetDlgItemTextW(hwndDlg, IDC_USAGE_BOX, s.c_str()); 472 473 free(usage); 474 } 475 476 INT_PTR CALLBACK BtrfsVolPropSheet::UsageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 477 try { 478 switch (uMsg) { 479 case WM_INITDIALOG: 480 { 481 wstring s; 482 int i; 483 ULONG usagesize; 484 NTSTATUS Status; 485 IO_STATUS_BLOCK iosb; 486 487 EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); 488 489 win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 490 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 491 492 if (h != INVALID_HANDLE_VALUE) { 493 btrfs_usage* usage; 494 495 i = 0; 496 usagesize = 1024; 497 498 usage = (btrfs_usage*)malloc(usagesize); 499 500 while (true) { 501 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_USAGE, nullptr, 0, usage, usagesize); 502 if (Status == STATUS_BUFFER_OVERFLOW) { 503 if (i < 8) { 504 usagesize += 1024; 505 506 free(usage); 507 usage = (btrfs_usage*)malloc(usagesize); 508 509 i++; 510 } else 511 break; 512 } else 513 break; 514 } 515 516 if (!NT_SUCCESS(Status)) { 517 free(usage); 518 break; 519 } 520 521 FormatUsage(hwndDlg, s, usage); 522 523 SetDlgItemTextW(hwndDlg, IDC_USAGE_BOX, s.c_str()); 524 525 free(usage); 526 } 527 528 break; 529 } 530 531 case WM_COMMAND: 532 switch (HIWORD(wParam)) { 533 case BN_CLICKED: 534 switch (LOWORD(wParam)) { 535 case IDOK: 536 case IDCANCEL: 537 EndDialog(hwndDlg, 0); 538 return true; 539 540 case IDC_USAGE_REFRESH: 541 RefreshUsage(hwndDlg); 542 return true; 543 } 544 break; 545 } 546 break; 547 } 548 } catch (const exception& e) { 549 error_message(hwndDlg, e.what()); 550 } 551 552 return false; 553 } 554 555 static INT_PTR CALLBACK stub_UsageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 556 BtrfsVolPropSheet* bvps; 557 558 if (uMsg == WM_INITDIALOG) { 559 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); 560 bvps = (BtrfsVolPropSheet*)lParam; 561 } else { 562 bvps = (BtrfsVolPropSheet*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 563 } 564 565 if (bvps) 566 return bvps->UsageDlgProc(hwndDlg, uMsg, wParam, lParam); 567 else 568 return false; 569 } 570 571 void BtrfsVolPropSheet::ShowUsage(HWND hwndDlg) { 572 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_VOL_USAGE), hwndDlg, stub_UsageDlgProc, (LPARAM)this); 573 } 574 575 static void add_lv_column(HWND list, int string, int cx) { 576 LVCOLUMNW lvc; 577 wstring s; 578 579 if (!load_string(module, string, s)) 580 throw last_error(GetLastError()); 581 582 lvc.mask = LVCF_TEXT|LVCF_WIDTH; 583 lvc.pszText = (WCHAR*)s.c_str(); 584 lvc.cx = cx; 585 SendMessageW(list, LVM_INSERTCOLUMNW, 0, (LPARAM)&lvc); 586 } 587 588 static int CALLBACK lv_sort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { 589 if (lParam1 < lParam2) 590 return -1; 591 else if (lParam1 > lParam2) 592 return 1; 593 else 594 return 0; 595 } 596 597 static uint64_t find_dev_alloc(uint64_t dev_id, btrfs_usage* usage) { 598 btrfs_usage* bue; 599 uint64_t alloc; 600 601 alloc = 0; 602 603 bue = usage; 604 while (true) { 605 uint64_t k; 606 607 for (k = 0; k < bue->num_devices; k++) { 608 if (bue->devices[k].dev_id == dev_id) 609 alloc += bue->devices[k].alloc; 610 } 611 612 if (bue->next_entry > 0) 613 bue = (btrfs_usage*)((uint8_t*)bue + bue->next_entry); 614 else 615 break; 616 } 617 618 return alloc; 619 } 620 621 void BtrfsVolPropSheet::RefreshDevList(HWND devlist) { 622 NTSTATUS Status; 623 IO_STATUS_BLOCK iosb; 624 ULONG usagesize, devsize; 625 btrfs_usage* usage; 626 btrfs_device* bd; 627 int i; 628 uint64_t num_rw_devices; 629 { 630 win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 631 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 632 633 if (h == INVALID_HANDLE_VALUE) 634 throw last_error(GetLastError()); 635 636 i = 0; 637 devsize = 1024; 638 639 if (devices) 640 free(devices); 641 642 devices = (btrfs_device*)malloc(devsize); 643 644 while (true) { 645 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_DEVICES, nullptr, 0, devices, devsize); 646 if (Status == STATUS_BUFFER_OVERFLOW) { 647 if (i < 8) { 648 devsize += 1024; 649 650 free(devices); 651 devices = (btrfs_device*)malloc(devsize); 652 653 i++; 654 } else 655 return; 656 } else 657 break; 658 } 659 660 if (!NT_SUCCESS(Status)) 661 return; 662 663 bd = devices; 664 665 i = 0; 666 usagesize = 1024; 667 668 usage = (btrfs_usage*)malloc(usagesize); 669 670 while (true) { 671 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_USAGE, nullptr, 0, usage, usagesize); 672 if (Status == STATUS_BUFFER_OVERFLOW) { 673 if (i < 8) { 674 usagesize += 1024; 675 676 free(usage); 677 usage = (btrfs_usage*)malloc(usagesize); 678 679 i++; 680 } else { 681 free(usage); 682 return; 683 } 684 } else 685 break; 686 } 687 688 if (!NT_SUCCESS(Status)) { 689 free(usage); 690 return; 691 } 692 } 693 694 SendMessageW(devlist, LVM_DELETEALLITEMS, 0, 0); 695 696 num_rw_devices = 0; 697 698 i = 0; 699 while (true) { 700 LVITEMW lvi; 701 wstring s, u; 702 uint64_t alloc; 703 704 // ID 705 706 RtlZeroMemory(&lvi, sizeof(LVITEMW)); 707 lvi.mask = LVIF_TEXT | LVIF_PARAM; 708 lvi.iItem = SendMessageW(devlist, LVM_GETITEMCOUNT, 0, 0); 709 lvi.lParam = (LPARAM)bd->dev_id; 710 711 s = to_wstring(bd->dev_id); 712 lvi.pszText = (LPWSTR)s.c_str(); 713 714 SendMessageW(devlist, LVM_INSERTITEMW, 0, (LPARAM)&lvi); 715 716 // description 717 718 lvi.mask = LVIF_TEXT; 719 lvi.iSubItem = 1; 720 721 if (bd->missing) { 722 if (!load_string(module, IDS_MISSING, s)) 723 throw last_error(GetLastError()); 724 } else if (bd->device_number == 0xffffffff) 725 s = wstring(bd->name, bd->namelen / sizeof(WCHAR)); 726 else if (bd->partition_number == 0) { 727 if (!load_string(module, IDS_DISK_NUM, u)) 728 throw last_error(GetLastError()); 729 730 wstring_sprintf(s, u, bd->device_number); 731 } else { 732 if (!load_string(module, IDS_DISK_PART_NUM, u)) 733 throw last_error(GetLastError()); 734 735 wstring_sprintf(s, u, bd->device_number, bd->partition_number); 736 } 737 738 lvi.pszText = (LPWSTR)s.c_str(); 739 740 SendMessageW(devlist, LVM_SETITEMW, 0, (LPARAM)&lvi); 741 742 // readonly 743 744 lvi.iSubItem = 2; 745 load_string(module, bd->readonly ? IDS_DEVLIST_READONLY_YES : IDS_DEVLIST_READONLY_NO, s); 746 lvi.pszText = (LPWSTR)s.c_str(); 747 SendMessageW(devlist, LVM_SETITEMW, 0, (LPARAM)&lvi); 748 749 if (!bd->readonly) 750 num_rw_devices++; 751 752 // size 753 754 lvi.iSubItem = 3; 755 format_size(bd->size, s, false); 756 lvi.pszText = (LPWSTR)s.c_str(); 757 SendMessageW(devlist, LVM_SETITEMW, 0, (LPARAM)&lvi); 758 759 // alloc 760 761 alloc = find_dev_alloc(bd->dev_id, usage); 762 763 lvi.iSubItem = 4; 764 format_size(alloc, s, false); 765 lvi.pszText = (LPWSTR)s.c_str(); 766 SendMessageW(devlist, LVM_SETITEMW, 0, (LPARAM)&lvi); 767 768 // alloc % 769 770 wstring_sprintf(s, L"%1.1f%%", (float)alloc * 100.0f / (float)bd->size); 771 lvi.iSubItem = 5; 772 lvi.pszText = (LPWSTR)s.c_str(); 773 SendMessageW(devlist, LVM_SETITEMW, 0, (LPARAM)&lvi); 774 775 i++; 776 777 if (bd->next_entry > 0) 778 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 779 else 780 break; 781 } 782 783 free(usage); 784 785 SendMessageW(devlist, LVM_SORTITEMS, 0, (LPARAM)lv_sort); 786 787 EnableWindow(GetDlgItem(GetParent(devlist), IDC_DEVICE_ADD), num_rw_devices > 0); 788 EnableWindow(GetDlgItem(GetParent(devlist), IDC_DEVICE_REMOVE), num_rw_devices > 1); 789 } 790 791 void BtrfsVolPropSheet::ResetStats(HWND hwndDlg) { 792 wstring t, sel; 793 WCHAR modfn[MAX_PATH]; 794 SHELLEXECUTEINFOW sei; 795 796 sel = to_wstring(stats_dev); 797 798 GetModuleFileNameW(module, modfn, sizeof(modfn) / sizeof(WCHAR)); 799 800 #ifndef __REACTOS__ 801 t = L"\""s + modfn + L"\",ResetStats " + fn + L"|" + sel; 802 #else 803 t = wstring(L"\"") + modfn + wstring(L"\",ResetStats ") + fn + wstring(L"|") + sel; 804 #endif 805 806 RtlZeroMemory(&sei, sizeof(sei)); 807 808 sei.cbSize = sizeof(sei); 809 sei.hwnd = hwndDlg; 810 sei.lpVerb = L"runas"; 811 sei.lpFile = L"rundll32.exe"; 812 sei.lpParameters = t.c_str(); 813 sei.nShow = SW_SHOW; 814 sei.fMask = SEE_MASK_NOCLOSEPROCESS; 815 816 if (!ShellExecuteExW(&sei)) 817 throw last_error(GetLastError()); 818 819 WaitForSingleObject(sei.hProcess, INFINITE); 820 CloseHandle(sei.hProcess); 821 822 win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 823 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 824 825 if (h != INVALID_HANDLE_VALUE) { 826 NTSTATUS Status; 827 IO_STATUS_BLOCK iosb; 828 ULONG devsize, i; 829 830 i = 0; 831 devsize = 1024; 832 833 free(devices); 834 devices = (btrfs_device*)malloc(devsize); 835 836 while (true) { 837 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_DEVICES, nullptr, 0, devices, devsize); 838 if (Status == STATUS_BUFFER_OVERFLOW) { 839 if (i < 8) { 840 devsize += 1024; 841 842 free(devices); 843 devices = (btrfs_device*)malloc(devsize); 844 845 i++; 846 } else 847 break; 848 } else 849 break; 850 } 851 } 852 853 EndDialog(hwndDlg, 0); 854 } 855 856 INT_PTR CALLBACK BtrfsVolPropSheet::StatsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 857 try { 858 switch (uMsg) { 859 case WM_INITDIALOG: 860 { 861 WCHAR s[255]; 862 wstring t; 863 btrfs_device *bd, *dev = nullptr; 864 int i; 865 866 static int stat_ids[] = { IDC_WRITE_ERRS, IDC_READ_ERRS, IDC_FLUSH_ERRS, IDC_CORRUPTION_ERRS, IDC_GENERATION_ERRS }; 867 868 bd = devices; 869 870 while (true) { 871 if (bd->dev_id == stats_dev) { 872 dev = bd; 873 break; 874 } 875 876 if (bd->next_entry > 0) 877 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 878 else 879 break; 880 } 881 882 if (!dev) { 883 EndDialog(hwndDlg, 0); 884 throw string_error(IDS_CANNOT_FIND_DEVICE); 885 } 886 887 GetDlgItemTextW(hwndDlg, IDC_DEVICE_ID, s, sizeof(s) / sizeof(WCHAR)); 888 889 wstring_sprintf(t, s, dev->dev_id); 890 891 SetDlgItemTextW(hwndDlg, IDC_DEVICE_ID, t.c_str()); 892 893 for (i = 0; i < 5; i++) { 894 GetDlgItemTextW(hwndDlg, stat_ids[i], s, sizeof(s) / sizeof(WCHAR)); 895 896 wstring_sprintf(t, s, dev->stats[i]); 897 898 SetDlgItemTextW(hwndDlg, stat_ids[i], t.c_str()); 899 } 900 901 SendMessageW(GetDlgItem(hwndDlg, IDC_RESET_STATS), BCM_SETSHIELD, 0, true); 902 EnableWindow(GetDlgItem(hwndDlg, IDC_RESET_STATS), !readonly); 903 904 break; 905 } 906 907 case WM_COMMAND: 908 switch (HIWORD(wParam)) { 909 case BN_CLICKED: 910 switch (LOWORD(wParam)) { 911 case IDOK: 912 case IDCANCEL: 913 EndDialog(hwndDlg, 0); 914 return true; 915 916 case IDC_RESET_STATS: 917 ResetStats(hwndDlg); 918 return true; 919 } 920 break; 921 } 922 break; 923 } 924 } catch (const exception& e) { 925 error_message(hwndDlg, e.what()); 926 } 927 928 return false; 929 } 930 931 static INT_PTR CALLBACK stub_StatsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 932 BtrfsVolPropSheet* bvps; 933 934 if (uMsg == WM_INITDIALOG) { 935 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); 936 bvps = (BtrfsVolPropSheet*)lParam; 937 } else { 938 bvps = (BtrfsVolPropSheet*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 939 } 940 941 if (bvps) 942 return bvps->StatsDlgProc(hwndDlg, uMsg, wParam, lParam); 943 else 944 return false; 945 } 946 947 void BtrfsVolPropSheet::ShowStats(HWND hwndDlg, uint64_t devid) { 948 stats_dev = devid; 949 950 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_DEVICE_STATS), hwndDlg, stub_StatsDlgProc, (LPARAM)this); 951 } 952 953 INT_PTR CALLBACK BtrfsVolPropSheet::DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 954 try { 955 switch (uMsg) { 956 case WM_INITDIALOG: 957 { 958 HWND devlist; 959 RECT rect; 960 ULONG w; 961 962 EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); 963 964 devlist = GetDlgItem(hwndDlg, IDC_DEVLIST); 965 966 GetClientRect(devlist, &rect); 967 w = rect.right - rect.left; 968 969 add_lv_column(devlist, IDS_DEVLIST_ALLOC_PC, w * 5 / 44); 970 add_lv_column(devlist, IDS_DEVLIST_ALLOC, w * 6 / 44); 971 add_lv_column(devlist, IDS_DEVLIST_SIZE, w * 6 / 44); 972 add_lv_column(devlist, IDS_DEVLIST_READONLY, w * 7 / 44); 973 add_lv_column(devlist, IDS_DEVLIST_DESC, w * 16 / 44); 974 add_lv_column(devlist, IDS_DEVLIST_ID, w * 4 / 44); 975 976 SendMessageW(GetDlgItem(hwndDlg, IDC_DEVICE_ADD), BCM_SETSHIELD, 0, true); 977 SendMessageW(GetDlgItem(hwndDlg, IDC_DEVICE_REMOVE), BCM_SETSHIELD, 0, true); 978 SendMessageW(GetDlgItem(hwndDlg, IDC_DEVICE_RESIZE), BCM_SETSHIELD, 0, true); 979 980 RefreshDevList(devlist); 981 982 break; 983 } 984 985 case WM_COMMAND: 986 switch (HIWORD(wParam)) { 987 case BN_CLICKED: 988 switch (LOWORD(wParam)) { 989 case IDOK: 990 case IDCANCEL: 991 KillTimer(hwndDlg, 1); 992 EndDialog(hwndDlg, 0); 993 return true; 994 995 case IDC_DEVICE_ADD: 996 { 997 wstring t; 998 WCHAR modfn[MAX_PATH]; 999 SHELLEXECUTEINFOW sei; 1000 1001 GetModuleFileNameW(module, modfn, sizeof(modfn) / sizeof(WCHAR)); 1002 1003 #ifndef __REACTOS__ 1004 t = L"\""s + modfn + L"\",AddDevice "s + fn; 1005 #else 1006 t = wstring(L"\"") + modfn + wstring(L"\",AddDevice ") + fn; 1007 #endif 1008 1009 RtlZeroMemory(&sei, sizeof(sei)); 1010 1011 sei.cbSize = sizeof(sei); 1012 sei.hwnd = hwndDlg; 1013 sei.lpVerb = L"runas"; 1014 sei.lpFile = L"rundll32.exe"; 1015 sei.lpParameters = t.c_str(); 1016 sei.nShow = SW_SHOW; 1017 sei.fMask = SEE_MASK_NOCLOSEPROCESS; 1018 1019 if (!ShellExecuteExW(&sei)) 1020 throw last_error(GetLastError()); 1021 1022 WaitForSingleObject(sei.hProcess, INFINITE); 1023 CloseHandle(sei.hProcess); 1024 1025 RefreshDevList(GetDlgItem(hwndDlg, IDC_DEVLIST)); 1026 1027 return true; 1028 } 1029 1030 case IDC_DEVICE_REFRESH: 1031 RefreshDevList(GetDlgItem(hwndDlg, IDC_DEVLIST)); 1032 return true; 1033 1034 case IDC_DEVICE_SHOW_STATS: 1035 { 1036 WCHAR sel[MAX_PATH]; 1037 HWND devlist; 1038 int index; 1039 LVITEMW lvi; 1040 1041 devlist = GetDlgItem(hwndDlg, IDC_DEVLIST); 1042 1043 index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED); 1044 1045 if (index == -1) 1046 return true; 1047 1048 RtlZeroMemory(&lvi, sizeof(LVITEMW)); 1049 lvi.mask = LVIF_TEXT; 1050 lvi.iItem = index; 1051 lvi.iSubItem = 0; 1052 lvi.pszText = sel; 1053 lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR); 1054 SendMessageW(devlist, LVM_GETITEMW, 0, (LPARAM)&lvi); 1055 1056 ShowStats(hwndDlg, _wtoi(sel)); 1057 return true; 1058 } 1059 1060 case IDC_DEVICE_REMOVE: 1061 { 1062 wstring t, mess, mess2, title; 1063 WCHAR modfn[MAX_PATH], sel[MAX_PATH], sel2[MAX_PATH]; 1064 HWND devlist; 1065 SHELLEXECUTEINFOW sei; 1066 int index; 1067 LVITEMW lvi; 1068 1069 devlist = GetDlgItem(hwndDlg, IDC_DEVLIST); 1070 1071 index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED); 1072 1073 if (index == -1) 1074 return true; 1075 1076 RtlZeroMemory(&lvi, sizeof(LVITEMW)); 1077 lvi.mask = LVIF_TEXT; 1078 lvi.iItem = index; 1079 lvi.iSubItem = 0; 1080 lvi.pszText = sel; 1081 lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR); 1082 SendMessageW(devlist, LVM_GETITEMW, 0, (LPARAM)&lvi); 1083 1084 lvi.iSubItem = 1; 1085 lvi.pszText = sel2; 1086 lvi.cchTextMax = sizeof(sel2) / sizeof(WCHAR); 1087 SendMessageW(devlist, LVM_GETITEMW, 0, (LPARAM)&lvi); 1088 1089 if (!load_string(module, IDS_REMOVE_DEVICE_CONFIRMATION, mess)) 1090 throw last_error(GetLastError()); 1091 1092 wstring_sprintf(mess2, mess, sel, sel2); 1093 1094 if (!load_string(module, IDS_CONFIRMATION_TITLE, title)) 1095 throw last_error(GetLastError()); 1096 1097 if (MessageBoxW(hwndDlg, mess2.c_str(), title.c_str(), MB_YESNO) != IDYES) 1098 return true; 1099 1100 GetModuleFileNameW(module, modfn, sizeof(modfn) / sizeof(WCHAR)); 1101 1102 #ifndef __REACTOS__ 1103 t = L"\""s + modfn + L"\",RemoveDevice "s + fn + L"|"s + sel; 1104 #else 1105 t = wstring(L"\"") + modfn + wstring(L"\",RemoveDevice ") + fn + wstring(L"|") + sel; 1106 #endif 1107 1108 RtlZeroMemory(&sei, sizeof(sei)); 1109 1110 sei.cbSize = sizeof(sei); 1111 sei.hwnd = hwndDlg; 1112 sei.lpVerb = L"runas"; 1113 sei.lpFile = L"rundll32.exe"; 1114 sei.lpParameters = t.c_str(); 1115 sei.nShow = SW_SHOW; 1116 sei.fMask = SEE_MASK_NOCLOSEPROCESS; 1117 1118 if (!ShellExecuteExW(&sei)) 1119 throw last_error(GetLastError()); 1120 1121 WaitForSingleObject(sei.hProcess, INFINITE); 1122 CloseHandle(sei.hProcess); 1123 1124 RefreshDevList(GetDlgItem(hwndDlg, IDC_DEVLIST)); 1125 1126 return true; 1127 } 1128 1129 case IDC_DEVICE_RESIZE: 1130 { 1131 HWND devlist; 1132 int index; 1133 LVITEMW lvi; 1134 wstring t; 1135 WCHAR modfn[MAX_PATH], sel[100]; 1136 SHELLEXECUTEINFOW sei; 1137 1138 devlist = GetDlgItem(hwndDlg, IDC_DEVLIST); 1139 1140 index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED); 1141 1142 if (index == -1) 1143 return true; 1144 1145 RtlZeroMemory(&lvi, sizeof(LVITEMW)); 1146 lvi.mask = LVIF_TEXT; 1147 lvi.iItem = index; 1148 lvi.iSubItem = 0; 1149 lvi.pszText = sel; 1150 lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR); 1151 SendMessageW(devlist, LVM_GETITEMW, 0, (LPARAM)&lvi); 1152 1153 GetModuleFileNameW(module, modfn, sizeof(modfn) / sizeof(WCHAR)); 1154 1155 #ifndef __REACTOS__ 1156 t = L"\""s + modfn + L"\",ResizeDevice "s + fn + L"|"s + sel; 1157 #else 1158 t = wstring(L"\"") + modfn + wstring(L"\",ResizeDevice ") + fn + wstring(L"|") + sel; 1159 #endif 1160 1161 RtlZeroMemory(&sei, sizeof(sei)); 1162 1163 sei.cbSize = sizeof(sei); 1164 sei.hwnd = hwndDlg; 1165 sei.lpVerb = L"runas"; 1166 sei.lpFile = L"rundll32.exe"; 1167 sei.lpParameters = t.c_str(); 1168 sei.nShow = SW_SHOW; 1169 sei.fMask = SEE_MASK_NOCLOSEPROCESS; 1170 1171 if (!ShellExecuteExW(&sei)) 1172 throw last_error(GetLastError()); 1173 1174 WaitForSingleObject(sei.hProcess, INFINITE); 1175 CloseHandle(sei.hProcess); 1176 1177 RefreshDevList(GetDlgItem(hwndDlg, IDC_DEVLIST)); 1178 } 1179 } 1180 break; 1181 } 1182 break; 1183 1184 case WM_NOTIFY: 1185 switch (((LPNMHDR)lParam)->code) { 1186 case LVN_ITEMCHANGED: 1187 { 1188 NMLISTVIEW* nmv = (NMLISTVIEW*)lParam; 1189 1190 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_SHOW_STATS), nmv->uNewState & LVIS_SELECTED); 1191 1192 if (nmv->uNewState & LVIS_SELECTED && !readonly) { 1193 HWND devlist; 1194 btrfs_device* bd; 1195 bool device_readonly = false; 1196 LVITEMW lvi; 1197 WCHAR sel[MAX_PATH]; 1198 uint64_t devid; 1199 1200 devlist = GetDlgItem(hwndDlg, IDC_DEVLIST); 1201 1202 RtlZeroMemory(&lvi, sizeof(LVITEMW)); 1203 lvi.mask = LVIF_TEXT; 1204 lvi.iItem = nmv->iItem; 1205 lvi.iSubItem = 0; 1206 lvi.pszText = sel; 1207 lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR); 1208 SendMessageW(devlist, LVM_GETITEMW, 0, (LPARAM)&lvi); 1209 devid = _wtoi(sel); 1210 1211 bd = devices; 1212 1213 while (true) { 1214 if (bd->dev_id == devid) { 1215 device_readonly = bd->readonly; 1216 break; 1217 } 1218 1219 if (bd->next_entry > 0) 1220 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 1221 else 1222 break; 1223 } 1224 1225 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_RESIZE), !device_readonly); 1226 } else 1227 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_RESIZE), false); 1228 1229 break; 1230 } 1231 } 1232 break; 1233 } 1234 } catch (const exception& e) { 1235 error_message(hwndDlg, e.what()); 1236 } 1237 1238 return false; 1239 } 1240 1241 static INT_PTR CALLBACK stub_DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 1242 BtrfsVolPropSheet* bvps; 1243 1244 if (uMsg == WM_INITDIALOG) { 1245 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); 1246 bvps = (BtrfsVolPropSheet*)lParam; 1247 } else { 1248 bvps = (BtrfsVolPropSheet*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 1249 } 1250 1251 if (bvps) 1252 return bvps->DeviceDlgProc(hwndDlg, uMsg, wParam, lParam); 1253 else 1254 return false; 1255 } 1256 1257 void BtrfsVolPropSheet::ShowDevices(HWND hwndDlg) { 1258 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_DEVICES), hwndDlg, stub_DeviceDlgProc, (LPARAM)this); 1259 } 1260 1261 void BtrfsVolPropSheet::ShowScrub(HWND hwndDlg) { 1262 wstring t; 1263 WCHAR modfn[MAX_PATH]; 1264 SHELLEXECUTEINFOW sei; 1265 1266 GetModuleFileNameW(module, modfn, sizeof(modfn) / sizeof(WCHAR)); 1267 1268 #ifndef __REACTOS__ 1269 t = L"\""s + modfn + L"\",ShowScrub "s + fn; 1270 #else 1271 t = wstring(L"\"") + modfn + wstring(L"\",ShowScrub ") + fn; 1272 #endif 1273 1274 RtlZeroMemory(&sei, sizeof(sei)); 1275 1276 sei.cbSize = sizeof(sei); 1277 sei.hwnd = hwndDlg; 1278 sei.lpVerb = L"runas"; 1279 sei.lpFile = L"rundll32.exe"; 1280 sei.lpParameters = t.c_str(); 1281 sei.nShow = SW_SHOW; 1282 sei.fMask = SEE_MASK_NOCLOSEPROCESS; 1283 1284 if (!ShellExecuteExW(&sei)) 1285 throw last_error(GetLastError()); 1286 1287 WaitForSingleObject(sei.hProcess, INFINITE); 1288 CloseHandle(sei.hProcess); 1289 } 1290 1291 static INT_PTR CALLBACK PropSheetDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 1292 try { 1293 switch (uMsg) { 1294 case WM_INITDIALOG: 1295 { 1296 PROPSHEETPAGE* psp = (PROPSHEETPAGE*)lParam; 1297 BtrfsVolPropSheet* bps = (BtrfsVolPropSheet*)psp->lParam; 1298 btrfs_device* bd; 1299 1300 EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); 1301 1302 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)bps); 1303 1304 bps->readonly = true; 1305 bd = bps->devices; 1306 1307 while (true) { 1308 if (!bd->readonly) { 1309 bps->readonly = false; 1310 break; 1311 } 1312 1313 if (bd->next_entry > 0) 1314 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 1315 else 1316 break; 1317 } 1318 1319 if (bps->uuid_set) { 1320 WCHAR s[255]; 1321 wstring t; 1322 1323 GetDlgItemTextW(hwndDlg, IDC_UUID, s, sizeof(s) / sizeof(WCHAR)); 1324 1325 wstring_sprintf(t, s, bps->uuid.uuid[0], bps->uuid.uuid[1], bps->uuid.uuid[2], bps->uuid.uuid[3], bps->uuid.uuid[4], bps->uuid.uuid[5], 1326 bps->uuid.uuid[6], bps->uuid.uuid[7], bps->uuid.uuid[8], bps->uuid.uuid[9], bps->uuid.uuid[10], bps->uuid.uuid[11], 1327 bps->uuid.uuid[12], bps->uuid.uuid[13], bps->uuid.uuid[14], bps->uuid.uuid[15]); 1328 1329 SetDlgItemTextW(hwndDlg, IDC_UUID, t.c_str()); 1330 } else 1331 SetDlgItemTextW(hwndDlg, IDC_UUID, L""); 1332 1333 SendMessageW(GetDlgItem(hwndDlg, IDC_VOL_SCRUB), BCM_SETSHIELD, 0, true); 1334 1335 return false; 1336 } 1337 1338 case WM_NOTIFY: 1339 { 1340 switch (((LPNMHDR)lParam)->code) { 1341 case PSN_KILLACTIVE: 1342 SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, false); 1343 break; 1344 } 1345 break; 1346 } 1347 1348 case WM_COMMAND: 1349 { 1350 BtrfsVolPropSheet* bps = (BtrfsVolPropSheet*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 1351 1352 if (bps) { 1353 switch (HIWORD(wParam)) { 1354 case BN_CLICKED: { 1355 switch (LOWORD(wParam)) { 1356 case IDC_VOL_SHOW_USAGE: 1357 bps->ShowUsage(hwndDlg); 1358 break; 1359 1360 case IDC_VOL_BALANCE: 1361 bps->balance->ShowBalance(hwndDlg); 1362 break; 1363 1364 case IDC_VOL_DEVICES: 1365 bps->ShowDevices(hwndDlg); 1366 break; 1367 1368 case IDC_VOL_SCRUB: 1369 bps->ShowScrub(hwndDlg); 1370 break; 1371 } 1372 } 1373 } 1374 } 1375 1376 break; 1377 } 1378 } 1379 } catch (const exception& e) { 1380 error_message(hwndDlg, e.what()); 1381 } 1382 1383 return false; 1384 } 1385 1386 HRESULT __stdcall BtrfsVolPropSheet::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) { 1387 try { 1388 PROPSHEETPAGE psp; 1389 HPROPSHEETPAGE hPage; 1390 INITCOMMONCONTROLSEX icex; 1391 1392 if (ignore) 1393 return S_OK; 1394 1395 icex.dwSize = sizeof(icex); 1396 icex.dwICC = ICC_LINK_CLASS; 1397 1398 if (!InitCommonControlsEx(&icex)) 1399 throw string_error(IDS_INITCOMMONCONTROLSEX_FAILED); 1400 1401 psp.dwSize = sizeof(psp); 1402 psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE; 1403 psp.hInstance = module; 1404 psp.pszTemplate = MAKEINTRESOURCE(IDD_VOL_PROP_SHEET); 1405 psp.hIcon = 0; 1406 psp.pszTitle = MAKEINTRESOURCE(IDS_VOL_PROP_SHEET_TITLE); 1407 psp.pfnDlgProc = (DLGPROC)PropSheetDlgProc; 1408 psp.pcRefParent = (UINT*)&objs_loaded; 1409 psp.pfnCallback = nullptr; 1410 psp.lParam = (LPARAM)this; 1411 1412 hPage = CreatePropertySheetPage(&psp); 1413 1414 if (hPage) { 1415 if (pfnAddPage(hPage, lParam)) { 1416 this->AddRef(); 1417 return S_OK; 1418 } else 1419 DestroyPropertySheetPage(hPage); 1420 } else 1421 return E_OUTOFMEMORY; 1422 } catch (const exception& e) { 1423 error_message(nullptr, e.what()); 1424 } 1425 1426 return E_FAIL; 1427 } 1428 1429 HRESULT __stdcall BtrfsVolPropSheet::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam) { 1430 return S_OK; 1431 } 1432 1433 #ifdef __cplusplus 1434 extern "C" { 1435 #endif 1436 1437 void CALLBACK ResetStatsW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 1438 try { 1439 win_handle token; 1440 NTSTATUS Status; 1441 TOKEN_PRIVILEGES tp; 1442 LUID luid; 1443 uint64_t devid; 1444 wstring cmdline, vol, dev; 1445 size_t pipe; 1446 IO_STATUS_BLOCK iosb; 1447 1448 set_dpi_aware(); 1449 1450 cmdline = lpszCmdLine; 1451 1452 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1453 throw last_error(GetLastError()); 1454 1455 if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) 1456 throw last_error(GetLastError()); 1457 1458 tp.PrivilegeCount = 1; 1459 tp.Privileges[0].Luid = luid; 1460 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1461 1462 if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) 1463 throw last_error(GetLastError()); 1464 1465 pipe = cmdline.find(L"|"); 1466 1467 if (pipe == string::npos) 1468 return; 1469 1470 vol = cmdline.substr(0, pipe); 1471 dev = cmdline.substr(pipe + 1); 1472 1473 devid = _wtoi(dev.c_str()); 1474 if (devid == 0) 1475 return; 1476 1477 win_handle h = CreateFileW(vol.c_str(), FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 1478 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 1479 1480 if (h == INVALID_HANDLE_VALUE) 1481 throw last_error(GetLastError()); 1482 1483 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESET_STATS, &devid, sizeof(uint64_t), nullptr, 0); 1484 if (!NT_SUCCESS(Status)) 1485 throw ntstatus_error(Status); 1486 } catch (const exception& e) { 1487 error_message(hwnd, e.what()); 1488 } 1489 } 1490 1491 #ifdef __cplusplus 1492 } 1493 #endif 1494