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