1 /* Copyright (c) Mark Harmstone 2017 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 #include "shellext.h" 19 #include "scrub.h" 20 #include "resource.h" 21 #ifndef __REACTOS__ 22 #include "../btrfsioctl.h" 23 #else 24 #include "btrfsioctl.h" 25 #endif 26 #include <shlobj.h> 27 #include <uxtheme.h> 28 #include <stdio.h> 29 #ifndef __REACTOS__ 30 #include <strsafe.h> 31 #include <winternl.h> 32 #else 33 #define WIN32_NO_STATUS 34 #include <windef.h> 35 #include <winbase.h> 36 #include <strsafe.h> 37 #include <ndk/iofuncs.h> 38 #include <ndk/iotypes.h> 39 #endif 40 #include <string> 41 42 #define NO_SHLWAPI_STRFCNS 43 #include <shlwapi.h> 44 #include <uxtheme.h> 45 46 void BtrfsScrub::UpdateTextBox(HWND hwndDlg, btrfs_query_scrub* bqs) { 47 btrfs_query_scrub* bqs2 = NULL; 48 BOOL alloc_bqs2 = FALSE; 49 NTSTATUS Status; 50 std::wstring s; 51 WCHAR t[255], u[255], dt[255], tm[255]; 52 FILETIME filetime; 53 SYSTEMTIME systime; 54 UINT64 recoverable_errors = 0, unrecoverable_errors = 0; 55 56 if (bqs->num_errors > 0) { 57 HANDLE h; 58 IO_STATUS_BLOCK iosb; 59 ULONG len; 60 61 h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 62 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); 63 if (h == INVALID_HANDLE_VALUE) { 64 ShowError(hwndDlg, GetLastError()); 65 return; 66 } 67 68 len = 0; 69 70 do { 71 len += 1024; 72 73 if (bqs2) 74 free(bqs2); 75 76 bqs2 = (btrfs_query_scrub*)malloc(len); 77 78 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_QUERY_SCRUB, NULL, 0, bqs2, len); 79 80 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { 81 ShowNtStatusError(hwndDlg, Status); 82 CloseHandle(h); 83 free(bqs2); 84 return; 85 } 86 } while (Status == STATUS_BUFFER_OVERFLOW); 87 88 alloc_bqs2 = TRUE; 89 90 CloseHandle(h); 91 } else 92 bqs2 = bqs; 93 94 s[0] = 0; 95 96 // "scrub started" 97 if (bqs2->start_time.QuadPart > 0) { 98 filetime.dwLowDateTime = bqs2->start_time.LowPart; 99 filetime.dwHighDateTime = bqs2->start_time.HighPart; 100 101 if (!FileTimeToSystemTime(&filetime, &systime)) { 102 ShowError(hwndDlg, GetLastError()); 103 goto end; 104 } 105 106 if (!SystemTimeToTzSpecificLocalTime(NULL, &systime, &systime)) { 107 ShowError(hwndDlg, GetLastError()); 108 goto end; 109 } 110 111 if (!LoadStringW(module, IDS_SCRUB_MSG_STARTED, t, sizeof(t) / sizeof(WCHAR))) { 112 ShowError(hwndDlg, GetLastError()); 113 goto end; 114 } 115 116 if (!GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, NULL, dt, sizeof(dt) / sizeof(WCHAR))) { 117 ShowError(hwndDlg, GetLastError()); 118 goto end; 119 } 120 121 if (!GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systime, NULL, tm, sizeof(tm) / sizeof(WCHAR))) { 122 ShowError(hwndDlg, GetLastError()); 123 goto end; 124 } 125 126 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, dt, tm) == STRSAFE_E_INSUFFICIENT_BUFFER) 127 goto end; 128 129 s += u; 130 s += L"\r\n"; 131 } 132 133 // errors 134 if (bqs2->num_errors > 0) { 135 btrfs_scrub_error* bse = &bqs2->errors; 136 137 do { 138 if (bse->recovered) 139 recoverable_errors++; 140 else 141 unrecoverable_errors++; 142 143 if (bse->parity) { 144 if (!LoadStringW(module, IDS_SCRUB_MSG_RECOVERABLE_PARITY, t, sizeof(t) / sizeof(WCHAR))) { 145 ShowError(hwndDlg, GetLastError()); 146 goto end; 147 } 148 149 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device) == STRSAFE_E_INSUFFICIENT_BUFFER) 150 goto end; 151 } else if (bse->is_metadata) { 152 int message; 153 154 if (bse->recovered) 155 message = IDS_SCRUB_MSG_RECOVERABLE_METADATA; 156 else if (bse->metadata.firstitem.obj_id == 0 && bse->metadata.firstitem.obj_type == 0 && bse->metadata.firstitem.offset == 0) 157 message = IDS_SCRUB_MSG_UNRECOVERABLE_METADATA; 158 else 159 message = IDS_SCRUB_MSG_UNRECOVERABLE_METADATA_FIRSTITEM; 160 161 if (!LoadStringW(module, message, t, sizeof(t) / sizeof(WCHAR))) { 162 ShowError(hwndDlg, GetLastError()); 163 goto end; 164 } 165 166 if (bse->recovered) { 167 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device) == STRSAFE_E_INSUFFICIENT_BUFFER) 168 goto end; 169 } else if (bse->metadata.firstitem.obj_id == 0 && bse->metadata.firstitem.obj_type == 0 && bse->metadata.firstitem.offset == 0) { 170 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device, 171 bse->metadata.root, bse->metadata.level) == STRSAFE_E_INSUFFICIENT_BUFFER) 172 goto end; 173 } else { 174 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device, 175 bse->metadata.root, bse->metadata.level, bse->metadata.firstitem.obj_id, bse->metadata.firstitem.obj_type, 176 bse->metadata.firstitem.offset) == STRSAFE_E_INSUFFICIENT_BUFFER) 177 goto end; 178 } 179 } else { 180 int message; 181 182 if (bse->recovered) 183 message = IDS_SCRUB_MSG_RECOVERABLE_DATA; 184 else if (bse->data.subvol != 0) 185 message = IDS_SCRUB_MSG_UNRECOVERABLE_DATA_SUBVOL; 186 else 187 message = IDS_SCRUB_MSG_UNRECOVERABLE_DATA; 188 189 if (!LoadStringW(module, message, t, sizeof(t) / sizeof(WCHAR))) { 190 ShowError(hwndDlg, GetLastError()); 191 goto end; 192 } 193 194 if (bse->recovered) { 195 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device) == STRSAFE_E_INSUFFICIENT_BUFFER) 196 goto end; 197 } else if (bse->data.subvol != 0) { 198 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device, bse->data.subvol, 199 bse->data.filename_length / sizeof(WCHAR), bse->data.filename, bse->data.offset) == STRSAFE_E_INSUFFICIENT_BUFFER) 200 goto end; 201 } else { 202 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device, bse->data.filename_length / sizeof(WCHAR), 203 bse->data.filename, bse->data.offset) == STRSAFE_E_INSUFFICIENT_BUFFER) 204 goto end; 205 } 206 } 207 208 s += u; 209 s += L"\r\n"; 210 211 if (bse->next_entry == 0) 212 break; 213 else 214 bse = (btrfs_scrub_error*)((UINT8*)bse + bse->next_entry); 215 } while (TRUE); 216 } 217 218 if (bqs2->finish_time.QuadPart > 0) { 219 WCHAR d1[255], d2[255]; 220 float speed; 221 222 // "scrub finished" 223 224 filetime.dwLowDateTime = bqs2->finish_time.LowPart; 225 filetime.dwHighDateTime = bqs2->finish_time.HighPart; 226 227 if (!FileTimeToSystemTime(&filetime, &systime)) { 228 ShowError(hwndDlg, GetLastError()); 229 goto end; 230 } 231 232 if (!SystemTimeToTzSpecificLocalTime(NULL, &systime, &systime)) { 233 ShowError(hwndDlg, GetLastError()); 234 goto end; 235 } 236 237 if (!LoadStringW(module, IDS_SCRUB_MSG_FINISHED, t, sizeof(t) / sizeof(WCHAR))) { 238 ShowError(hwndDlg, GetLastError()); 239 goto end; 240 } 241 242 if (!GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, NULL, dt, sizeof(dt) / sizeof(WCHAR))) { 243 ShowError(hwndDlg, GetLastError()); 244 goto end; 245 } 246 247 if (!GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systime, NULL, tm, sizeof(tm) / sizeof(WCHAR))) { 248 ShowError(hwndDlg, GetLastError()); 249 goto end; 250 } 251 252 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, dt, tm) == STRSAFE_E_INSUFFICIENT_BUFFER) 253 goto end; 254 255 s += u; 256 s += L"\r\n"; 257 258 // summary 259 260 if (!LoadStringW(module, IDS_SCRUB_MSG_SUMMARY, t, sizeof(t) / sizeof(WCHAR))) { 261 ShowError(hwndDlg, GetLastError()); 262 goto end; 263 } 264 265 format_size(bqs2->data_scrubbed, d1, sizeof(d1) / sizeof(WCHAR), FALSE); 266 267 speed = (float)bqs2->data_scrubbed / ((float)bqs2->duration / 10000000.0f); 268 269 format_size((UINT64)speed, d2, sizeof(d2) / sizeof(WCHAR), FALSE); 270 271 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, d1, bqs2->duration / 10000000, d2) == STRSAFE_E_INSUFFICIENT_BUFFER) 272 goto end; 273 274 s += u; 275 s += L"\r\n"; 276 277 // recoverable errors 278 279 if (!LoadStringW(module, IDS_SCRUB_MSG_SUMMARY_ERRORS_RECOVERABLE, t, sizeof(t) / sizeof(WCHAR))) { 280 ShowError(hwndDlg, GetLastError()); 281 goto end; 282 } 283 284 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, recoverable_errors) == STRSAFE_E_INSUFFICIENT_BUFFER) 285 goto end; 286 287 s += u; 288 s += L"\r\n"; 289 290 // unrecoverable errors 291 292 if (!LoadStringW(module, IDS_SCRUB_MSG_SUMMARY_ERRORS_UNRECOVERABLE, t, sizeof(t) / sizeof(WCHAR))) { 293 ShowError(hwndDlg, GetLastError()); 294 goto end; 295 } 296 297 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, unrecoverable_errors) == STRSAFE_E_INSUFFICIENT_BUFFER) 298 goto end; 299 300 s += u; 301 s += L"\r\n"; 302 } 303 304 SetWindowTextW(GetDlgItem(hwndDlg, IDC_SCRUB_INFO), s.c_str()); 305 306 end: 307 if (alloc_bqs2) 308 free(bqs2); 309 } 310 311 void BtrfsScrub::RefreshScrubDlg(HWND hwndDlg, BOOL first_time) { 312 HANDLE h; 313 btrfs_query_scrub bqs; 314 315 h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 316 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); 317 if (h != INVALID_HANDLE_VALUE) { 318 NTSTATUS Status; 319 IO_STATUS_BLOCK iosb; 320 321 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_QUERY_SCRUB, NULL, 0, &bqs, sizeof(btrfs_query_scrub)); 322 323 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { 324 ShowNtStatusError(hwndDlg, Status); 325 CloseHandle(h); 326 return; 327 } 328 329 CloseHandle(h); 330 } else { 331 ShowError(hwndDlg, GetLastError()); 332 return; 333 } 334 335 if (first_time || status != bqs.status || chunks_left != bqs.chunks_left) { 336 WCHAR s[255]; 337 338 if (bqs.status == BTRFS_SCRUB_STOPPED) { 339 EnableWindow(GetDlgItem(hwndDlg, IDC_START_SCRUB), TRUE); 340 EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_SCRUB), FALSE); 341 EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_SCRUB), FALSE); 342 343 if (bqs.error != STATUS_SUCCESS) { 344 WCHAR t[255]; 345 346 if (!LoadStringW(module, IDS_SCRUB_FAILED, t, sizeof(t) / sizeof(WCHAR))) { 347 ShowError(hwndDlg, GetLastError()); 348 return; 349 } 350 351 if (StringCchPrintfW(s, sizeof(s) / sizeof(WCHAR), t, bqs.error) == STRSAFE_E_INSUFFICIENT_BUFFER) 352 return; 353 } else { 354 if (!LoadStringW(module, bqs.total_chunks == 0 ? IDS_NO_SCRUB : IDS_SCRUB_FINISHED, s, sizeof(s) / sizeof(WCHAR))) { 355 ShowError(hwndDlg, GetLastError()); 356 return; 357 } 358 } 359 } else { 360 WCHAR t[255]; 361 float pc; 362 363 EnableWindow(GetDlgItem(hwndDlg, IDC_START_SCRUB), FALSE); 364 EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_SCRUB), TRUE); 365 EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_SCRUB), TRUE); 366 367 if (!LoadStringW(module, bqs.status == BTRFS_SCRUB_PAUSED ? IDS_SCRUB_PAUSED : IDS_SCRUB_RUNNING, t, sizeof(t) / sizeof(WCHAR))) { 368 ShowError(hwndDlg, GetLastError()); 369 return; 370 } 371 372 pc = ((float)(bqs.total_chunks - bqs.chunks_left) / (float)bqs.total_chunks) * 100.0f; 373 374 if (StringCchPrintfW(s, sizeof(s) / sizeof(WCHAR), t, bqs.total_chunks - bqs.chunks_left, bqs.total_chunks, pc) == STRSAFE_E_INSUFFICIENT_BUFFER) 375 return; 376 } 377 378 SetDlgItemTextW(hwndDlg, IDC_SCRUB_STATUS, s); 379 380 if (first_time || status != bqs.status) { 381 EnableWindow(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), bqs.status != BTRFS_SCRUB_STOPPED); 382 383 if (bqs.status != BTRFS_SCRUB_STOPPED) { 384 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETRANGE32, 0, (LPARAM)bqs.total_chunks); 385 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETPOS, (WPARAM)(bqs.total_chunks - bqs.chunks_left), 0); 386 387 if (bqs.status == BTRFS_SCRUB_PAUSED) 388 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETSTATE, PBST_PAUSED, 0); 389 else 390 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETSTATE, PBST_NORMAL, 0); 391 } else { 392 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETRANGE32, 0, 0); 393 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETPOS, 0, 0); 394 } 395 396 chunks_left = bqs.chunks_left; 397 } 398 } 399 400 if (bqs.status != BTRFS_SCRUB_STOPPED && chunks_left != bqs.chunks_left) { 401 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETPOS, (WPARAM)(bqs.total_chunks - bqs.chunks_left), 0); 402 chunks_left = bqs.chunks_left; 403 } 404 405 if (first_time || status != bqs.status || num_errors != bqs.num_errors) { 406 UpdateTextBox(hwndDlg, &bqs); 407 408 num_errors = bqs.num_errors; 409 } 410 411 status = bqs.status; 412 } 413 414 void BtrfsScrub::StartScrub(HWND hwndDlg) { 415 HANDLE h; 416 417 h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 418 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); 419 if (h != INVALID_HANDLE_VALUE) { 420 NTSTATUS Status; 421 IO_STATUS_BLOCK iosb; 422 423 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_START_SCRUB, NULL, 0, NULL, 0); 424 425 if (Status == STATUS_DEVICE_NOT_READY) { 426 btrfs_query_balance bqb; 427 NTSTATUS Status2; 428 429 Status2 = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_QUERY_BALANCE, NULL, 0, &bqb, sizeof(btrfs_query_balance)); 430 431 if (NT_SUCCESS(Status2) && bqb.status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED)) { 432 ShowStringError(hwndDlg, IDS_SCRUB_BALANCE_RUNNING); 433 CloseHandle(h); 434 return; 435 } 436 } 437 438 if (!NT_SUCCESS(Status)) { 439 ShowNtStatusError(hwndDlg, Status); 440 CloseHandle(h); 441 return; 442 } 443 444 RefreshScrubDlg(hwndDlg, TRUE); 445 446 CloseHandle(h); 447 } else { 448 ShowError(hwndDlg, GetLastError()); 449 return; 450 } 451 } 452 453 void BtrfsScrub::PauseScrub(HWND hwndDlg) { 454 HANDLE h; 455 btrfs_query_scrub bqs; 456 457 h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 458 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); 459 if (h != INVALID_HANDLE_VALUE) { 460 NTSTATUS Status; 461 IO_STATUS_BLOCK iosb; 462 463 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_QUERY_SCRUB, NULL, 0, &bqs, sizeof(btrfs_query_scrub)); 464 465 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { 466 ShowNtStatusError(hwndDlg, Status); 467 CloseHandle(h); 468 return; 469 } 470 471 if (bqs.status == BTRFS_SCRUB_PAUSED) 472 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_RESUME_SCRUB, NULL, 0, NULL, 0); 473 else 474 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_PAUSE_SCRUB, NULL, 0, NULL, 0); 475 476 if (!NT_SUCCESS(Status)) { 477 ShowNtStatusError(hwndDlg, Status); 478 CloseHandle(h); 479 return; 480 } 481 482 CloseHandle(h); 483 } else { 484 ShowError(hwndDlg, GetLastError()); 485 return; 486 } 487 } 488 489 void BtrfsScrub::StopScrub(HWND hwndDlg) { 490 HANDLE h; 491 492 h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 493 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); 494 if (h != INVALID_HANDLE_VALUE) { 495 NTSTATUS Status; 496 IO_STATUS_BLOCK iosb; 497 498 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_STOP_SCRUB, NULL, 0, NULL, 0); 499 500 if (!NT_SUCCESS(Status)) { 501 ShowNtStatusError(hwndDlg, Status); 502 CloseHandle(h); 503 return; 504 } 505 506 CloseHandle(h); 507 } else { 508 ShowError(hwndDlg, GetLastError()); 509 return; 510 } 511 } 512 513 INT_PTR CALLBACK BtrfsScrub::ScrubDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 514 switch (uMsg) { 515 case WM_INITDIALOG: 516 RefreshScrubDlg(hwndDlg, TRUE); 517 SetTimer(hwndDlg, 1, 1000, NULL); 518 break; 519 520 case WM_COMMAND: 521 switch (HIWORD(wParam)) { 522 case BN_CLICKED: 523 switch (LOWORD(wParam)) { 524 case IDOK: 525 case IDCANCEL: 526 EndDialog(hwndDlg, 0); 527 return TRUE; 528 529 case IDC_START_SCRUB: 530 StartScrub(hwndDlg); 531 return TRUE; 532 533 case IDC_PAUSE_SCRUB: 534 PauseScrub(hwndDlg); 535 return TRUE; 536 537 case IDC_CANCEL_SCRUB: 538 StopScrub(hwndDlg); 539 return TRUE; 540 } 541 break; 542 } 543 break; 544 545 case WM_TIMER: 546 RefreshScrubDlg(hwndDlg, FALSE); 547 break; 548 } 549 550 return FALSE; 551 } 552 553 static INT_PTR CALLBACK stub_ScrubDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 554 BtrfsScrub* bs; 555 556 if (uMsg == WM_INITDIALOG) { 557 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); 558 bs = (BtrfsScrub*)lParam; 559 } else { 560 bs = (BtrfsScrub*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 561 } 562 563 if (bs) 564 return bs->ScrubDlgProc(hwndDlg, uMsg, wParam, lParam); 565 else 566 return FALSE; 567 } 568 569 void CALLBACK ShowScrubW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 570 HANDLE token; 571 TOKEN_PRIVILEGES tp; 572 LUID luid; 573 BtrfsScrub* scrub; 574 575 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { 576 ShowError(hwnd, GetLastError()); 577 return; 578 } 579 580 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) { 581 ShowError(hwnd, GetLastError()); 582 goto end; 583 } 584 585 tp.PrivilegeCount = 1; 586 tp.Privileges[0].Luid = luid; 587 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 588 589 if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { 590 ShowError(hwnd, GetLastError()); 591 goto end; 592 } 593 594 set_dpi_aware(); 595 596 scrub = new BtrfsScrub(lpszCmdLine); 597 598 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_SCRUB), hwnd, stub_ScrubDlgProc, (LPARAM)scrub); 599 600 delete scrub; 601 602 end: 603 CloseHandle(token); 604 } 605 606 void CALLBACK StartScrubW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 607 LPWSTR* args; 608 int num_args; 609 610 args = CommandLineToArgvW(lpszCmdLine, &num_args); 611 612 if (!args) 613 return; 614 615 if (num_args >= 1) { 616 HANDLE h, token; 617 LUID luid; 618 TOKEN_PRIVILEGES tp; 619 620 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 621 goto end; 622 623 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) { 624 CloseHandle(token); 625 goto end; 626 } 627 628 tp.PrivilegeCount = 1; 629 tp.Privileges[0].Luid = luid; 630 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 631 632 if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { 633 CloseHandle(token); 634 goto end; 635 } 636 637 CloseHandle(token); 638 639 h = CreateFileW(args[0], FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 640 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); 641 if (h != INVALID_HANDLE_VALUE) { 642 IO_STATUS_BLOCK iosb; 643 644 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_START_SCRUB, NULL, 0, NULL, 0); 645 646 CloseHandle(h); 647 } 648 } 649 650 end: 651 LocalFree(args); 652 } 653 654 void CALLBACK StopScrubW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 655 LPWSTR* args; 656 int num_args; 657 658 args = CommandLineToArgvW(lpszCmdLine, &num_args); 659 660 if (!args) 661 return; 662 663 if (num_args >= 1) { 664 HANDLE h, token; 665 LUID luid; 666 TOKEN_PRIVILEGES tp; 667 668 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 669 goto end; 670 671 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) 672 goto end; 673 674 tp.PrivilegeCount = 1; 675 tp.Privileges[0].Luid = luid; 676 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 677 678 if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) 679 goto end; 680 681 CloseHandle(token); 682 683 h = CreateFileW(args[0], FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 684 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); 685 if (h != INVALID_HANDLE_VALUE) { 686 IO_STATUS_BLOCK iosb; 687 688 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_STOP_SCRUB, NULL, 0, NULL, 0); 689 690 CloseHandle(h); 691 } 692 } 693 694 end: 695 LocalFree(args); 696 } 697