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 #include "shellext.h" 19 #include "balance.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 41 #define NO_SHLWAPI_STRFCNS 42 #include <shlwapi.h> 43 #include <uxtheme.h> 44 45 static uint64_t convtypes2[] = { BLOCK_FLAG_SINGLE, BLOCK_FLAG_DUPLICATE, BLOCK_FLAG_RAID0, BLOCK_FLAG_RAID1, BLOCK_FLAG_RAID5, BLOCK_FLAG_RAID6, BLOCK_FLAG_RAID10 }; 46 47 static WCHAR hex_digit(uint8_t u) { 48 if (u >= 0xa && u <= 0xf) 49 return (uint8_t)(u - 0xa + 'a'); 50 else 51 return (uint8_t)(u + '0'); 52 } 53 54 static void serialize(void* data, ULONG len, WCHAR* s) { 55 uint8_t* d; 56 57 d = (uint8_t*)data; 58 59 while (true) { 60 *s = hex_digit((uint8_t)(*d >> 4)); s++; 61 *s = hex_digit(*d & 0xf); s++; 62 63 d++; 64 len--; 65 66 if (len == 0) { 67 *s = 0; 68 return; 69 } 70 } 71 } 72 73 void BtrfsBalance::StartBalance(HWND hwndDlg) { 74 wstring t; 75 WCHAR modfn[MAX_PATH], u[600]; 76 SHELLEXECUTEINFOW sei; 77 btrfs_start_balance bsb; 78 79 GetModuleFileNameW(module, modfn, sizeof(modfn) / sizeof(WCHAR)); 80 81 #ifndef __REACTOS__ 82 t = L"\""s + modfn + L"\",StartBalance "s + fn + L" "s; 83 #else 84 t = wstring(L"\"") + modfn + wstring(L"\",StartBalance ") + fn + wstring(L" "); 85 #endif 86 87 RtlCopyMemory(&bsb.opts[0], &data_opts, sizeof(btrfs_balance_opts)); 88 RtlCopyMemory(&bsb.opts[1], &metadata_opts, sizeof(btrfs_balance_opts)); 89 RtlCopyMemory(&bsb.opts[2], &system_opts, sizeof(btrfs_balance_opts)); 90 91 if (IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED) 92 bsb.opts[0].flags |= BTRFS_BALANCE_OPTS_ENABLED; 93 else 94 bsb.opts[0].flags &= ~BTRFS_BALANCE_OPTS_ENABLED; 95 96 if (IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED) 97 bsb.opts[1].flags |= BTRFS_BALANCE_OPTS_ENABLED; 98 else 99 bsb.opts[1].flags &= ~BTRFS_BALANCE_OPTS_ENABLED; 100 101 if (IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED) 102 bsb.opts[2].flags |= BTRFS_BALANCE_OPTS_ENABLED; 103 else 104 bsb.opts[2].flags &= ~BTRFS_BALANCE_OPTS_ENABLED; 105 106 serialize(&bsb, sizeof(btrfs_start_balance), u); 107 108 t += u; 109 110 RtlZeroMemory(&sei, sizeof(sei)); 111 112 sei.cbSize = sizeof(sei); 113 sei.hwnd = hwndDlg; 114 sei.lpVerb = L"runas"; 115 sei.lpFile = L"rundll32.exe"; 116 sei.lpParameters = t.c_str(); 117 sei.nShow = SW_SHOW; 118 sei.fMask = SEE_MASK_NOCLOSEPROCESS; 119 120 if (!ShellExecuteExW(&sei)) 121 throw last_error(GetLastError()); 122 123 cancelling = false; 124 removing = false; 125 shrinking = false; 126 balance_status = BTRFS_BALANCE_RUNNING; 127 128 EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_BALANCE), true); 129 EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_BALANCE), true); 130 EnableWindow(GetDlgItem(hwndDlg, IDC_BALANCE_PROGRESS), true); 131 EnableWindow(GetDlgItem(hwndDlg, IDC_DATA), false); 132 EnableWindow(GetDlgItem(hwndDlg, IDC_METADATA), false); 133 EnableWindow(GetDlgItem(hwndDlg, IDC_SYSTEM), false); 134 EnableWindow(GetDlgItem(hwndDlg, IDC_DATA_OPTIONS), data_opts.flags & BTRFS_BALANCE_OPTS_ENABLED ? true : false); 135 EnableWindow(GetDlgItem(hwndDlg, IDC_METADATA_OPTIONS), metadata_opts.flags & BTRFS_BALANCE_OPTS_ENABLED ? true : false); 136 EnableWindow(GetDlgItem(hwndDlg, IDC_SYSTEM_OPTIONS), system_opts.flags & BTRFS_BALANCE_OPTS_ENABLED ? true : false); 137 138 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), false); 139 140 WaitForSingleObject(sei.hProcess, INFINITE); 141 CloseHandle(sei.hProcess); 142 } 143 144 void BtrfsBalance::PauseBalance(HWND hwndDlg) { 145 WCHAR modfn[MAX_PATH]; 146 wstring t; 147 SHELLEXECUTEINFOW sei; 148 149 GetModuleFileNameW(module, modfn, sizeof(modfn) / sizeof(WCHAR)); 150 151 #ifndef __REACTOS__ 152 t = L"\""s + modfn + L"\",PauseBalance " + fn; 153 #else 154 t = wstring(L"\"") + modfn + wstring(L"\",PauseBalance ") + fn; 155 #endif 156 157 RtlZeroMemory(&sei, sizeof(sei)); 158 159 sei.cbSize = sizeof(sei); 160 sei.hwnd = hwndDlg; 161 sei.lpVerb = L"runas"; 162 sei.lpFile = L"rundll32.exe"; 163 sei.lpParameters = t.c_str(); 164 sei.nShow = SW_SHOW; 165 sei.fMask = SEE_MASK_NOCLOSEPROCESS; 166 167 if (!ShellExecuteExW(&sei)) 168 throw last_error(GetLastError()); 169 170 WaitForSingleObject(sei.hProcess, INFINITE); 171 CloseHandle(sei.hProcess); 172 } 173 174 void BtrfsBalance::StopBalance(HWND hwndDlg) { 175 WCHAR modfn[MAX_PATH]; 176 wstring t; 177 SHELLEXECUTEINFOW sei; 178 179 GetModuleFileNameW(module, modfn, sizeof(modfn) / sizeof(WCHAR)); 180 181 #ifndef __REACTOS__ 182 t = L"\""s + modfn + L"\",StopBalance " + fn; 183 #else 184 t = wstring(L"\"") + modfn + wstring(L"\",StopBalance ") + fn; 185 #endif 186 187 RtlZeroMemory(&sei, sizeof(sei)); 188 189 sei.cbSize = sizeof(sei); 190 sei.hwnd = hwndDlg; 191 sei.lpVerb = L"runas"; 192 sei.lpFile = L"rundll32.exe"; 193 sei.lpParameters = t.c_str(); 194 sei.nShow = SW_SHOW; 195 sei.fMask = SEE_MASK_NOCLOSEPROCESS; 196 197 if (!ShellExecuteExW(&sei)) 198 throw last_error(GetLastError()); 199 200 cancelling = true; 201 202 WaitForSingleObject(sei.hProcess, INFINITE); 203 CloseHandle(sei.hProcess); 204 } 205 206 void BtrfsBalance::RefreshBalanceDlg(HWND hwndDlg, bool first) { 207 bool balancing = false; 208 wstring s, t; 209 210 { 211 win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 212 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 213 214 if (h != INVALID_HANDLE_VALUE) { 215 NTSTATUS Status; 216 IO_STATUS_BLOCK iosb; 217 218 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_BALANCE, nullptr, 0, &bqb, sizeof(btrfs_query_balance)); 219 220 if (!NT_SUCCESS(Status)) 221 throw ntstatus_error(Status); 222 } else 223 throw last_error(GetLastError()); 224 } 225 226 if (cancelling) 227 bqb.status = BTRFS_BALANCE_STOPPED; 228 229 balancing = bqb.status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED); 230 231 if (!balancing) { 232 if (first || balance_status != BTRFS_BALANCE_STOPPED) { 233 int resid; 234 235 EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_BALANCE), false); 236 EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_BALANCE), false); 237 SendMessageW(GetDlgItem(hwndDlg, IDC_BALANCE_PROGRESS), PBM_SETSTATE, PBST_NORMAL, 0); 238 EnableWindow(GetDlgItem(hwndDlg, IDC_BALANCE_PROGRESS), false); 239 EnableWindow(GetDlgItem(hwndDlg, IDC_DATA), true); 240 EnableWindow(GetDlgItem(hwndDlg, IDC_METADATA), true); 241 EnableWindow(GetDlgItem(hwndDlg, IDC_SYSTEM), true); 242 243 if (balance_status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED)) { 244 CheckDlgButton(hwndDlg, IDC_DATA, BST_UNCHECKED); 245 CheckDlgButton(hwndDlg, IDC_METADATA, BST_UNCHECKED); 246 CheckDlgButton(hwndDlg, IDC_SYSTEM, BST_UNCHECKED); 247 248 SendMessage(GetDlgItem(hwndDlg, IDC_BALANCE_PROGRESS), PBM_SETPOS, 0, 0); 249 } 250 251 EnableWindow(GetDlgItem(hwndDlg, IDC_DATA_OPTIONS), IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED ? true : false); 252 EnableWindow(GetDlgItem(hwndDlg, IDC_METADATA_OPTIONS), IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED ? true : false); 253 EnableWindow(GetDlgItem(hwndDlg, IDC_SYSTEM_OPTIONS), IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED ? true : false); 254 255 if (bqb.status & BTRFS_BALANCE_ERROR) { 256 if (removing) 257 resid = IDS_BALANCE_FAILED_REMOVAL; 258 else if (shrinking) 259 resid = IDS_BALANCE_FAILED_SHRINK; 260 else 261 resid = IDS_BALANCE_FAILED; 262 263 if (!load_string(module, resid, s)) 264 throw last_error(GetLastError()); 265 266 wstring_sprintf(t, s, bqb.error, format_ntstatus(bqb.error).c_str()); 267 268 SetDlgItemTextW(hwndDlg, IDC_BALANCE_STATUS, t.c_str()); 269 } else { 270 if (cancelling) 271 resid = removing ? IDS_BALANCE_CANCELLED_REMOVAL : (shrinking ? IDS_BALANCE_CANCELLED_SHRINK : IDS_BALANCE_CANCELLED); 272 else if (balance_status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED)) 273 resid = removing ? IDS_BALANCE_COMPLETE_REMOVAL : (shrinking ? IDS_BALANCE_COMPLETE_SHRINK : IDS_BALANCE_COMPLETE); 274 else 275 resid = IDS_NO_BALANCE; 276 277 if (!load_string(module, resid, s)) 278 throw last_error(GetLastError()); 279 280 SetDlgItemTextW(hwndDlg, IDC_BALANCE_STATUS, s.c_str()); 281 } 282 283 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), !readonly && (IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED || 284 IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED || IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED) ? true: false); 285 286 balance_status = bqb.status; 287 cancelling = false; 288 } 289 290 return; 291 } 292 293 if (first || !(balance_status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED))) { 294 EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_BALANCE), true); 295 EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_BALANCE), true); 296 EnableWindow(GetDlgItem(hwndDlg, IDC_BALANCE_PROGRESS), true); 297 EnableWindow(GetDlgItem(hwndDlg, IDC_DATA), false); 298 EnableWindow(GetDlgItem(hwndDlg, IDC_METADATA), false); 299 EnableWindow(GetDlgItem(hwndDlg, IDC_SYSTEM), false); 300 301 CheckDlgButton(hwndDlg, IDC_DATA, bqb.data_opts.flags & BTRFS_BALANCE_OPTS_ENABLED ? BST_CHECKED : BST_UNCHECKED); 302 CheckDlgButton(hwndDlg, IDC_METADATA, bqb.metadata_opts.flags & BTRFS_BALANCE_OPTS_ENABLED ? BST_CHECKED : BST_UNCHECKED); 303 CheckDlgButton(hwndDlg, IDC_SYSTEM, bqb.system_opts.flags & BTRFS_BALANCE_OPTS_ENABLED ? BST_CHECKED : BST_UNCHECKED); 304 305 EnableWindow(GetDlgItem(hwndDlg, IDC_DATA_OPTIONS), bqb.data_opts.flags & BTRFS_BALANCE_OPTS_ENABLED ? true : false); 306 EnableWindow(GetDlgItem(hwndDlg, IDC_METADATA_OPTIONS), bqb.metadata_opts.flags & BTRFS_BALANCE_OPTS_ENABLED ? true : false); 307 EnableWindow(GetDlgItem(hwndDlg, IDC_SYSTEM_OPTIONS), bqb.system_opts.flags & BTRFS_BALANCE_OPTS_ENABLED ? true : false); 308 309 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), false); 310 } 311 312 SendMessageW(GetDlgItem(hwndDlg, IDC_BALANCE_PROGRESS), PBM_SETRANGE32, 0, (LPARAM)bqb.total_chunks); 313 SendMessageW(GetDlgItem(hwndDlg, IDC_BALANCE_PROGRESS), PBM_SETPOS, (WPARAM)(bqb.total_chunks - bqb.chunks_left), 0); 314 315 if (bqb.status & BTRFS_BALANCE_PAUSED && balance_status != bqb.status) 316 SendMessageW(GetDlgItem(hwndDlg, IDC_BALANCE_PROGRESS), PBM_SETSTATE, PBST_PAUSED, 0); 317 else if (!(bqb.status & BTRFS_BALANCE_PAUSED) && balance_status & BTRFS_BALANCE_PAUSED) 318 SendMessageW(GetDlgItem(hwndDlg, IDC_BALANCE_PROGRESS), PBM_SETSTATE, PBST_NORMAL, 0); 319 320 balance_status = bqb.status; 321 322 if (bqb.status & BTRFS_BALANCE_REMOVAL) { 323 if (!load_string(module, balance_status & BTRFS_BALANCE_PAUSED ? IDS_BALANCE_PAUSED_REMOVAL : IDS_BALANCE_RUNNING_REMOVAL, s)) 324 throw last_error(GetLastError()); 325 326 wstring_sprintf(t, s, bqb.data_opts.devid, bqb.total_chunks - bqb.chunks_left, bqb.total_chunks, 327 (float)(bqb.total_chunks - bqb.chunks_left) * 100.0f / (float)bqb.total_chunks); 328 329 removing = true; 330 shrinking = false; 331 } else if (bqb.status & BTRFS_BALANCE_SHRINKING) { 332 if (!load_string(module, balance_status & BTRFS_BALANCE_PAUSED ? IDS_BALANCE_PAUSED_SHRINK : IDS_BALANCE_RUNNING_SHRINK, s)) 333 throw last_error(GetLastError()); 334 335 wstring_sprintf(t, s, bqb.data_opts.devid, bqb.total_chunks - bqb.chunks_left, bqb.total_chunks, 336 (float)(bqb.total_chunks - bqb.chunks_left) * 100.0f / (float)bqb.total_chunks); 337 338 removing = false; 339 shrinking = true; 340 } else { 341 if (!load_string(module, balance_status & BTRFS_BALANCE_PAUSED ? IDS_BALANCE_PAUSED : IDS_BALANCE_RUNNING, s)) 342 throw last_error(GetLastError()); 343 344 wstring_sprintf(t, s, bqb.total_chunks - bqb.chunks_left, bqb.total_chunks, 345 (float)(bqb.total_chunks - bqb.chunks_left) * 100.0f / (float)bqb.total_chunks); 346 347 removing = false; 348 shrinking = false; 349 } 350 351 SetDlgItemTextW(hwndDlg, IDC_BALANCE_STATUS, t.c_str()); 352 } 353 354 void BtrfsBalance::SaveBalanceOpts(HWND hwndDlg) { 355 btrfs_balance_opts* opts; 356 357 switch (opts_type) { 358 case 1: 359 opts = &data_opts; 360 break; 361 362 case 2: 363 opts = &metadata_opts; 364 break; 365 366 case 3: 367 opts = &system_opts; 368 break; 369 370 default: 371 return; 372 } 373 374 RtlZeroMemory(opts, sizeof(btrfs_balance_opts)); 375 376 if (IsDlgButtonChecked(hwndDlg, IDC_PROFILES) == BST_CHECKED) { 377 opts->flags |= BTRFS_BALANCE_OPTS_PROFILES; 378 379 if (IsDlgButtonChecked(hwndDlg, IDC_PROFILES_SINGLE) == BST_CHECKED) opts->profiles |= BLOCK_FLAG_SINGLE; 380 if (IsDlgButtonChecked(hwndDlg, IDC_PROFILES_DUP) == BST_CHECKED) opts->profiles |= BLOCK_FLAG_DUPLICATE; 381 if (IsDlgButtonChecked(hwndDlg, IDC_PROFILES_RAID0) == BST_CHECKED) opts->profiles |= BLOCK_FLAG_RAID0; 382 if (IsDlgButtonChecked(hwndDlg, IDC_PROFILES_RAID1) == BST_CHECKED) opts->profiles |= BLOCK_FLAG_RAID1; 383 if (IsDlgButtonChecked(hwndDlg, IDC_PROFILES_RAID10) == BST_CHECKED) opts->profiles |= BLOCK_FLAG_RAID10; 384 if (IsDlgButtonChecked(hwndDlg, IDC_PROFILES_RAID5) == BST_CHECKED) opts->profiles |= BLOCK_FLAG_RAID5; 385 if (IsDlgButtonChecked(hwndDlg, IDC_PROFILES_RAID6) == BST_CHECKED) opts->profiles |= BLOCK_FLAG_RAID6; 386 } 387 388 if (IsDlgButtonChecked(hwndDlg, IDC_DEVID) == BST_CHECKED) { 389 int sel; 390 391 opts->flags |= BTRFS_BALANCE_OPTS_DEVID; 392 393 sel = SendMessageW(GetDlgItem(hwndDlg, IDC_DEVID_COMBO), CB_GETCURSEL, 0, 0); 394 395 if (sel == CB_ERR) 396 opts->flags &= ~BTRFS_BALANCE_OPTS_DEVID; 397 else { 398 btrfs_device* bd = devices; 399 int i = 0; 400 401 while (true) { 402 if (i == sel) { 403 opts->devid = bd->dev_id; 404 break; 405 } 406 407 i++; 408 409 if (bd->next_entry > 0) 410 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 411 else 412 break; 413 } 414 415 if (opts->devid == 0) 416 opts->flags &= ~BTRFS_BALANCE_OPTS_DEVID; 417 } 418 } 419 420 if (IsDlgButtonChecked(hwndDlg, IDC_DRANGE) == BST_CHECKED) { 421 WCHAR s[255]; 422 423 opts->flags |= BTRFS_BALANCE_OPTS_DRANGE; 424 425 GetWindowTextW(GetDlgItem(hwndDlg, IDC_DRANGE_START), s, sizeof(s) / sizeof(WCHAR)); 426 opts->drange_start = _wtoi64(s); 427 428 GetWindowTextW(GetDlgItem(hwndDlg, IDC_DRANGE_END), s, sizeof(s) / sizeof(WCHAR)); 429 opts->drange_end = _wtoi64(s); 430 431 if (opts->drange_end < opts->drange_start) 432 throw string_error(IDS_DRANGE_END_BEFORE_START); 433 } 434 435 if (IsDlgButtonChecked(hwndDlg, IDC_VRANGE) == BST_CHECKED) { 436 WCHAR s[255]; 437 438 opts->flags |= BTRFS_BALANCE_OPTS_VRANGE; 439 440 GetWindowTextW(GetDlgItem(hwndDlg, IDC_VRANGE_START), s, sizeof(s) / sizeof(WCHAR)); 441 opts->vrange_start = _wtoi64(s); 442 443 GetWindowTextW(GetDlgItem(hwndDlg, IDC_VRANGE_END), s, sizeof(s) / sizeof(WCHAR)); 444 opts->vrange_end = _wtoi64(s); 445 446 if (opts->vrange_end < opts->vrange_start) 447 throw string_error(IDS_VRANGE_END_BEFORE_START); 448 } 449 450 if (IsDlgButtonChecked(hwndDlg, IDC_LIMIT) == BST_CHECKED) { 451 WCHAR s[255]; 452 453 opts->flags |= BTRFS_BALANCE_OPTS_LIMIT; 454 455 GetWindowTextW(GetDlgItem(hwndDlg, IDC_LIMIT_START), s, sizeof(s) / sizeof(WCHAR)); 456 opts->limit_start = _wtoi64(s); 457 458 GetWindowTextW(GetDlgItem(hwndDlg, IDC_LIMIT_END), s, sizeof(s) / sizeof(WCHAR)); 459 opts->limit_end = _wtoi64(s); 460 461 if (opts->limit_end < opts->limit_start) 462 throw string_error(IDS_LIMIT_END_BEFORE_START); 463 } 464 465 if (IsDlgButtonChecked(hwndDlg, IDC_STRIPES) == BST_CHECKED) { 466 WCHAR s[255]; 467 468 opts->flags |= BTRFS_BALANCE_OPTS_STRIPES; 469 470 GetWindowTextW(GetDlgItem(hwndDlg, IDC_STRIPES_START), s, sizeof(s) / sizeof(WCHAR)); 471 opts->stripes_start = (uint8_t)_wtoi(s); 472 473 GetWindowTextW(GetDlgItem(hwndDlg, IDC_STRIPES_END), s, sizeof(s) / sizeof(WCHAR)); 474 opts->stripes_end = (uint8_t)_wtoi(s); 475 476 if (opts->stripes_end < opts->stripes_start) 477 throw string_error(IDS_STRIPES_END_BEFORE_START); 478 } 479 480 if (IsDlgButtonChecked(hwndDlg, IDC_USAGE) == BST_CHECKED) { 481 WCHAR s[255]; 482 483 opts->flags |= BTRFS_BALANCE_OPTS_USAGE; 484 485 GetWindowTextW(GetDlgItem(hwndDlg, IDC_USAGE_START), s, sizeof(s) / sizeof(WCHAR)); 486 opts->usage_start = (uint8_t)_wtoi(s); 487 488 GetWindowTextW(GetDlgItem(hwndDlg, IDC_USAGE_END), s, sizeof(s) / sizeof(WCHAR)); 489 opts->usage_end = (uint8_t)_wtoi(s); 490 491 if (opts->usage_end < opts->usage_start) 492 throw string_error(IDS_USAGE_END_BEFORE_START); 493 } 494 495 if (IsDlgButtonChecked(hwndDlg, IDC_CONVERT) == BST_CHECKED) { 496 int sel; 497 498 opts->flags |= BTRFS_BALANCE_OPTS_CONVERT; 499 500 sel = SendMessageW(GetDlgItem(hwndDlg, IDC_CONVERT_COMBO), CB_GETCURSEL, 0, 0); 501 502 if (sel == CB_ERR || (unsigned int)sel >= sizeof(convtypes2) / sizeof(convtypes2[0])) 503 opts->flags &= ~BTRFS_BALANCE_OPTS_CONVERT; 504 else { 505 opts->convert = convtypes2[sel]; 506 507 if (IsDlgButtonChecked(hwndDlg, IDC_SOFT) == BST_CHECKED) opts->flags |= BTRFS_BALANCE_OPTS_SOFT; 508 } 509 } 510 511 EndDialog(hwndDlg, 0); 512 } 513 514 INT_PTR CALLBACK BtrfsBalance::BalanceOptsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 515 try { 516 switch (uMsg) { 517 case WM_INITDIALOG: 518 { 519 HWND devcb, convcb; 520 btrfs_device* bd; 521 btrfs_balance_opts* opts; 522 static int convtypes[] = { IDS_SINGLE2, IDS_DUP, IDS_RAID0, IDS_RAID1, IDS_RAID5, IDS_RAID6, IDS_RAID10, 0 }; 523 int i, num_devices = 0, num_writeable_devices = 0; 524 wstring s, u; 525 bool balance_started = balance_status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED); 526 527 switch (opts_type) { 528 case 1: 529 opts = balance_started ? &bqb.data_opts : &data_opts; 530 break; 531 532 case 2: 533 opts = balance_started ? &bqb.metadata_opts : &metadata_opts; 534 break; 535 536 case 3: 537 opts = balance_started ? &bqb.system_opts : &system_opts; 538 break; 539 540 default: 541 return true; 542 } 543 544 EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); 545 546 devcb = GetDlgItem(hwndDlg, IDC_DEVID_COMBO); 547 548 if (!load_string(module, IDS_DEVID_LIST, u)) 549 throw last_error(GetLastError()); 550 551 bd = devices; 552 while (true) { 553 wstring t, v; 554 555 if (bd->device_number == 0xffffffff) 556 s = wstring(bd->name, bd->namelen); 557 else if (bd->partition_number == 0) { 558 if (!load_string(module, IDS_DISK_NUM, v)) 559 throw last_error(GetLastError()); 560 561 wstring_sprintf(s, v, bd->device_number); 562 } else { 563 if (!load_string(module, IDS_DISK_PART_NUM, v)) 564 throw last_error(GetLastError()); 565 566 wstring_sprintf(s, v, bd->device_number, bd->partition_number); 567 } 568 569 wstring_sprintf(t, u, bd->dev_id, s.c_str()); 570 571 SendMessage(devcb, CB_ADDSTRING, 0, (LPARAM)t.c_str()); 572 573 if (opts->devid == bd->dev_id) 574 SendMessage(devcb, CB_SETCURSEL, num_devices, 0); 575 576 num_devices++; 577 578 if (!bd->readonly) 579 num_writeable_devices++; 580 581 if (bd->next_entry > 0) 582 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 583 else 584 break; 585 } 586 587 convcb = GetDlgItem(hwndDlg, IDC_CONVERT_COMBO); 588 589 if (num_writeable_devices == 0) 590 num_writeable_devices = num_devices; 591 592 i = 0; 593 while (convtypes[i] != 0) { 594 if (!load_string(module, convtypes[i], s)) 595 throw last_error(GetLastError()); 596 597 SendMessage(convcb, CB_ADDSTRING, 0, (LPARAM)s.c_str()); 598 599 if (opts->convert == convtypes2[i]) 600 SendMessage(convcb, CB_SETCURSEL, i, 0); 601 602 i++; 603 604 if (num_writeable_devices < 2 && i == 2) 605 break; 606 else if (num_writeable_devices < 3 && i == 4) 607 break; 608 else if (num_writeable_devices < 4 && i == 5) 609 break; 610 } 611 612 // profiles 613 614 CheckDlgButton(hwndDlg, IDC_PROFILES, opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? BST_CHECKED : BST_UNCHECKED); 615 CheckDlgButton(hwndDlg, IDC_PROFILES_SINGLE, opts->profiles & BLOCK_FLAG_SINGLE ? BST_CHECKED : BST_UNCHECKED); 616 CheckDlgButton(hwndDlg, IDC_PROFILES_DUP, opts->profiles & BLOCK_FLAG_DUPLICATE ? BST_CHECKED : BST_UNCHECKED); 617 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID0, opts->profiles & BLOCK_FLAG_RAID0 ? BST_CHECKED : BST_UNCHECKED); 618 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID1, opts->profiles & BLOCK_FLAG_RAID1 ? BST_CHECKED : BST_UNCHECKED); 619 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID10, opts->profiles & BLOCK_FLAG_RAID10 ? BST_CHECKED : BST_UNCHECKED); 620 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID5, opts->profiles & BLOCK_FLAG_RAID5 ? BST_CHECKED : BST_UNCHECKED); 621 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID6, opts->profiles & BLOCK_FLAG_RAID6 ? BST_CHECKED : BST_UNCHECKED); 622 623 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_SINGLE), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? true : false); 624 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_DUP), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? true : false); 625 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID0), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? true : false); 626 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID1), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? true : false); 627 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID10), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? true : false); 628 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID5), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? true : false); 629 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID6), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? true : false); 630 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES), balance_started ? false : true); 631 632 // usage 633 634 CheckDlgButton(hwndDlg, IDC_USAGE, opts->flags & BTRFS_BALANCE_OPTS_USAGE ? BST_CHECKED : BST_UNCHECKED); 635 636 s = to_wstring(opts->usage_start); 637 SetDlgItemTextW(hwndDlg, IDC_USAGE_START, s.c_str()); 638 SendMessageW(GetDlgItem(hwndDlg, IDC_USAGE_START_SPINNER), UDM_SETRANGE32, 0, 100); 639 640 s = to_wstring(opts->usage_end); 641 SetDlgItemTextW(hwndDlg, IDC_USAGE_END, s.c_str()); 642 SendMessageW(GetDlgItem(hwndDlg, IDC_USAGE_END_SPINNER), UDM_SETRANGE32, 0, 100); 643 644 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_START), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_USAGE ? true : false); 645 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_START_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_USAGE ? true : false); 646 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_END), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_USAGE ? true : false); 647 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_END_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_USAGE ? true : false); 648 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE), balance_started ? false : true); 649 650 // devid 651 652 if (num_devices < 2 || balance_started) 653 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVID), false); 654 655 CheckDlgButton(hwndDlg, IDC_DEVID, opts->flags & BTRFS_BALANCE_OPTS_DEVID ? BST_CHECKED : BST_UNCHECKED); 656 EnableWindow(devcb, (opts->flags & BTRFS_BALANCE_OPTS_DEVID && num_devices >= 2 && !balance_started) ? true : false); 657 658 // drange 659 660 CheckDlgButton(hwndDlg, IDC_DRANGE, opts->flags & BTRFS_BALANCE_OPTS_DRANGE ? BST_CHECKED : BST_UNCHECKED); 661 662 s = to_wstring(opts->drange_start); 663 SetDlgItemTextW(hwndDlg, IDC_DRANGE_START, s.c_str()); 664 665 s = to_wstring(opts->drange_end); 666 SetDlgItemTextW(hwndDlg, IDC_DRANGE_END, s.c_str()); 667 668 EnableWindow(GetDlgItem(hwndDlg, IDC_DRANGE_START), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_DRANGE ? true : false); 669 EnableWindow(GetDlgItem(hwndDlg, IDC_DRANGE_END), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_DRANGE ? true : false); 670 EnableWindow(GetDlgItem(hwndDlg, IDC_DRANGE), balance_started ? false : true); 671 672 // vrange 673 674 CheckDlgButton(hwndDlg, IDC_VRANGE, opts->flags & BTRFS_BALANCE_OPTS_VRANGE ? BST_CHECKED : BST_UNCHECKED); 675 676 s = to_wstring(opts->vrange_start); 677 SetDlgItemTextW(hwndDlg, IDC_VRANGE_START, s.c_str()); 678 679 s = to_wstring(opts->vrange_end); 680 SetDlgItemTextW(hwndDlg, IDC_VRANGE_END, s.c_str()); 681 682 EnableWindow(GetDlgItem(hwndDlg, IDC_VRANGE_START), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_VRANGE ? true : false); 683 EnableWindow(GetDlgItem(hwndDlg, IDC_VRANGE_END), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_VRANGE ? true : false); 684 EnableWindow(GetDlgItem(hwndDlg, IDC_VRANGE), balance_started ? false : true); 685 686 // limit 687 688 CheckDlgButton(hwndDlg, IDC_LIMIT, opts->flags & BTRFS_BALANCE_OPTS_LIMIT ? BST_CHECKED : BST_UNCHECKED); 689 690 s = to_wstring(opts->limit_start); 691 SetDlgItemTextW(hwndDlg, IDC_LIMIT_START, s.c_str()); 692 SendMessageW(GetDlgItem(hwndDlg, IDC_LIMIT_START_SPINNER), UDM_SETRANGE32, 0, 0x7fffffff); 693 694 s = to_wstring(opts->limit_end); 695 SetDlgItemTextW(hwndDlg, IDC_LIMIT_END, s.c_str()); 696 SendMessageW(GetDlgItem(hwndDlg, IDC_LIMIT_END_SPINNER), UDM_SETRANGE32, 0, 0x7fffffff); 697 698 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_START), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_LIMIT ? true : false); 699 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_START_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_LIMIT ? true : false); 700 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_END), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_LIMIT ? true : false); 701 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_END_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_LIMIT ? true : false); 702 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT), balance_started ? false : true); 703 704 // stripes 705 706 CheckDlgButton(hwndDlg, IDC_STRIPES, opts->flags & BTRFS_BALANCE_OPTS_STRIPES ? BST_CHECKED : BST_UNCHECKED); 707 708 s = to_wstring(opts->stripes_start); 709 SetDlgItemTextW(hwndDlg, IDC_STRIPES_START, s.c_str()); 710 SendMessageW(GetDlgItem(hwndDlg, IDC_STRIPES_START_SPINNER), UDM_SETRANGE32, 0, 0xffff); 711 712 s = to_wstring(opts->stripes_end); 713 SetDlgItemTextW(hwndDlg, IDC_STRIPES_END, s.c_str()); 714 SendMessageW(GetDlgItem(hwndDlg, IDC_STRIPES_END_SPINNER), UDM_SETRANGE32, 0, 0xffff); 715 716 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_START), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_STRIPES ? true : false); 717 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_START_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_STRIPES ? true : false); 718 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_END), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_STRIPES ? true : false); 719 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_END_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_STRIPES ? true : false); 720 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES), balance_started ? false : true); 721 722 // convert 723 724 CheckDlgButton(hwndDlg, IDC_CONVERT, opts->flags & BTRFS_BALANCE_OPTS_CONVERT ? BST_CHECKED : BST_UNCHECKED); 725 CheckDlgButton(hwndDlg, IDC_SOFT, opts->flags & BTRFS_BALANCE_OPTS_SOFT ? BST_CHECKED : BST_UNCHECKED); 726 727 EnableWindow(GetDlgItem(hwndDlg, IDC_SOFT), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_CONVERT ? true : false); 728 EnableWindow(convcb, !balance_started && opts->flags & BTRFS_BALANCE_OPTS_CONVERT ? true : false); 729 EnableWindow(GetDlgItem(hwndDlg, IDC_CONVERT), balance_started ? false : true); 730 731 break; 732 } 733 734 case WM_COMMAND: 735 switch (HIWORD(wParam)) { 736 case BN_CLICKED: 737 switch (LOWORD(wParam)) { 738 case IDOK: 739 if (balance_status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED)) 740 EndDialog(hwndDlg, 0); 741 else 742 SaveBalanceOpts(hwndDlg); 743 return true; 744 745 case IDCANCEL: 746 EndDialog(hwndDlg, 0); 747 return true; 748 749 case IDC_PROFILES: { 750 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_PROFILES) == BST_CHECKED ? true : false; 751 752 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_SINGLE), enabled); 753 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_DUP), enabled); 754 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID0), enabled); 755 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID1), enabled); 756 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID10), enabled); 757 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID5), enabled); 758 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID6), enabled); 759 break; 760 } 761 762 case IDC_USAGE: { 763 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_USAGE) == BST_CHECKED ? true : false; 764 765 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_START), enabled); 766 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_START_SPINNER), enabled); 767 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_END), enabled); 768 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_END_SPINNER), enabled); 769 break; 770 } 771 772 case IDC_DEVID: { 773 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_DEVID) == BST_CHECKED ? true : false; 774 775 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVID_COMBO), enabled); 776 break; 777 } 778 779 case IDC_DRANGE: { 780 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_DRANGE) == BST_CHECKED ? true : false; 781 782 EnableWindow(GetDlgItem(hwndDlg, IDC_DRANGE_START), enabled); 783 EnableWindow(GetDlgItem(hwndDlg, IDC_DRANGE_END), enabled); 784 break; 785 } 786 787 case IDC_VRANGE: { 788 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_VRANGE) == BST_CHECKED ? true : false; 789 790 EnableWindow(GetDlgItem(hwndDlg, IDC_VRANGE_START), enabled); 791 EnableWindow(GetDlgItem(hwndDlg, IDC_VRANGE_END), enabled); 792 break; 793 } 794 795 case IDC_LIMIT: { 796 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_LIMIT) == BST_CHECKED ? true : false; 797 798 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_START), enabled); 799 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_START_SPINNER), enabled); 800 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_END), enabled); 801 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_END_SPINNER), enabled); 802 break; 803 } 804 805 case IDC_STRIPES: { 806 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_STRIPES) == BST_CHECKED ? true : false; 807 808 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_START), enabled); 809 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_START_SPINNER), enabled); 810 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_END), enabled); 811 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_END_SPINNER), enabled); 812 break; 813 } 814 815 case IDC_CONVERT: { 816 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_CONVERT) == BST_CHECKED ? true : false; 817 818 EnableWindow(GetDlgItem(hwndDlg, IDC_CONVERT_COMBO), enabled); 819 EnableWindow(GetDlgItem(hwndDlg, IDC_SOFT), enabled); 820 break; 821 } 822 } 823 break; 824 } 825 break; 826 } 827 } catch (const exception& e) { 828 error_message(hwndDlg, e.what()); 829 } 830 831 return false; 832 } 833 834 static INT_PTR CALLBACK stub_BalanceOptsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 835 BtrfsBalance* bb; 836 837 if (uMsg == WM_INITDIALOG) { 838 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); 839 bb = (BtrfsBalance*)lParam; 840 } else { 841 bb = (BtrfsBalance*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 842 } 843 844 if (bb) 845 return bb->BalanceOptsDlgProc(hwndDlg, uMsg, wParam, lParam); 846 else 847 return false; 848 } 849 850 void BtrfsBalance::ShowBalanceOptions(HWND hwndDlg, uint8_t type) { 851 opts_type = type; 852 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_BALANCE_OPTIONS), hwndDlg, stub_BalanceOptsDlgProc, (LPARAM)this); 853 } 854 855 INT_PTR CALLBACK BtrfsBalance::BalanceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 856 try { 857 switch (uMsg) { 858 case WM_INITDIALOG: 859 { 860 EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); 861 862 RtlZeroMemory(&data_opts, sizeof(btrfs_balance_opts)); 863 RtlZeroMemory(&metadata_opts, sizeof(btrfs_balance_opts)); 864 RtlZeroMemory(&system_opts, sizeof(btrfs_balance_opts)); 865 866 removing = called_from_RemoveDevice; 867 shrinking = called_from_ShrinkDevice; 868 balance_status = (removing || shrinking) ? BTRFS_BALANCE_RUNNING : BTRFS_BALANCE_STOPPED; 869 cancelling = false; 870 RefreshBalanceDlg(hwndDlg, true); 871 872 if (readonly) { 873 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), false); 874 EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_BALANCE), false); 875 EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_BALANCE), false); 876 } 877 878 SendMessageW(GetDlgItem(hwndDlg, IDC_START_BALANCE), BCM_SETSHIELD, 0, true); 879 SendMessageW(GetDlgItem(hwndDlg, IDC_PAUSE_BALANCE), BCM_SETSHIELD, 0, true); 880 SendMessageW(GetDlgItem(hwndDlg, IDC_CANCEL_BALANCE), BCM_SETSHIELD, 0, true); 881 882 SetTimer(hwndDlg, 1, 1000, nullptr); 883 884 break; 885 } 886 887 case WM_COMMAND: 888 switch (HIWORD(wParam)) { 889 case BN_CLICKED: 890 switch (LOWORD(wParam)) { 891 case IDOK: 892 case IDCANCEL: 893 KillTimer(hwndDlg, 1); 894 EndDialog(hwndDlg, 0); 895 return true; 896 897 case IDC_DATA: 898 EnableWindow(GetDlgItem(hwndDlg, IDC_DATA_OPTIONS), IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED ? true : false); 899 900 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), !readonly && (IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED || 901 IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED || IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED) ? true: false); 902 return true; 903 904 case IDC_METADATA: 905 EnableWindow(GetDlgItem(hwndDlg, IDC_METADATA_OPTIONS), IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED ? true : false); 906 907 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), !readonly && (IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED || 908 IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED || IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED) ? true: false); 909 return true; 910 911 case IDC_SYSTEM: 912 EnableWindow(GetDlgItem(hwndDlg, IDC_SYSTEM_OPTIONS), IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED ? true : false); 913 914 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), !readonly && (IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED || 915 IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED || IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED) ? true: false); 916 return true; 917 918 case IDC_DATA_OPTIONS: 919 ShowBalanceOptions(hwndDlg, 1); 920 return true; 921 922 case IDC_METADATA_OPTIONS: 923 ShowBalanceOptions(hwndDlg, 2); 924 return true; 925 926 case IDC_SYSTEM_OPTIONS: 927 ShowBalanceOptions(hwndDlg, 3); 928 return true; 929 930 case IDC_START_BALANCE: 931 StartBalance(hwndDlg); 932 return true; 933 934 case IDC_PAUSE_BALANCE: 935 PauseBalance(hwndDlg); 936 RefreshBalanceDlg(hwndDlg, false); 937 return true; 938 939 case IDC_CANCEL_BALANCE: 940 StopBalance(hwndDlg); 941 RefreshBalanceDlg(hwndDlg, false); 942 return true; 943 } 944 break; 945 } 946 break; 947 948 case WM_TIMER: 949 RefreshBalanceDlg(hwndDlg, false); 950 break; 951 } 952 } catch (const exception& e) { 953 error_message(hwndDlg, e.what()); 954 } 955 956 return false; 957 } 958 959 static INT_PTR CALLBACK stub_BalanceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 960 BtrfsBalance* bb; 961 962 if (uMsg == WM_INITDIALOG) { 963 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); 964 bb = (BtrfsBalance*)lParam; 965 } else { 966 bb = (BtrfsBalance*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 967 } 968 969 if (bb) 970 return bb->BalanceDlgProc(hwndDlg, uMsg, wParam, lParam); 971 else 972 return false; 973 } 974 975 void BtrfsBalance::ShowBalance(HWND hwndDlg) { 976 btrfs_device* bd; 977 978 if (devices) { 979 free(devices); 980 devices = nullptr; 981 } 982 983 { 984 win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 985 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 986 987 if (h != INVALID_HANDLE_VALUE) { 988 NTSTATUS Status; 989 IO_STATUS_BLOCK iosb; 990 ULONG devsize, i; 991 992 i = 0; 993 devsize = 1024; 994 995 devices = (btrfs_device*)malloc(devsize); 996 997 while (true) { 998 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_DEVICES, nullptr, 0, devices, devsize); 999 if (Status == STATUS_BUFFER_OVERFLOW) { 1000 if (i < 8) { 1001 devsize += 1024; 1002 1003 free(devices); 1004 devices = (btrfs_device*)malloc(devsize); 1005 1006 i++; 1007 } else 1008 return; 1009 } else 1010 break; 1011 } 1012 1013 if (!NT_SUCCESS(Status)) 1014 throw ntstatus_error(Status); 1015 } else 1016 throw last_error(GetLastError()); 1017 } 1018 1019 readonly = true; 1020 bd = devices; 1021 1022 while (true) { 1023 if (!bd->readonly) { 1024 readonly = false; 1025 break; 1026 } 1027 1028 if (bd->next_entry > 0) 1029 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 1030 else 1031 break; 1032 } 1033 1034 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_BALANCE), hwndDlg, stub_BalanceDlgProc, (LPARAM)this); 1035 } 1036 1037 static uint8_t from_hex_digit(WCHAR c) { 1038 if (c >= 'a' && c <= 'f') 1039 return (uint8_t)(c - 'a' + 0xa); 1040 else if (c >= 'A' && c <= 'F') 1041 return (uint8_t)(c - 'A' + 0xa); 1042 else 1043 return (uint8_t)(c - '0'); 1044 } 1045 1046 static void unserialize(void* data, ULONG len, WCHAR* s) { 1047 uint8_t* d; 1048 1049 d = (uint8_t*)data; 1050 1051 while (s[0] != 0 && s[1] != 0 && len > 0) { 1052 *d = (uint8_t)(from_hex_digit(s[0]) << 4) | from_hex_digit(s[1]); 1053 1054 s += 2; 1055 d++; 1056 len--; 1057 } 1058 } 1059 1060 #ifdef __REACTOS__ 1061 extern "C" { 1062 #endif 1063 1064 void CALLBACK StartBalanceW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 1065 try { 1066 WCHAR *s, *vol, *block; 1067 win_handle h, token; 1068 btrfs_start_balance bsb; 1069 TOKEN_PRIVILEGES tp; 1070 LUID luid; 1071 1072 s = wcsstr(lpszCmdLine, L" "); 1073 if (!s) 1074 return; 1075 1076 s[0] = 0; 1077 1078 vol = lpszCmdLine; 1079 block = &s[1]; 1080 1081 RtlZeroMemory(&bsb, sizeof(btrfs_start_balance)); 1082 unserialize(&bsb, sizeof(btrfs_start_balance), block); 1083 1084 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1085 throw last_error(GetLastError()); 1086 1087 if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) 1088 throw last_error(GetLastError()); 1089 1090 tp.PrivilegeCount = 1; 1091 tp.Privileges[0].Luid = luid; 1092 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1093 1094 if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) 1095 throw last_error(GetLastError()); 1096 1097 h = CreateFileW(vol, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 1098 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 1099 1100 if (h != INVALID_HANDLE_VALUE) { 1101 NTSTATUS Status; 1102 IO_STATUS_BLOCK iosb; 1103 1104 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_START_BALANCE, &bsb, sizeof(btrfs_start_balance), nullptr, 0); 1105 1106 if (Status == STATUS_DEVICE_NOT_READY) { 1107 btrfs_query_scrub bqs; 1108 NTSTATUS Status2; 1109 1110 Status2 = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_SCRUB, nullptr, 0, &bqs, sizeof(btrfs_query_scrub)); 1111 1112 if ((NT_SUCCESS(Status2) || Status2 == STATUS_BUFFER_OVERFLOW) && bqs.status != BTRFS_SCRUB_STOPPED) 1113 throw string_error(IDS_BALANCE_SCRUB_RUNNING); 1114 } 1115 1116 if (!NT_SUCCESS(Status)) 1117 throw ntstatus_error(Status); 1118 } else 1119 throw last_error(GetLastError()); 1120 } catch (const exception& e) { 1121 error_message(hwnd, e.what()); 1122 } 1123 } 1124 1125 void CALLBACK PauseBalanceW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 1126 try { 1127 win_handle h, token; 1128 TOKEN_PRIVILEGES tp; 1129 LUID luid; 1130 1131 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1132 throw last_error(GetLastError()); 1133 1134 if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) 1135 throw last_error(GetLastError()); 1136 1137 tp.PrivilegeCount = 1; 1138 tp.Privileges[0].Luid = luid; 1139 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1140 1141 if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) 1142 throw last_error(GetLastError()); 1143 1144 h = CreateFileW(lpszCmdLine, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 1145 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 1146 1147 if (h != INVALID_HANDLE_VALUE) { 1148 NTSTATUS Status; 1149 IO_STATUS_BLOCK iosb; 1150 btrfs_query_balance bqb2; 1151 1152 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_BALANCE, nullptr, 0, &bqb2, sizeof(btrfs_query_balance)); 1153 if (!NT_SUCCESS(Status)) 1154 throw ntstatus_error(Status); 1155 1156 if (bqb2.status & BTRFS_BALANCE_PAUSED) 1157 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESUME_BALANCE, nullptr, 0, nullptr, 0); 1158 else if (bqb2.status & BTRFS_BALANCE_RUNNING) 1159 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_PAUSE_BALANCE, nullptr, 0, nullptr, 0); 1160 else 1161 return; 1162 1163 if (!NT_SUCCESS(Status)) 1164 throw ntstatus_error(Status); 1165 } else 1166 throw last_error(GetLastError()); 1167 } catch (const exception& e) { 1168 error_message(hwnd, e.what()); 1169 } 1170 } 1171 1172 void CALLBACK StopBalanceW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 1173 try { 1174 win_handle h, token; 1175 TOKEN_PRIVILEGES tp; 1176 LUID luid; 1177 1178 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1179 throw last_error(GetLastError()); 1180 1181 if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) 1182 throw last_error(GetLastError()); 1183 1184 tp.PrivilegeCount = 1; 1185 tp.Privileges[0].Luid = luid; 1186 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1187 1188 if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) 1189 throw last_error(GetLastError()); 1190 1191 h = CreateFileW(lpszCmdLine, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 1192 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 1193 1194 if (h != INVALID_HANDLE_VALUE) { 1195 NTSTATUS Status; 1196 IO_STATUS_BLOCK iosb; 1197 btrfs_query_balance bqb2; 1198 1199 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_BALANCE, nullptr, 0, &bqb2, sizeof(btrfs_query_balance)); 1200 if (!NT_SUCCESS(Status)) 1201 throw ntstatus_error(Status); 1202 1203 if (bqb2.status & BTRFS_BALANCE_PAUSED || bqb2.status & BTRFS_BALANCE_RUNNING) 1204 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_STOP_BALANCE, nullptr, 0, nullptr, 0); 1205 else 1206 return; 1207 1208 if (!NT_SUCCESS(Status)) 1209 throw ntstatus_error(Status); 1210 } else 1211 throw last_error(GetLastError()); 1212 } catch (const exception& e) { 1213 error_message(hwnd, e.what()); 1214 } 1215 } 1216 1217 #ifdef __REACTOS__ 1218 } /* extern "C" */ 1219 #endif 1220