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