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 if (IsDlgButtonChecked(hwndDlg, IDC_PROFILES_RAID1C3) == BST_CHECKED) opts->profiles |= BLOCK_FLAG_RAID1C3; 387 if (IsDlgButtonChecked(hwndDlg, IDC_PROFILES_RAID1C4) == BST_CHECKED) opts->profiles |= BLOCK_FLAG_RAID1C4; 388 } 389 390 if (IsDlgButtonChecked(hwndDlg, IDC_DEVID) == BST_CHECKED) { 391 opts->flags |= BTRFS_BALANCE_OPTS_DEVID; 392 393 auto 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 opts->flags |= BTRFS_BALANCE_OPTS_CONVERT; 497 498 auto sel = SendMessageW(GetDlgItem(hwndDlg, IDC_CONVERT_COMBO), CB_GETCURSEL, 0, 0); 499 500 if (sel == CB_ERR || (unsigned int)sel >= sizeof(convtypes2) / sizeof(convtypes2[0])) 501 opts->flags &= ~BTRFS_BALANCE_OPTS_CONVERT; 502 else { 503 opts->convert = convtypes2[sel]; 504 505 if (IsDlgButtonChecked(hwndDlg, IDC_SOFT) == BST_CHECKED) opts->flags |= BTRFS_BALANCE_OPTS_SOFT; 506 } 507 } 508 509 EndDialog(hwndDlg, 0); 510 } 511 512 INT_PTR CALLBACK BtrfsBalance::BalanceOptsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 513 try { 514 switch (uMsg) { 515 case WM_INITDIALOG: 516 { 517 HWND devcb, convcb; 518 btrfs_device* bd; 519 btrfs_balance_opts* opts; 520 static int convtypes[] = { IDS_SINGLE2, IDS_DUP, IDS_RAID0, IDS_RAID1, IDS_RAID5, IDS_RAID1C3, IDS_RAID6, IDS_RAID10, IDS_RAID1C4, 0 }; 521 int i, num_devices = 0, num_writeable_devices = 0; 522 wstring s, u; 523 bool balance_started = balance_status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED); 524 525 switch (opts_type) { 526 case 1: 527 opts = balance_started ? &bqb.data_opts : &data_opts; 528 break; 529 530 case 2: 531 opts = balance_started ? &bqb.metadata_opts : &metadata_opts; 532 break; 533 534 case 3: 535 opts = balance_started ? &bqb.system_opts : &system_opts; 536 break; 537 538 default: 539 return true; 540 } 541 542 EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); 543 544 devcb = GetDlgItem(hwndDlg, IDC_DEVID_COMBO); 545 546 if (!load_string(module, IDS_DEVID_LIST, u)) 547 throw last_error(GetLastError()); 548 549 bd = devices; 550 while (true) { 551 wstring t, v; 552 553 if (bd->device_number == 0xffffffff) 554 s = wstring(bd->name, bd->namelen); 555 else if (bd->partition_number == 0) { 556 if (!load_string(module, IDS_DISK_NUM, v)) 557 throw last_error(GetLastError()); 558 559 wstring_sprintf(s, v, bd->device_number); 560 } else { 561 if (!load_string(module, IDS_DISK_PART_NUM, v)) 562 throw last_error(GetLastError()); 563 564 wstring_sprintf(s, v, bd->device_number, bd->partition_number); 565 } 566 567 wstring_sprintf(t, u, bd->dev_id, s.c_str()); 568 569 SendMessage(devcb, CB_ADDSTRING, 0, (LPARAM)t.c_str()); 570 571 if (opts->devid == bd->dev_id) 572 SendMessage(devcb, CB_SETCURSEL, num_devices, 0); 573 574 num_devices++; 575 576 if (!bd->readonly) 577 num_writeable_devices++; 578 579 if (bd->next_entry > 0) 580 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 581 else 582 break; 583 } 584 585 convcb = GetDlgItem(hwndDlg, IDC_CONVERT_COMBO); 586 587 if (num_writeable_devices == 0) 588 num_writeable_devices = num_devices; 589 590 i = 0; 591 while (convtypes[i] != 0) { 592 if (!load_string(module, convtypes[i], s)) 593 throw last_error(GetLastError()); 594 595 SendMessage(convcb, CB_ADDSTRING, 0, (LPARAM)s.c_str()); 596 597 if (opts->convert == convtypes2[i]) 598 SendMessage(convcb, CB_SETCURSEL, i, 0); 599 600 i++; 601 602 if (num_writeable_devices < 2 && i == 2) 603 break; 604 else if (num_writeable_devices < 3 && i == 4) 605 break; 606 else if (num_writeable_devices < 4 && i == 6) 607 break; 608 } 609 610 // profiles 611 612 CheckDlgButton(hwndDlg, IDC_PROFILES, opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? BST_CHECKED : BST_UNCHECKED); 613 CheckDlgButton(hwndDlg, IDC_PROFILES_SINGLE, opts->profiles & BLOCK_FLAG_SINGLE ? BST_CHECKED : BST_UNCHECKED); 614 CheckDlgButton(hwndDlg, IDC_PROFILES_DUP, opts->profiles & BLOCK_FLAG_DUPLICATE ? BST_CHECKED : BST_UNCHECKED); 615 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID0, opts->profiles & BLOCK_FLAG_RAID0 ? BST_CHECKED : BST_UNCHECKED); 616 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID1, opts->profiles & BLOCK_FLAG_RAID1 ? BST_CHECKED : BST_UNCHECKED); 617 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID10, opts->profiles & BLOCK_FLAG_RAID10 ? BST_CHECKED : BST_UNCHECKED); 618 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID5, opts->profiles & BLOCK_FLAG_RAID5 ? BST_CHECKED : BST_UNCHECKED); 619 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID6, opts->profiles & BLOCK_FLAG_RAID6 ? BST_CHECKED : BST_UNCHECKED); 620 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID1C3, opts->profiles & BLOCK_FLAG_RAID1C3 ? BST_CHECKED : BST_UNCHECKED); 621 CheckDlgButton(hwndDlg, IDC_PROFILES_RAID1C4, opts->profiles & BLOCK_FLAG_RAID1C4 ? 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_RAID1C3), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? true : false); 631 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID1C4), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_PROFILES ? true : false); 632 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES), balance_started ? false : true); 633 634 // usage 635 636 CheckDlgButton(hwndDlg, IDC_USAGE, opts->flags & BTRFS_BALANCE_OPTS_USAGE ? BST_CHECKED : BST_UNCHECKED); 637 638 s = to_wstring(opts->usage_start); 639 SetDlgItemTextW(hwndDlg, IDC_USAGE_START, s.c_str()); 640 SendMessageW(GetDlgItem(hwndDlg, IDC_USAGE_START_SPINNER), UDM_SETRANGE32, 0, 100); 641 642 s = to_wstring(opts->usage_end); 643 SetDlgItemTextW(hwndDlg, IDC_USAGE_END, s.c_str()); 644 SendMessageW(GetDlgItem(hwndDlg, IDC_USAGE_END_SPINNER), UDM_SETRANGE32, 0, 100); 645 646 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_START), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_USAGE ? true : false); 647 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_START_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_USAGE ? true : false); 648 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_END), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_USAGE ? true : false); 649 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_END_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_USAGE ? true : false); 650 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE), balance_started ? false : true); 651 652 // devid 653 654 if (num_devices < 2 || balance_started) 655 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVID), false); 656 657 CheckDlgButton(hwndDlg, IDC_DEVID, opts->flags & BTRFS_BALANCE_OPTS_DEVID ? BST_CHECKED : BST_UNCHECKED); 658 EnableWindow(devcb, (opts->flags & BTRFS_BALANCE_OPTS_DEVID && num_devices >= 2 && !balance_started) ? true : false); 659 660 // drange 661 662 CheckDlgButton(hwndDlg, IDC_DRANGE, opts->flags & BTRFS_BALANCE_OPTS_DRANGE ? BST_CHECKED : BST_UNCHECKED); 663 664 s = to_wstring(opts->drange_start); 665 SetDlgItemTextW(hwndDlg, IDC_DRANGE_START, s.c_str()); 666 667 s = to_wstring(opts->drange_end); 668 SetDlgItemTextW(hwndDlg, IDC_DRANGE_END, s.c_str()); 669 670 EnableWindow(GetDlgItem(hwndDlg, IDC_DRANGE_START), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_DRANGE ? true : false); 671 EnableWindow(GetDlgItem(hwndDlg, IDC_DRANGE_END), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_DRANGE ? true : false); 672 EnableWindow(GetDlgItem(hwndDlg, IDC_DRANGE), balance_started ? false : true); 673 674 // vrange 675 676 CheckDlgButton(hwndDlg, IDC_VRANGE, opts->flags & BTRFS_BALANCE_OPTS_VRANGE ? BST_CHECKED : BST_UNCHECKED); 677 678 s = to_wstring(opts->vrange_start); 679 SetDlgItemTextW(hwndDlg, IDC_VRANGE_START, s.c_str()); 680 681 s = to_wstring(opts->vrange_end); 682 SetDlgItemTextW(hwndDlg, IDC_VRANGE_END, s.c_str()); 683 684 EnableWindow(GetDlgItem(hwndDlg, IDC_VRANGE_START), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_VRANGE ? true : false); 685 EnableWindow(GetDlgItem(hwndDlg, IDC_VRANGE_END), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_VRANGE ? true : false); 686 EnableWindow(GetDlgItem(hwndDlg, IDC_VRANGE), balance_started ? false : true); 687 688 // limit 689 690 CheckDlgButton(hwndDlg, IDC_LIMIT, opts->flags & BTRFS_BALANCE_OPTS_LIMIT ? BST_CHECKED : BST_UNCHECKED); 691 692 s = to_wstring(opts->limit_start); 693 SetDlgItemTextW(hwndDlg, IDC_LIMIT_START, s.c_str()); 694 SendMessageW(GetDlgItem(hwndDlg, IDC_LIMIT_START_SPINNER), UDM_SETRANGE32, 0, 0x7fffffff); 695 696 s = to_wstring(opts->limit_end); 697 SetDlgItemTextW(hwndDlg, IDC_LIMIT_END, s.c_str()); 698 SendMessageW(GetDlgItem(hwndDlg, IDC_LIMIT_END_SPINNER), UDM_SETRANGE32, 0, 0x7fffffff); 699 700 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_START), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_LIMIT ? true : false); 701 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_START_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_LIMIT ? true : false); 702 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_END), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_LIMIT ? true : false); 703 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_END_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_LIMIT ? true : false); 704 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT), balance_started ? false : true); 705 706 // stripes 707 708 CheckDlgButton(hwndDlg, IDC_STRIPES, opts->flags & BTRFS_BALANCE_OPTS_STRIPES ? BST_CHECKED : BST_UNCHECKED); 709 710 s = to_wstring(opts->stripes_start); 711 SetDlgItemTextW(hwndDlg, IDC_STRIPES_START, s.c_str()); 712 SendMessageW(GetDlgItem(hwndDlg, IDC_STRIPES_START_SPINNER), UDM_SETRANGE32, 0, 0xffff); 713 714 s = to_wstring(opts->stripes_end); 715 SetDlgItemTextW(hwndDlg, IDC_STRIPES_END, s.c_str()); 716 SendMessageW(GetDlgItem(hwndDlg, IDC_STRIPES_END_SPINNER), UDM_SETRANGE32, 0, 0xffff); 717 718 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_START), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_STRIPES ? true : false); 719 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_START_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_STRIPES ? true : false); 720 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_END), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_STRIPES ? true : false); 721 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_END_SPINNER), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_STRIPES ? true : false); 722 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES), balance_started ? false : true); 723 724 // convert 725 726 CheckDlgButton(hwndDlg, IDC_CONVERT, opts->flags & BTRFS_BALANCE_OPTS_CONVERT ? BST_CHECKED : BST_UNCHECKED); 727 CheckDlgButton(hwndDlg, IDC_SOFT, opts->flags & BTRFS_BALANCE_OPTS_SOFT ? BST_CHECKED : BST_UNCHECKED); 728 729 EnableWindow(GetDlgItem(hwndDlg, IDC_SOFT), !balance_started && opts->flags & BTRFS_BALANCE_OPTS_CONVERT ? true : false); 730 EnableWindow(convcb, !balance_started && opts->flags & BTRFS_BALANCE_OPTS_CONVERT ? true : false); 731 EnableWindow(GetDlgItem(hwndDlg, IDC_CONVERT), balance_started ? false : true); 732 733 break; 734 } 735 736 case WM_COMMAND: 737 switch (HIWORD(wParam)) { 738 case BN_CLICKED: 739 switch (LOWORD(wParam)) { 740 case IDOK: 741 if (balance_status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED)) 742 EndDialog(hwndDlg, 0); 743 else 744 SaveBalanceOpts(hwndDlg); 745 return true; 746 747 case IDCANCEL: 748 EndDialog(hwndDlg, 0); 749 return true; 750 751 case IDC_PROFILES: { 752 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_PROFILES) == BST_CHECKED ? true : false; 753 754 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_SINGLE), enabled); 755 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_DUP), enabled); 756 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID0), enabled); 757 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID1), enabled); 758 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID10), enabled); 759 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID5), enabled); 760 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID6), enabled); 761 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID1C3), enabled); 762 EnableWindow(GetDlgItem(hwndDlg, IDC_PROFILES_RAID1C4), enabled); 763 break; 764 } 765 766 case IDC_USAGE: { 767 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_USAGE) == BST_CHECKED ? true : false; 768 769 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_START), enabled); 770 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_START_SPINNER), enabled); 771 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_END), enabled); 772 EnableWindow(GetDlgItem(hwndDlg, IDC_USAGE_END_SPINNER), enabled); 773 break; 774 } 775 776 case IDC_DEVID: { 777 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_DEVID) == BST_CHECKED ? true : false; 778 779 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVID_COMBO), enabled); 780 break; 781 } 782 783 case IDC_DRANGE: { 784 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_DRANGE) == BST_CHECKED ? true : false; 785 786 EnableWindow(GetDlgItem(hwndDlg, IDC_DRANGE_START), enabled); 787 EnableWindow(GetDlgItem(hwndDlg, IDC_DRANGE_END), enabled); 788 break; 789 } 790 791 case IDC_VRANGE: { 792 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_VRANGE) == BST_CHECKED ? true : false; 793 794 EnableWindow(GetDlgItem(hwndDlg, IDC_VRANGE_START), enabled); 795 EnableWindow(GetDlgItem(hwndDlg, IDC_VRANGE_END), enabled); 796 break; 797 } 798 799 case IDC_LIMIT: { 800 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_LIMIT) == BST_CHECKED ? true : false; 801 802 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_START), enabled); 803 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_START_SPINNER), enabled); 804 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_END), enabled); 805 EnableWindow(GetDlgItem(hwndDlg, IDC_LIMIT_END_SPINNER), enabled); 806 break; 807 } 808 809 case IDC_STRIPES: { 810 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_STRIPES) == BST_CHECKED ? true : false; 811 812 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_START), enabled); 813 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_START_SPINNER), enabled); 814 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_END), enabled); 815 EnableWindow(GetDlgItem(hwndDlg, IDC_STRIPES_END_SPINNER), enabled); 816 break; 817 } 818 819 case IDC_CONVERT: { 820 bool enabled = IsDlgButtonChecked(hwndDlg, IDC_CONVERT) == BST_CHECKED ? true : false; 821 822 EnableWindow(GetDlgItem(hwndDlg, IDC_CONVERT_COMBO), enabled); 823 EnableWindow(GetDlgItem(hwndDlg, IDC_SOFT), enabled); 824 break; 825 } 826 } 827 break; 828 } 829 break; 830 } 831 } catch (const exception& e) { 832 error_message(hwndDlg, e.what()); 833 } 834 835 return false; 836 } 837 838 static INT_PTR CALLBACK stub_BalanceOptsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 839 BtrfsBalance* bb; 840 841 if (uMsg == WM_INITDIALOG) { 842 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); 843 bb = (BtrfsBalance*)lParam; 844 } else { 845 bb = (BtrfsBalance*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 846 } 847 848 if (bb) 849 return bb->BalanceOptsDlgProc(hwndDlg, uMsg, wParam, lParam); 850 else 851 return false; 852 } 853 854 void BtrfsBalance::ShowBalanceOptions(HWND hwndDlg, uint8_t type) { 855 opts_type = type; 856 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_BALANCE_OPTIONS), hwndDlg, stub_BalanceOptsDlgProc, (LPARAM)this); 857 } 858 859 INT_PTR CALLBACK BtrfsBalance::BalanceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 860 try { 861 switch (uMsg) { 862 case WM_INITDIALOG: 863 { 864 EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); 865 866 RtlZeroMemory(&data_opts, sizeof(btrfs_balance_opts)); 867 RtlZeroMemory(&metadata_opts, sizeof(btrfs_balance_opts)); 868 RtlZeroMemory(&system_opts, sizeof(btrfs_balance_opts)); 869 870 removing = called_from_RemoveDevice; 871 shrinking = called_from_ShrinkDevice; 872 balance_status = (removing || shrinking) ? BTRFS_BALANCE_RUNNING : BTRFS_BALANCE_STOPPED; 873 cancelling = false; 874 RefreshBalanceDlg(hwndDlg, true); 875 876 if (readonly) { 877 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), false); 878 EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_BALANCE), false); 879 EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_BALANCE), false); 880 } 881 882 SendMessageW(GetDlgItem(hwndDlg, IDC_START_BALANCE), BCM_SETSHIELD, 0, true); 883 SendMessageW(GetDlgItem(hwndDlg, IDC_PAUSE_BALANCE), BCM_SETSHIELD, 0, true); 884 SendMessageW(GetDlgItem(hwndDlg, IDC_CANCEL_BALANCE), BCM_SETSHIELD, 0, true); 885 886 SetTimer(hwndDlg, 1, 1000, nullptr); 887 888 break; 889 } 890 891 case WM_COMMAND: 892 switch (HIWORD(wParam)) { 893 case BN_CLICKED: 894 switch (LOWORD(wParam)) { 895 case IDOK: 896 case IDCANCEL: 897 KillTimer(hwndDlg, 1); 898 EndDialog(hwndDlg, 0); 899 return true; 900 901 case IDC_DATA: 902 EnableWindow(GetDlgItem(hwndDlg, IDC_DATA_OPTIONS), IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED ? true : false); 903 904 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), !readonly && (IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED || 905 IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED || IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED) ? true: false); 906 return true; 907 908 case IDC_METADATA: 909 EnableWindow(GetDlgItem(hwndDlg, IDC_METADATA_OPTIONS), IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED ? true : false); 910 911 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), !readonly && (IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED || 912 IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED || IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED) ? true: false); 913 return true; 914 915 case IDC_SYSTEM: 916 EnableWindow(GetDlgItem(hwndDlg, IDC_SYSTEM_OPTIONS), IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED ? true : false); 917 918 EnableWindow(GetDlgItem(hwndDlg, IDC_START_BALANCE), !readonly && (IsDlgButtonChecked(hwndDlg, IDC_DATA) == BST_CHECKED || 919 IsDlgButtonChecked(hwndDlg, IDC_METADATA) == BST_CHECKED || IsDlgButtonChecked(hwndDlg, IDC_SYSTEM) == BST_CHECKED) ? true: false); 920 return true; 921 922 case IDC_DATA_OPTIONS: 923 ShowBalanceOptions(hwndDlg, 1); 924 return true; 925 926 case IDC_METADATA_OPTIONS: 927 ShowBalanceOptions(hwndDlg, 2); 928 return true; 929 930 case IDC_SYSTEM_OPTIONS: 931 ShowBalanceOptions(hwndDlg, 3); 932 return true; 933 934 case IDC_START_BALANCE: 935 StartBalance(hwndDlg); 936 return true; 937 938 case IDC_PAUSE_BALANCE: 939 PauseBalance(hwndDlg); 940 RefreshBalanceDlg(hwndDlg, false); 941 return true; 942 943 case IDC_CANCEL_BALANCE: 944 StopBalance(hwndDlg); 945 RefreshBalanceDlg(hwndDlg, false); 946 return true; 947 } 948 break; 949 } 950 break; 951 952 case WM_TIMER: 953 RefreshBalanceDlg(hwndDlg, false); 954 break; 955 } 956 } catch (const exception& e) { 957 error_message(hwndDlg, e.what()); 958 } 959 960 return false; 961 } 962 963 static INT_PTR CALLBACK stub_BalanceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 964 BtrfsBalance* bb; 965 966 if (uMsg == WM_INITDIALOG) { 967 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); 968 bb = (BtrfsBalance*)lParam; 969 } else { 970 bb = (BtrfsBalance*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 971 } 972 973 if (bb) 974 return bb->BalanceDlgProc(hwndDlg, uMsg, wParam, lParam); 975 else 976 return false; 977 } 978 979 void BtrfsBalance::ShowBalance(HWND hwndDlg) { 980 btrfs_device* bd; 981 982 if (devices) { 983 free(devices); 984 devices = nullptr; 985 } 986 987 { 988 win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 989 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 990 991 if (h != INVALID_HANDLE_VALUE) { 992 NTSTATUS Status; 993 IO_STATUS_BLOCK iosb; 994 ULONG devsize, i; 995 996 i = 0; 997 devsize = 1024; 998 999 devices = (btrfs_device*)malloc(devsize); 1000 1001 while (true) { 1002 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_DEVICES, nullptr, 0, devices, devsize); 1003 if (Status == STATUS_BUFFER_OVERFLOW) { 1004 if (i < 8) { 1005 devsize += 1024; 1006 1007 free(devices); 1008 devices = (btrfs_device*)malloc(devsize); 1009 1010 i++; 1011 } else 1012 return; 1013 } else 1014 break; 1015 } 1016 1017 if (!NT_SUCCESS(Status)) 1018 throw ntstatus_error(Status); 1019 } else 1020 throw last_error(GetLastError()); 1021 } 1022 1023 readonly = true; 1024 bd = devices; 1025 1026 while (true) { 1027 if (!bd->readonly) { 1028 readonly = false; 1029 break; 1030 } 1031 1032 if (bd->next_entry > 0) 1033 bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); 1034 else 1035 break; 1036 } 1037 1038 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_BALANCE), hwndDlg, stub_BalanceDlgProc, (LPARAM)this); 1039 } 1040 1041 static uint8_t from_hex_digit(WCHAR c) { 1042 if (c >= 'a' && c <= 'f') 1043 return (uint8_t)(c - 'a' + 0xa); 1044 else if (c >= 'A' && c <= 'F') 1045 return (uint8_t)(c - 'A' + 0xa); 1046 else 1047 return (uint8_t)(c - '0'); 1048 } 1049 1050 static void unserialize(void* data, ULONG len, WCHAR* s) { 1051 uint8_t* d; 1052 1053 d = (uint8_t*)data; 1054 1055 while (s[0] != 0 && s[1] != 0 && len > 0) { 1056 *d = (uint8_t)(from_hex_digit(s[0]) << 4) | from_hex_digit(s[1]); 1057 1058 s += 2; 1059 d++; 1060 len--; 1061 } 1062 } 1063 1064 #ifdef __REACTOS__ 1065 extern "C" { 1066 #endif 1067 1068 void CALLBACK StartBalanceW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 1069 try { 1070 WCHAR *s, *vol, *block; 1071 win_handle h, token; 1072 btrfs_start_balance bsb; 1073 TOKEN_PRIVILEGES tp; 1074 LUID luid; 1075 1076 s = wcsstr(lpszCmdLine, L" "); 1077 if (!s) 1078 return; 1079 1080 s[0] = 0; 1081 1082 vol = lpszCmdLine; 1083 block = &s[1]; 1084 1085 RtlZeroMemory(&bsb, sizeof(btrfs_start_balance)); 1086 unserialize(&bsb, sizeof(btrfs_start_balance), block); 1087 1088 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1089 throw last_error(GetLastError()); 1090 1091 if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) 1092 throw last_error(GetLastError()); 1093 1094 tp.PrivilegeCount = 1; 1095 tp.Privileges[0].Luid = luid; 1096 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1097 1098 if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) 1099 throw last_error(GetLastError()); 1100 1101 h = CreateFileW(vol, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 1102 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 1103 1104 if (h != INVALID_HANDLE_VALUE) { 1105 NTSTATUS Status; 1106 IO_STATUS_BLOCK iosb; 1107 1108 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_START_BALANCE, &bsb, sizeof(btrfs_start_balance), nullptr, 0); 1109 1110 if (Status == STATUS_DEVICE_NOT_READY) { 1111 btrfs_query_scrub bqs; 1112 NTSTATUS Status2; 1113 1114 Status2 = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_SCRUB, nullptr, 0, &bqs, sizeof(btrfs_query_scrub)); 1115 1116 if ((NT_SUCCESS(Status2) || Status2 == STATUS_BUFFER_OVERFLOW) && bqs.status != BTRFS_SCRUB_STOPPED) 1117 throw string_error(IDS_BALANCE_SCRUB_RUNNING); 1118 } 1119 1120 if (!NT_SUCCESS(Status)) 1121 throw ntstatus_error(Status); 1122 } else 1123 throw last_error(GetLastError()); 1124 } catch (const exception& e) { 1125 error_message(hwnd, e.what()); 1126 } 1127 } 1128 1129 void CALLBACK PauseBalanceW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 1130 try { 1131 win_handle h, token; 1132 TOKEN_PRIVILEGES tp; 1133 LUID luid; 1134 1135 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1136 throw last_error(GetLastError()); 1137 1138 if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) 1139 throw last_error(GetLastError()); 1140 1141 tp.PrivilegeCount = 1; 1142 tp.Privileges[0].Luid = luid; 1143 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1144 1145 if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) 1146 throw last_error(GetLastError()); 1147 1148 h = CreateFileW(lpszCmdLine, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 1149 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 1150 1151 if (h != INVALID_HANDLE_VALUE) { 1152 NTSTATUS Status; 1153 IO_STATUS_BLOCK iosb; 1154 btrfs_query_balance bqb2; 1155 1156 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_BALANCE, nullptr, 0, &bqb2, sizeof(btrfs_query_balance)); 1157 if (!NT_SUCCESS(Status)) 1158 throw ntstatus_error(Status); 1159 1160 if (bqb2.status & BTRFS_BALANCE_PAUSED) 1161 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESUME_BALANCE, nullptr, 0, nullptr, 0); 1162 else if (bqb2.status & BTRFS_BALANCE_RUNNING) 1163 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_PAUSE_BALANCE, nullptr, 0, nullptr, 0); 1164 else 1165 return; 1166 1167 if (!NT_SUCCESS(Status)) 1168 throw ntstatus_error(Status); 1169 } else 1170 throw last_error(GetLastError()); 1171 } catch (const exception& e) { 1172 error_message(hwnd, e.what()); 1173 } 1174 } 1175 1176 void CALLBACK StopBalanceW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 1177 try { 1178 win_handle h, token; 1179 TOKEN_PRIVILEGES tp; 1180 LUID luid; 1181 1182 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1183 throw last_error(GetLastError()); 1184 1185 if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) 1186 throw last_error(GetLastError()); 1187 1188 tp.PrivilegeCount = 1; 1189 tp.Privileges[0].Luid = luid; 1190 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1191 1192 if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) 1193 throw last_error(GetLastError()); 1194 1195 h = CreateFileW(lpszCmdLine, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, 1196 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr); 1197 1198 if (h != INVALID_HANDLE_VALUE) { 1199 NTSTATUS Status; 1200 IO_STATUS_BLOCK iosb; 1201 btrfs_query_balance bqb2; 1202 1203 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_BALANCE, nullptr, 0, &bqb2, sizeof(btrfs_query_balance)); 1204 if (!NT_SUCCESS(Status)) 1205 throw ntstatus_error(Status); 1206 1207 if (bqb2.status & BTRFS_BALANCE_PAUSED || bqb2.status & BTRFS_BALANCE_RUNNING) 1208 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_STOP_BALANCE, nullptr, 0, nullptr, 0); 1209 else 1210 return; 1211 1212 if (!NT_SUCCESS(Status)) 1213 throw ntstatus_error(Status); 1214 } else 1215 throw last_error(GetLastError()); 1216 } catch (const exception& e) { 1217 error_message(hwnd, e.what()); 1218 } 1219 } 1220 1221 #ifdef __REACTOS__ 1222 } /* extern "C" */ 1223 #endif 1224