1 /* Copyright (c) Mark Harmstone 2016-17
3 * This file is part of WinBtrfs.
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.
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.
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/>. */
22 #include "../btrfsioctl.h"
24 #include "btrfsioctl.h"
33 #define WIN32_NO_STATUS
37 #include <ndk/iofuncs.h>
38 #include <ndk/iotypes.h>
41 #define NO_SHLWAPI_STRFCNS
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
};
47 static WCHAR
hex_digit(uint8_t u
) {
48 if (u
>= 0xa && u
<= 0xf)
49 return (uint8_t)(u
- 0xa + 'a');
51 return (uint8_t)(u
+ '0');
54 static void serialize(void* data
, ULONG len
, WCHAR
* s
) {
60 *s
= hex_digit((uint8_t)(*d
>> 4)); s
++;
61 *s
= hex_digit(*d
& 0xf); s
++;
73 void BtrfsBalance::StartBalance(HWND hwndDlg
) {
75 WCHAR modfn
[MAX_PATH
], u
[600];
76 SHELLEXECUTEINFOW sei
;
77 btrfs_start_balance bsb
;
79 GetModuleFileNameW(module
, modfn
, sizeof(modfn
) / sizeof(WCHAR
));
82 t
= L
"\""s
+ modfn
+ L
"\",StartBalance "s
+ fn
+ L
" "s
;
84 t
= wstring(L
"\"") + modfn
+ wstring(L
"\",StartBalance ") + fn
+ wstring(L
" ");
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
));
91 if (IsDlgButtonChecked(hwndDlg
, IDC_DATA
) == BST_CHECKED
)
92 bsb
.opts
[0].flags
|= BTRFS_BALANCE_OPTS_ENABLED
;
94 bsb
.opts
[0].flags
&= ~BTRFS_BALANCE_OPTS_ENABLED
;
96 if (IsDlgButtonChecked(hwndDlg
, IDC_METADATA
) == BST_CHECKED
)
97 bsb
.opts
[1].flags
|= BTRFS_BALANCE_OPTS_ENABLED
;
99 bsb
.opts
[1].flags
&= ~BTRFS_BALANCE_OPTS_ENABLED
;
101 if (IsDlgButtonChecked(hwndDlg
, IDC_SYSTEM
) == BST_CHECKED
)
102 bsb
.opts
[2].flags
|= BTRFS_BALANCE_OPTS_ENABLED
;
104 bsb
.opts
[2].flags
&= ~BTRFS_BALANCE_OPTS_ENABLED
;
106 serialize(&bsb
, sizeof(btrfs_start_balance
), u
);
110 RtlZeroMemory(&sei
, sizeof(sei
));
112 sei
.cbSize
= sizeof(sei
);
114 sei
.lpVerb
= L
"runas";
115 sei
.lpFile
= L
"rundll32.exe";
116 sei
.lpParameters
= t
.c_str();
118 sei
.fMask
= SEE_MASK_NOCLOSEPROCESS
;
120 if (!ShellExecuteExW(&sei
))
121 throw last_error(GetLastError());
126 balance_status
= BTRFS_BALANCE_RUNNING
;
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);
138 EnableWindow(GetDlgItem(hwndDlg
, IDC_START_BALANCE
), false);
140 WaitForSingleObject(sei
.hProcess
, INFINITE
);
141 CloseHandle(sei
.hProcess
);
144 void BtrfsBalance::PauseBalance(HWND hwndDlg
) {
145 WCHAR modfn
[MAX_PATH
];
147 SHELLEXECUTEINFOW sei
;
149 GetModuleFileNameW(module
, modfn
, sizeof(modfn
) / sizeof(WCHAR
));
152 t
= L
"\""s
+ modfn
+ L
"\",PauseBalance " + fn
;
154 t
= wstring(L
"\"") + modfn
+ wstring(L
"\",PauseBalance ") + fn
;
157 RtlZeroMemory(&sei
, sizeof(sei
));
159 sei
.cbSize
= sizeof(sei
);
161 sei
.lpVerb
= L
"runas";
162 sei
.lpFile
= L
"rundll32.exe";
163 sei
.lpParameters
= t
.c_str();
165 sei
.fMask
= SEE_MASK_NOCLOSEPROCESS
;
167 if (!ShellExecuteExW(&sei
))
168 throw last_error(GetLastError());
170 WaitForSingleObject(sei
.hProcess
, INFINITE
);
171 CloseHandle(sei
.hProcess
);
174 void BtrfsBalance::StopBalance(HWND hwndDlg
) {
175 WCHAR modfn
[MAX_PATH
];
177 SHELLEXECUTEINFOW sei
;
179 GetModuleFileNameW(module
, modfn
, sizeof(modfn
) / sizeof(WCHAR
));
182 t
= L
"\""s
+ modfn
+ L
"\",StopBalance " + fn
;
184 t
= wstring(L
"\"") + modfn
+ wstring(L
"\",StopBalance ") + fn
;
187 RtlZeroMemory(&sei
, sizeof(sei
));
189 sei
.cbSize
= sizeof(sei
);
191 sei
.lpVerb
= L
"runas";
192 sei
.lpFile
= L
"rundll32.exe";
193 sei
.lpParameters
= t
.c_str();
195 sei
.fMask
= SEE_MASK_NOCLOSEPROCESS
;
197 if (!ShellExecuteExW(&sei
))
198 throw last_error(GetLastError());
202 WaitForSingleObject(sei
.hProcess
, INFINITE
);
203 CloseHandle(sei
.hProcess
);
206 void BtrfsBalance::RefreshBalanceDlg(HWND hwndDlg
, bool first
) {
207 bool balancing
= false;
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);
214 if (h
!= INVALID_HANDLE_VALUE
) {
216 IO_STATUS_BLOCK iosb
;
218 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_QUERY_BALANCE
, nullptr, 0, &bqb
, sizeof(btrfs_query_balance
));
220 if (!NT_SUCCESS(Status
))
221 throw ntstatus_error(Status
);
223 throw last_error(GetLastError());
227 bqb
.status
= BTRFS_BALANCE_STOPPED
;
229 balancing
= bqb
.status
& (BTRFS_BALANCE_RUNNING
| BTRFS_BALANCE_PAUSED
);
232 if (first
|| balance_status
!= BTRFS_BALANCE_STOPPED
) {
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);
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
);
248 SendMessage(GetDlgItem(hwndDlg
, IDC_BALANCE_PROGRESS
), PBM_SETPOS
, 0, 0);
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);
255 if (bqb
.status
& BTRFS_BALANCE_ERROR
) {
257 resid
= IDS_BALANCE_FAILED_REMOVAL
;
259 resid
= IDS_BALANCE_FAILED_SHRINK
;
261 resid
= IDS_BALANCE_FAILED
;
263 if (!load_string(module
, resid
, s
))
264 throw last_error(GetLastError());
266 wstring_sprintf(t
, s
, bqb
.error
, format_ntstatus(bqb
.error
).c_str());
268 SetDlgItemTextW(hwndDlg
, IDC_BALANCE_STATUS
, t
.c_str());
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
);
275 resid
= IDS_NO_BALANCE
;
277 if (!load_string(module
, resid
, s
))
278 throw last_error(GetLastError());
280 SetDlgItemTextW(hwndDlg
, IDC_BALANCE_STATUS
, s
.c_str());
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);
286 balance_status
= bqb
.status
;
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);
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
);
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);
309 EnableWindow(GetDlgItem(hwndDlg
, IDC_START_BALANCE
), false);
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);
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);
320 balance_status
= bqb
.status
;
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());
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
);
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());
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
);
341 if (!load_string(module
, balance_status
& BTRFS_BALANCE_PAUSED
? IDS_BALANCE_PAUSED
: IDS_BALANCE_RUNNING
, s
))
342 throw last_error(GetLastError());
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
);
351 SetDlgItemTextW(hwndDlg
, IDC_BALANCE_STATUS
, t
.c_str());
354 void BtrfsBalance::SaveBalanceOpts(HWND hwndDlg
) {
355 btrfs_balance_opts
* opts
;
363 opts
= &metadata_opts
;
374 RtlZeroMemory(opts
, sizeof(btrfs_balance_opts
));
376 if (IsDlgButtonChecked(hwndDlg
, IDC_PROFILES
) == BST_CHECKED
) {
377 opts
->flags
|= BTRFS_BALANCE_OPTS_PROFILES
;
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
;
388 if (IsDlgButtonChecked(hwndDlg
, IDC_DEVID
) == BST_CHECKED
) {
389 opts
->flags
|= BTRFS_BALANCE_OPTS_DEVID
;
391 auto sel
= SendMessageW(GetDlgItem(hwndDlg
, IDC_DEVID_COMBO
), CB_GETCURSEL
, 0, 0);
394 opts
->flags
&= ~BTRFS_BALANCE_OPTS_DEVID
;
396 btrfs_device
* bd
= devices
;
401 opts
->devid
= bd
->dev_id
;
407 if (bd
->next_entry
> 0)
408 bd
= (btrfs_device
*)((uint8_t*)bd
+ bd
->next_entry
);
413 if (opts
->devid
== 0)
414 opts
->flags
&= ~BTRFS_BALANCE_OPTS_DEVID
;
418 if (IsDlgButtonChecked(hwndDlg
, IDC_DRANGE
) == BST_CHECKED
) {
421 opts
->flags
|= BTRFS_BALANCE_OPTS_DRANGE
;
423 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_DRANGE_START
), s
, sizeof(s
) / sizeof(WCHAR
));
424 opts
->drange_start
= _wtoi64(s
);
426 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_DRANGE_END
), s
, sizeof(s
) / sizeof(WCHAR
));
427 opts
->drange_end
= _wtoi64(s
);
429 if (opts
->drange_end
< opts
->drange_start
)
430 throw string_error(IDS_DRANGE_END_BEFORE_START
);
433 if (IsDlgButtonChecked(hwndDlg
, IDC_VRANGE
) == BST_CHECKED
) {
436 opts
->flags
|= BTRFS_BALANCE_OPTS_VRANGE
;
438 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_VRANGE_START
), s
, sizeof(s
) / sizeof(WCHAR
));
439 opts
->vrange_start
= _wtoi64(s
);
441 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_VRANGE_END
), s
, sizeof(s
) / sizeof(WCHAR
));
442 opts
->vrange_end
= _wtoi64(s
);
444 if (opts
->vrange_end
< opts
->vrange_start
)
445 throw string_error(IDS_VRANGE_END_BEFORE_START
);
448 if (IsDlgButtonChecked(hwndDlg
, IDC_LIMIT
) == BST_CHECKED
) {
451 opts
->flags
|= BTRFS_BALANCE_OPTS_LIMIT
;
453 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_LIMIT_START
), s
, sizeof(s
) / sizeof(WCHAR
));
454 opts
->limit_start
= _wtoi64(s
);
456 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_LIMIT_END
), s
, sizeof(s
) / sizeof(WCHAR
));
457 opts
->limit_end
= _wtoi64(s
);
459 if (opts
->limit_end
< opts
->limit_start
)
460 throw string_error(IDS_LIMIT_END_BEFORE_START
);
463 if (IsDlgButtonChecked(hwndDlg
, IDC_STRIPES
) == BST_CHECKED
) {
466 opts
->flags
|= BTRFS_BALANCE_OPTS_STRIPES
;
468 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_STRIPES_START
), s
, sizeof(s
) / sizeof(WCHAR
));
469 opts
->stripes_start
= (uint8_t)_wtoi(s
);
471 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_STRIPES_END
), s
, sizeof(s
) / sizeof(WCHAR
));
472 opts
->stripes_end
= (uint8_t)_wtoi(s
);
474 if (opts
->stripes_end
< opts
->stripes_start
)
475 throw string_error(IDS_STRIPES_END_BEFORE_START
);
478 if (IsDlgButtonChecked(hwndDlg
, IDC_USAGE
) == BST_CHECKED
) {
481 opts
->flags
|= BTRFS_BALANCE_OPTS_USAGE
;
483 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_USAGE_START
), s
, sizeof(s
) / sizeof(WCHAR
));
484 opts
->usage_start
= (uint8_t)_wtoi(s
);
486 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_USAGE_END
), s
, sizeof(s
) / sizeof(WCHAR
));
487 opts
->usage_end
= (uint8_t)_wtoi(s
);
489 if (opts
->usage_end
< opts
->usage_start
)
490 throw string_error(IDS_USAGE_END_BEFORE_START
);
493 if (IsDlgButtonChecked(hwndDlg
, IDC_CONVERT
) == BST_CHECKED
) {
494 opts
->flags
|= BTRFS_BALANCE_OPTS_CONVERT
;
496 auto sel
= SendMessageW(GetDlgItem(hwndDlg
, IDC_CONVERT_COMBO
), CB_GETCURSEL
, 0, 0);
498 if (sel
== CB_ERR
|| (unsigned int)sel
>= sizeof(convtypes2
) / sizeof(convtypes2
[0]))
499 opts
->flags
&= ~BTRFS_BALANCE_OPTS_CONVERT
;
501 opts
->convert
= convtypes2
[sel
];
503 if (IsDlgButtonChecked(hwndDlg
, IDC_SOFT
) == BST_CHECKED
) opts
->flags
|= BTRFS_BALANCE_OPTS_SOFT
;
507 EndDialog(hwndDlg
, 0);
510 INT_PTR CALLBACK
BtrfsBalance::BalanceOptsDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
517 btrfs_balance_opts
* opts
;
518 static int convtypes
[] = { IDS_SINGLE2
, IDS_DUP
, IDS_RAID0
, IDS_RAID1
, IDS_RAID5
, IDS_RAID6
, IDS_RAID10
, 0 };
519 int i
, num_devices
= 0, num_writeable_devices
= 0;
521 bool balance_started
= balance_status
& (BTRFS_BALANCE_RUNNING
| BTRFS_BALANCE_PAUSED
);
525 opts
= balance_started
? &bqb
.data_opts
: &data_opts
;
529 opts
= balance_started
? &bqb
.metadata_opts
: &metadata_opts
;
533 opts
= balance_started
? &bqb
.system_opts
: &system_opts
;
540 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
542 devcb
= GetDlgItem(hwndDlg
, IDC_DEVID_COMBO
);
544 if (!load_string(module
, IDS_DEVID_LIST
, u
))
545 throw last_error(GetLastError());
551 if (bd
->device_number
== 0xffffffff)
552 s
= wstring(bd
->name
, bd
->namelen
);
553 else if (bd
->partition_number
== 0) {
554 if (!load_string(module
, IDS_DISK_NUM
, v
))
555 throw last_error(GetLastError());
557 wstring_sprintf(s
, v
, bd
->device_number
);
559 if (!load_string(module
, IDS_DISK_PART_NUM
, v
))
560 throw last_error(GetLastError());
562 wstring_sprintf(s
, v
, bd
->device_number
, bd
->partition_number
);
565 wstring_sprintf(t
, u
, bd
->dev_id
, s
.c_str());
567 SendMessage(devcb
, CB_ADDSTRING
, 0, (LPARAM
)t
.c_str());
569 if (opts
->devid
== bd
->dev_id
)
570 SendMessage(devcb
, CB_SETCURSEL
, num_devices
, 0);
575 num_writeable_devices
++;
577 if (bd
->next_entry
> 0)
578 bd
= (btrfs_device
*)((uint8_t*)bd
+ bd
->next_entry
);
583 convcb
= GetDlgItem(hwndDlg
, IDC_CONVERT_COMBO
);
585 if (num_writeable_devices
== 0)
586 num_writeable_devices
= num_devices
;
589 while (convtypes
[i
] != 0) {
590 if (!load_string(module
, convtypes
[i
], s
))
591 throw last_error(GetLastError());
593 SendMessage(convcb
, CB_ADDSTRING
, 0, (LPARAM
)s
.c_str());
595 if (opts
->convert
== convtypes2
[i
])
596 SendMessage(convcb
, CB_SETCURSEL
, i
, 0);
600 if (num_writeable_devices
< 2 && i
== 2)
602 else if (num_writeable_devices
< 3 && i
== 4)
604 else if (num_writeable_devices
< 4 && i
== 5)
610 CheckDlgButton(hwndDlg
, IDC_PROFILES
, opts
->flags
& BTRFS_BALANCE_OPTS_PROFILES
? BST_CHECKED
: BST_UNCHECKED
);
611 CheckDlgButton(hwndDlg
, IDC_PROFILES_SINGLE
, opts
->profiles
& BLOCK_FLAG_SINGLE
? BST_CHECKED
: BST_UNCHECKED
);
612 CheckDlgButton(hwndDlg
, IDC_PROFILES_DUP
, opts
->profiles
& BLOCK_FLAG_DUPLICATE
? BST_CHECKED
: BST_UNCHECKED
);
613 CheckDlgButton(hwndDlg
, IDC_PROFILES_RAID0
, opts
->profiles
& BLOCK_FLAG_RAID0
? BST_CHECKED
: BST_UNCHECKED
);
614 CheckDlgButton(hwndDlg
, IDC_PROFILES_RAID1
, opts
->profiles
& BLOCK_FLAG_RAID1
? BST_CHECKED
: BST_UNCHECKED
);
615 CheckDlgButton(hwndDlg
, IDC_PROFILES_RAID10
, opts
->profiles
& BLOCK_FLAG_RAID10
? BST_CHECKED
: BST_UNCHECKED
);
616 CheckDlgButton(hwndDlg
, IDC_PROFILES_RAID5
, opts
->profiles
& BLOCK_FLAG_RAID5
? BST_CHECKED
: BST_UNCHECKED
);
617 CheckDlgButton(hwndDlg
, IDC_PROFILES_RAID6
, opts
->profiles
& BLOCK_FLAG_RAID6
? BST_CHECKED
: BST_UNCHECKED
);
619 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_SINGLE
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_PROFILES
? true : false);
620 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_DUP
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_PROFILES
? true : false);
621 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_RAID0
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_PROFILES
? true : false);
622 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_RAID1
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_PROFILES
? true : false);
623 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_RAID10
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_PROFILES
? true : false);
624 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_RAID5
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_PROFILES
? true : false);
625 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_RAID6
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_PROFILES
? true : false);
626 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES
), balance_started
? false : true);
630 CheckDlgButton(hwndDlg
, IDC_USAGE
, opts
->flags
& BTRFS_BALANCE_OPTS_USAGE
? BST_CHECKED
: BST_UNCHECKED
);
632 s
= to_wstring(opts
->usage_start
);
633 SetDlgItemTextW(hwndDlg
, IDC_USAGE_START
, s
.c_str());
634 SendMessageW(GetDlgItem(hwndDlg
, IDC_USAGE_START_SPINNER
), UDM_SETRANGE32
, 0, 100);
636 s
= to_wstring(opts
->usage_end
);
637 SetDlgItemTextW(hwndDlg
, IDC_USAGE_END
, s
.c_str());
638 SendMessageW(GetDlgItem(hwndDlg
, IDC_USAGE_END_SPINNER
), UDM_SETRANGE32
, 0, 100);
640 EnableWindow(GetDlgItem(hwndDlg
, IDC_USAGE_START
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_USAGE
? true : false);
641 EnableWindow(GetDlgItem(hwndDlg
, IDC_USAGE_START_SPINNER
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_USAGE
? true : false);
642 EnableWindow(GetDlgItem(hwndDlg
, IDC_USAGE_END
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_USAGE
? true : false);
643 EnableWindow(GetDlgItem(hwndDlg
, IDC_USAGE_END_SPINNER
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_USAGE
? true : false);
644 EnableWindow(GetDlgItem(hwndDlg
, IDC_USAGE
), balance_started
? false : true);
648 if (num_devices
< 2 || balance_started
)
649 EnableWindow(GetDlgItem(hwndDlg
, IDC_DEVID
), false);
651 CheckDlgButton(hwndDlg
, IDC_DEVID
, opts
->flags
& BTRFS_BALANCE_OPTS_DEVID
? BST_CHECKED
: BST_UNCHECKED
);
652 EnableWindow(devcb
, (opts
->flags
& BTRFS_BALANCE_OPTS_DEVID
&& num_devices
>= 2 && !balance_started
) ? true : false);
656 CheckDlgButton(hwndDlg
, IDC_DRANGE
, opts
->flags
& BTRFS_BALANCE_OPTS_DRANGE
? BST_CHECKED
: BST_UNCHECKED
);
658 s
= to_wstring(opts
->drange_start
);
659 SetDlgItemTextW(hwndDlg
, IDC_DRANGE_START
, s
.c_str());
661 s
= to_wstring(opts
->drange_end
);
662 SetDlgItemTextW(hwndDlg
, IDC_DRANGE_END
, s
.c_str());
664 EnableWindow(GetDlgItem(hwndDlg
, IDC_DRANGE_START
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_DRANGE
? true : false);
665 EnableWindow(GetDlgItem(hwndDlg
, IDC_DRANGE_END
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_DRANGE
? true : false);
666 EnableWindow(GetDlgItem(hwndDlg
, IDC_DRANGE
), balance_started
? false : true);
670 CheckDlgButton(hwndDlg
, IDC_VRANGE
, opts
->flags
& BTRFS_BALANCE_OPTS_VRANGE
? BST_CHECKED
: BST_UNCHECKED
);
672 s
= to_wstring(opts
->vrange_start
);
673 SetDlgItemTextW(hwndDlg
, IDC_VRANGE_START
, s
.c_str());
675 s
= to_wstring(opts
->vrange_end
);
676 SetDlgItemTextW(hwndDlg
, IDC_VRANGE_END
, s
.c_str());
678 EnableWindow(GetDlgItem(hwndDlg
, IDC_VRANGE_START
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_VRANGE
? true : false);
679 EnableWindow(GetDlgItem(hwndDlg
, IDC_VRANGE_END
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_VRANGE
? true : false);
680 EnableWindow(GetDlgItem(hwndDlg
, IDC_VRANGE
), balance_started
? false : true);
684 CheckDlgButton(hwndDlg
, IDC_LIMIT
, opts
->flags
& BTRFS_BALANCE_OPTS_LIMIT
? BST_CHECKED
: BST_UNCHECKED
);
686 s
= to_wstring(opts
->limit_start
);
687 SetDlgItemTextW(hwndDlg
, IDC_LIMIT_START
, s
.c_str());
688 SendMessageW(GetDlgItem(hwndDlg
, IDC_LIMIT_START_SPINNER
), UDM_SETRANGE32
, 0, 0x7fffffff);
690 s
= to_wstring(opts
->limit_end
);
691 SetDlgItemTextW(hwndDlg
, IDC_LIMIT_END
, s
.c_str());
692 SendMessageW(GetDlgItem(hwndDlg
, IDC_LIMIT_END_SPINNER
), UDM_SETRANGE32
, 0, 0x7fffffff);
694 EnableWindow(GetDlgItem(hwndDlg
, IDC_LIMIT_START
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_LIMIT
? true : false);
695 EnableWindow(GetDlgItem(hwndDlg
, IDC_LIMIT_START_SPINNER
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_LIMIT
? true : false);
696 EnableWindow(GetDlgItem(hwndDlg
, IDC_LIMIT_END
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_LIMIT
? true : false);
697 EnableWindow(GetDlgItem(hwndDlg
, IDC_LIMIT_END_SPINNER
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_LIMIT
? true : false);
698 EnableWindow(GetDlgItem(hwndDlg
, IDC_LIMIT
), balance_started
? false : true);
702 CheckDlgButton(hwndDlg
, IDC_STRIPES
, opts
->flags
& BTRFS_BALANCE_OPTS_STRIPES
? BST_CHECKED
: BST_UNCHECKED
);
704 s
= to_wstring(opts
->stripes_start
);
705 SetDlgItemTextW(hwndDlg
, IDC_STRIPES_START
, s
.c_str());
706 SendMessageW(GetDlgItem(hwndDlg
, IDC_STRIPES_START_SPINNER
), UDM_SETRANGE32
, 0, 0xffff);
708 s
= to_wstring(opts
->stripes_end
);
709 SetDlgItemTextW(hwndDlg
, IDC_STRIPES_END
, s
.c_str());
710 SendMessageW(GetDlgItem(hwndDlg
, IDC_STRIPES_END_SPINNER
), UDM_SETRANGE32
, 0, 0xffff);
712 EnableWindow(GetDlgItem(hwndDlg
, IDC_STRIPES_START
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_STRIPES
? true : false);
713 EnableWindow(GetDlgItem(hwndDlg
, IDC_STRIPES_START_SPINNER
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_STRIPES
? true : false);
714 EnableWindow(GetDlgItem(hwndDlg
, IDC_STRIPES_END
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_STRIPES
? true : false);
715 EnableWindow(GetDlgItem(hwndDlg
, IDC_STRIPES_END_SPINNER
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_STRIPES
? true : false);
716 EnableWindow(GetDlgItem(hwndDlg
, IDC_STRIPES
), balance_started
? false : true);
720 CheckDlgButton(hwndDlg
, IDC_CONVERT
, opts
->flags
& BTRFS_BALANCE_OPTS_CONVERT
? BST_CHECKED
: BST_UNCHECKED
);
721 CheckDlgButton(hwndDlg
, IDC_SOFT
, opts
->flags
& BTRFS_BALANCE_OPTS_SOFT
? BST_CHECKED
: BST_UNCHECKED
);
723 EnableWindow(GetDlgItem(hwndDlg
, IDC_SOFT
), !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_CONVERT
? true : false);
724 EnableWindow(convcb
, !balance_started
&& opts
->flags
& BTRFS_BALANCE_OPTS_CONVERT
? true : false);
725 EnableWindow(GetDlgItem(hwndDlg
, IDC_CONVERT
), balance_started
? false : true);
731 switch (HIWORD(wParam
)) {
733 switch (LOWORD(wParam
)) {
735 if (balance_status
& (BTRFS_BALANCE_RUNNING
| BTRFS_BALANCE_PAUSED
))
736 EndDialog(hwndDlg
, 0);
738 SaveBalanceOpts(hwndDlg
);
742 EndDialog(hwndDlg
, 0);
746 bool enabled
= IsDlgButtonChecked(hwndDlg
, IDC_PROFILES
) == BST_CHECKED
? true : false;
748 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_SINGLE
), enabled
);
749 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_DUP
), enabled
);
750 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_RAID0
), enabled
);
751 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_RAID1
), enabled
);
752 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_RAID10
), enabled
);
753 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_RAID5
), enabled
);
754 EnableWindow(GetDlgItem(hwndDlg
, IDC_PROFILES_RAID6
), enabled
);
759 bool enabled
= IsDlgButtonChecked(hwndDlg
, IDC_USAGE
) == BST_CHECKED
? true : false;
761 EnableWindow(GetDlgItem(hwndDlg
, IDC_USAGE_START
), enabled
);
762 EnableWindow(GetDlgItem(hwndDlg
, IDC_USAGE_START_SPINNER
), enabled
);
763 EnableWindow(GetDlgItem(hwndDlg
, IDC_USAGE_END
), enabled
);
764 EnableWindow(GetDlgItem(hwndDlg
, IDC_USAGE_END_SPINNER
), enabled
);
769 bool enabled
= IsDlgButtonChecked(hwndDlg
, IDC_DEVID
) == BST_CHECKED
? true : false;
771 EnableWindow(GetDlgItem(hwndDlg
, IDC_DEVID_COMBO
), enabled
);
776 bool enabled
= IsDlgButtonChecked(hwndDlg
, IDC_DRANGE
) == BST_CHECKED
? true : false;
778 EnableWindow(GetDlgItem(hwndDlg
, IDC_DRANGE_START
), enabled
);
779 EnableWindow(GetDlgItem(hwndDlg
, IDC_DRANGE_END
), enabled
);
784 bool enabled
= IsDlgButtonChecked(hwndDlg
, IDC_VRANGE
) == BST_CHECKED
? true : false;
786 EnableWindow(GetDlgItem(hwndDlg
, IDC_VRANGE_START
), enabled
);
787 EnableWindow(GetDlgItem(hwndDlg
, IDC_VRANGE_END
), enabled
);
792 bool enabled
= IsDlgButtonChecked(hwndDlg
, IDC_LIMIT
) == BST_CHECKED
? true : false;
794 EnableWindow(GetDlgItem(hwndDlg
, IDC_LIMIT_START
), enabled
);
795 EnableWindow(GetDlgItem(hwndDlg
, IDC_LIMIT_START_SPINNER
), enabled
);
796 EnableWindow(GetDlgItem(hwndDlg
, IDC_LIMIT_END
), enabled
);
797 EnableWindow(GetDlgItem(hwndDlg
, IDC_LIMIT_END_SPINNER
), enabled
);
802 bool enabled
= IsDlgButtonChecked(hwndDlg
, IDC_STRIPES
) == BST_CHECKED
? true : false;
804 EnableWindow(GetDlgItem(hwndDlg
, IDC_STRIPES_START
), enabled
);
805 EnableWindow(GetDlgItem(hwndDlg
, IDC_STRIPES_START_SPINNER
), enabled
);
806 EnableWindow(GetDlgItem(hwndDlg
, IDC_STRIPES_END
), enabled
);
807 EnableWindow(GetDlgItem(hwndDlg
, IDC_STRIPES_END_SPINNER
), enabled
);
812 bool enabled
= IsDlgButtonChecked(hwndDlg
, IDC_CONVERT
) == BST_CHECKED
? true : false;
814 EnableWindow(GetDlgItem(hwndDlg
, IDC_CONVERT_COMBO
), enabled
);
815 EnableWindow(GetDlgItem(hwndDlg
, IDC_SOFT
), enabled
);
823 } catch (const exception
& e
) {
824 error_message(hwndDlg
, e
.what());
830 static INT_PTR CALLBACK
stub_BalanceOptsDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
833 if (uMsg
== WM_INITDIALOG
) {
834 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
835 bb
= (BtrfsBalance
*)lParam
;
837 bb
= (BtrfsBalance
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
841 return bb
->BalanceOptsDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
846 void BtrfsBalance::ShowBalanceOptions(HWND hwndDlg
, uint8_t type
) {
848 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_BALANCE_OPTIONS
), hwndDlg
, stub_BalanceOptsDlgProc
, (LPARAM
)this);
851 INT_PTR CALLBACK
BtrfsBalance::BalanceDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
856 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
858 RtlZeroMemory(&data_opts
, sizeof(btrfs_balance_opts
));
859 RtlZeroMemory(&metadata_opts
, sizeof(btrfs_balance_opts
));
860 RtlZeroMemory(&system_opts
, sizeof(btrfs_balance_opts
));
862 removing
= called_from_RemoveDevice
;
863 shrinking
= called_from_ShrinkDevice
;
864 balance_status
= (removing
|| shrinking
) ? BTRFS_BALANCE_RUNNING
: BTRFS_BALANCE_STOPPED
;
866 RefreshBalanceDlg(hwndDlg
, true);
869 EnableWindow(GetDlgItem(hwndDlg
, IDC_START_BALANCE
), false);
870 EnableWindow(GetDlgItem(hwndDlg
, IDC_PAUSE_BALANCE
), false);
871 EnableWindow(GetDlgItem(hwndDlg
, IDC_CANCEL_BALANCE
), false);
874 SendMessageW(GetDlgItem(hwndDlg
, IDC_START_BALANCE
), BCM_SETSHIELD
, 0, true);
875 SendMessageW(GetDlgItem(hwndDlg
, IDC_PAUSE_BALANCE
), BCM_SETSHIELD
, 0, true);
876 SendMessageW(GetDlgItem(hwndDlg
, IDC_CANCEL_BALANCE
), BCM_SETSHIELD
, 0, true);
878 SetTimer(hwndDlg
, 1, 1000, nullptr);
884 switch (HIWORD(wParam
)) {
886 switch (LOWORD(wParam
)) {
889 KillTimer(hwndDlg
, 1);
890 EndDialog(hwndDlg
, 0);
894 EnableWindow(GetDlgItem(hwndDlg
, IDC_DATA_OPTIONS
), IsDlgButtonChecked(hwndDlg
, IDC_DATA
) == BST_CHECKED
? true : false);
896 EnableWindow(GetDlgItem(hwndDlg
, IDC_START_BALANCE
), !readonly
&& (IsDlgButtonChecked(hwndDlg
, IDC_DATA
) == BST_CHECKED
||
897 IsDlgButtonChecked(hwndDlg
, IDC_METADATA
) == BST_CHECKED
|| IsDlgButtonChecked(hwndDlg
, IDC_SYSTEM
) == BST_CHECKED
) ? true: false);
901 EnableWindow(GetDlgItem(hwndDlg
, IDC_METADATA_OPTIONS
), IsDlgButtonChecked(hwndDlg
, IDC_METADATA
) == BST_CHECKED
? true : false);
903 EnableWindow(GetDlgItem(hwndDlg
, IDC_START_BALANCE
), !readonly
&& (IsDlgButtonChecked(hwndDlg
, IDC_DATA
) == BST_CHECKED
||
904 IsDlgButtonChecked(hwndDlg
, IDC_METADATA
) == BST_CHECKED
|| IsDlgButtonChecked(hwndDlg
, IDC_SYSTEM
) == BST_CHECKED
) ? true: false);
908 EnableWindow(GetDlgItem(hwndDlg
, IDC_SYSTEM_OPTIONS
), IsDlgButtonChecked(hwndDlg
, IDC_SYSTEM
) == BST_CHECKED
? true : false);
910 EnableWindow(GetDlgItem(hwndDlg
, IDC_START_BALANCE
), !readonly
&& (IsDlgButtonChecked(hwndDlg
, IDC_DATA
) == BST_CHECKED
||
911 IsDlgButtonChecked(hwndDlg
, IDC_METADATA
) == BST_CHECKED
|| IsDlgButtonChecked(hwndDlg
, IDC_SYSTEM
) == BST_CHECKED
) ? true: false);
914 case IDC_DATA_OPTIONS
:
915 ShowBalanceOptions(hwndDlg
, 1);
918 case IDC_METADATA_OPTIONS
:
919 ShowBalanceOptions(hwndDlg
, 2);
922 case IDC_SYSTEM_OPTIONS
:
923 ShowBalanceOptions(hwndDlg
, 3);
926 case IDC_START_BALANCE
:
927 StartBalance(hwndDlg
);
930 case IDC_PAUSE_BALANCE
:
931 PauseBalance(hwndDlg
);
932 RefreshBalanceDlg(hwndDlg
, false);
935 case IDC_CANCEL_BALANCE
:
936 StopBalance(hwndDlg
);
937 RefreshBalanceDlg(hwndDlg
, false);
945 RefreshBalanceDlg(hwndDlg
, false);
948 } catch (const exception
& e
) {
949 error_message(hwndDlg
, e
.what());
955 static INT_PTR CALLBACK
stub_BalanceDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
958 if (uMsg
== WM_INITDIALOG
) {
959 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
960 bb
= (BtrfsBalance
*)lParam
;
962 bb
= (BtrfsBalance
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
966 return bb
->BalanceDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
971 void BtrfsBalance::ShowBalance(HWND hwndDlg
) {
980 win_handle h
= CreateFileW(fn
.c_str(), FILE_TRAVERSE
| FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr,
981 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, nullptr);
983 if (h
!= INVALID_HANDLE_VALUE
) {
985 IO_STATUS_BLOCK iosb
;
991 devices
= (btrfs_device
*)malloc(devsize
);
994 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_GET_DEVICES
, nullptr, 0, devices
, devsize
);
995 if (Status
== STATUS_BUFFER_OVERFLOW
) {
1000 devices
= (btrfs_device
*)malloc(devsize
);
1009 if (!NT_SUCCESS(Status
))
1010 throw ntstatus_error(Status
);
1012 throw last_error(GetLastError());
1019 if (!bd
->readonly
) {
1024 if (bd
->next_entry
> 0)
1025 bd
= (btrfs_device
*)((uint8_t*)bd
+ bd
->next_entry
);
1030 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_BALANCE
), hwndDlg
, stub_BalanceDlgProc
, (LPARAM
)this);
1033 static uint8_t from_hex_digit(WCHAR c
) {
1034 if (c
>= 'a' && c
<= 'f')
1035 return (uint8_t)(c
- 'a' + 0xa);
1036 else if (c
>= 'A' && c
<= 'F')
1037 return (uint8_t)(c
- 'A' + 0xa);
1039 return (uint8_t)(c
- '0');
1042 static void unserialize(void* data
, ULONG len
, WCHAR
* s
) {
1047 while (s
[0] != 0 && s
[1] != 0 && len
> 0) {
1048 *d
= (uint8_t)(from_hex_digit(s
[0]) << 4) | from_hex_digit(s
[1]);
1060 void CALLBACK
StartBalanceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
1062 WCHAR
*s
, *vol
, *block
;
1063 win_handle h
, token
;
1064 btrfs_start_balance bsb
;
1065 TOKEN_PRIVILEGES tp
;
1068 s
= wcsstr(lpszCmdLine
, L
" ");
1077 RtlZeroMemory(&bsb
, sizeof(btrfs_start_balance
));
1078 unserialize(&bsb
, sizeof(btrfs_start_balance
), block
);
1080 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
))
1081 throw last_error(GetLastError());
1083 if (!LookupPrivilegeValueW(nullptr, L
"SeManageVolumePrivilege", &luid
))
1084 throw last_error(GetLastError());
1086 tp
.PrivilegeCount
= 1;
1087 tp
.Privileges
[0].Luid
= luid
;
1088 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
1090 if (!AdjustTokenPrivileges(token
, false, &tp
, sizeof(TOKEN_PRIVILEGES
), nullptr, nullptr))
1091 throw last_error(GetLastError());
1093 h
= CreateFileW(vol
, FILE_TRAVERSE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr,
1094 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, nullptr);
1096 if (h
!= INVALID_HANDLE_VALUE
) {
1098 IO_STATUS_BLOCK iosb
;
1100 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_START_BALANCE
, &bsb
, sizeof(btrfs_start_balance
), nullptr, 0);
1102 if (Status
== STATUS_DEVICE_NOT_READY
) {
1103 btrfs_query_scrub bqs
;
1106 Status2
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_QUERY_SCRUB
, nullptr, 0, &bqs
, sizeof(btrfs_query_scrub
));
1108 if ((NT_SUCCESS(Status2
) || Status2
== STATUS_BUFFER_OVERFLOW
) && bqs
.status
!= BTRFS_SCRUB_STOPPED
)
1109 throw string_error(IDS_BALANCE_SCRUB_RUNNING
);
1112 if (!NT_SUCCESS(Status
))
1113 throw ntstatus_error(Status
);
1115 throw last_error(GetLastError());
1116 } catch (const exception
& e
) {
1117 error_message(hwnd
, e
.what());
1121 void CALLBACK
PauseBalanceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
1123 win_handle h
, token
;
1124 TOKEN_PRIVILEGES tp
;
1127 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
))
1128 throw last_error(GetLastError());
1130 if (!LookupPrivilegeValueW(nullptr, L
"SeManageVolumePrivilege", &luid
))
1131 throw last_error(GetLastError());
1133 tp
.PrivilegeCount
= 1;
1134 tp
.Privileges
[0].Luid
= luid
;
1135 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
1137 if (!AdjustTokenPrivileges(token
, false, &tp
, sizeof(TOKEN_PRIVILEGES
), nullptr, nullptr))
1138 throw last_error(GetLastError());
1140 h
= CreateFileW(lpszCmdLine
, FILE_TRAVERSE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr,
1141 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, nullptr);
1143 if (h
!= INVALID_HANDLE_VALUE
) {
1145 IO_STATUS_BLOCK iosb
;
1146 btrfs_query_balance bqb2
;
1148 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_QUERY_BALANCE
, nullptr, 0, &bqb2
, sizeof(btrfs_query_balance
));
1149 if (!NT_SUCCESS(Status
))
1150 throw ntstatus_error(Status
);
1152 if (bqb2
.status
& BTRFS_BALANCE_PAUSED
)
1153 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_RESUME_BALANCE
, nullptr, 0, nullptr, 0);
1154 else if (bqb2
.status
& BTRFS_BALANCE_RUNNING
)
1155 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_PAUSE_BALANCE
, nullptr, 0, nullptr, 0);
1159 if (!NT_SUCCESS(Status
))
1160 throw ntstatus_error(Status
);
1162 throw last_error(GetLastError());
1163 } catch (const exception
& e
) {
1164 error_message(hwnd
, e
.what());
1168 void CALLBACK
StopBalanceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
1170 win_handle h
, token
;
1171 TOKEN_PRIVILEGES tp
;
1174 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
))
1175 throw last_error(GetLastError());
1177 if (!LookupPrivilegeValueW(nullptr, L
"SeManageVolumePrivilege", &luid
))
1178 throw last_error(GetLastError());
1180 tp
.PrivilegeCount
= 1;
1181 tp
.Privileges
[0].Luid
= luid
;
1182 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
1184 if (!AdjustTokenPrivileges(token
, false, &tp
, sizeof(TOKEN_PRIVILEGES
), nullptr, nullptr))
1185 throw last_error(GetLastError());
1187 h
= CreateFileW(lpszCmdLine
, FILE_TRAVERSE
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr,
1188 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, nullptr);
1190 if (h
!= INVALID_HANDLE_VALUE
) {
1192 IO_STATUS_BLOCK iosb
;
1193 btrfs_query_balance bqb2
;
1195 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_QUERY_BALANCE
, nullptr, 0, &bqb2
, sizeof(btrfs_query_balance
));
1196 if (!NT_SUCCESS(Status
))
1197 throw ntstatus_error(Status
);
1199 if (bqb2
.status
& BTRFS_BALANCE_PAUSED
|| bqb2
.status
& BTRFS_BALANCE_RUNNING
)
1200 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_STOP_BALANCE
, nullptr, 0, nullptr, 0);
1204 if (!NT_SUCCESS(Status
))
1205 throw ntstatus_error(Status
);
1207 throw last_error(GetLastError());
1208 } catch (const exception
& e
) {
1209 error_message(hwnd
, e
.what());