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 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 u
) {
48 if (u
>= 0xa && u
<= 0xf)
54 static void serialize(void* data
, ULONG len
, WCHAR
* s
) {
60 *s
= hex_digit(*d
>> 4); s
++;
61 *s
= hex_digit(*d
& 0xf); s
++;
73 void BtrfsBalance::StartBalance(HWND hwndDlg
) {
74 WCHAR t
[MAX_PATH
+ 600], u
[600];
75 SHELLEXECUTEINFOW sei
;
76 btrfs_start_balance bsb
;
79 GetModuleFileNameW(module
, t
+ 1, (sizeof(t
) / sizeof(WCHAR
)) - 1);
80 wcscat(t
, L
"\",StartBalance ");
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
));
88 if (IsDlgButtonChecked(hwndDlg
, IDC_DATA
) == BST_CHECKED
)
89 bsb
.opts
[0].flags
|= BTRFS_BALANCE_OPTS_ENABLED
;
91 bsb
.opts
[0].flags
&= ~BTRFS_BALANCE_OPTS_ENABLED
;
93 if (IsDlgButtonChecked(hwndDlg
, IDC_METADATA
) == BST_CHECKED
)
94 bsb
.opts
[1].flags
|= BTRFS_BALANCE_OPTS_ENABLED
;
96 bsb
.opts
[1].flags
&= ~BTRFS_BALANCE_OPTS_ENABLED
;
98 if (IsDlgButtonChecked(hwndDlg
, IDC_SYSTEM
) == BST_CHECKED
)
99 bsb
.opts
[2].flags
|= BTRFS_BALANCE_OPTS_ENABLED
;
101 bsb
.opts
[2].flags
&= ~BTRFS_BALANCE_OPTS_ENABLED
;
103 serialize(&bsb
, sizeof(btrfs_start_balance
), u
);
106 RtlZeroMemory(&sei
, sizeof(sei
));
108 sei
.cbSize
= sizeof(sei
);
110 sei
.lpVerb
= L
"runas";
111 sei
.lpFile
= L
"rundll32.exe";
112 sei
.lpParameters
= t
;
114 sei
.fMask
= SEE_MASK_NOCLOSEPROCESS
;
116 if (!ShellExecuteExW(&sei
)) {
117 ShowError(hwndDlg
, GetLastError());
124 balance_status
= BTRFS_BALANCE_RUNNING
;
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
);
136 EnableWindow(GetDlgItem(hwndDlg
, IDC_START_BALANCE
), FALSE
);
138 WaitForSingleObject(sei
.hProcess
, INFINITE
);
139 CloseHandle(sei
.hProcess
);
142 void BtrfsBalance::PauseBalance(HWND hwndDlg
) {
143 WCHAR t
[MAX_PATH
+ 100];
144 SHELLEXECUTEINFOW sei
;
147 GetModuleFileNameW(module
, t
+ 1, (sizeof(t
) / sizeof(WCHAR
)) - 1);
148 wcscat(t
, L
"\",PauseBalance ");
151 RtlZeroMemory(&sei
, sizeof(sei
));
153 sei
.cbSize
= sizeof(sei
);
155 sei
.lpVerb
= L
"runas";
156 sei
.lpFile
= L
"rundll32.exe";
157 sei
.lpParameters
= t
;
159 sei
.fMask
= SEE_MASK_NOCLOSEPROCESS
;
161 if (!ShellExecuteExW(&sei
)) {
162 ShowError(hwndDlg
, GetLastError());
166 WaitForSingleObject(sei
.hProcess
, INFINITE
);
167 CloseHandle(sei
.hProcess
);
170 void BtrfsBalance::StopBalance(HWND hwndDlg
) {
171 WCHAR t
[MAX_PATH
+ 100];
172 SHELLEXECUTEINFOW sei
;
175 GetModuleFileNameW(module
, t
+ 1, (sizeof(t
) / sizeof(WCHAR
)) - 1);
176 wcscat(t
, L
"\",StopBalance ");
179 RtlZeroMemory(&sei
, sizeof(sei
));
181 sei
.cbSize
= sizeof(sei
);
183 sei
.lpVerb
= L
"runas";
184 sei
.lpFile
= L
"rundll32.exe";
185 sei
.lpParameters
= t
;
187 sei
.fMask
= SEE_MASK_NOCLOSEPROCESS
;
189 if (!ShellExecuteExW(&sei
)) {
190 ShowError(hwndDlg
, GetLastError());
196 WaitForSingleObject(sei
.hProcess
, INFINITE
);
197 CloseHandle(sei
.hProcess
);
200 void BtrfsBalance::RefreshBalanceDlg(HWND hwndDlg
, BOOL first
) {
202 BOOL balancing
= FALSE
;
203 WCHAR s
[255], t
[255];
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
) {
209 IO_STATUS_BLOCK iosb
;
211 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_QUERY_BALANCE
, NULL
, 0, &bqb
, sizeof(btrfs_query_balance
));
213 if (!NT_SUCCESS(Status
)) {
214 ShowNtStatusError(hwndDlg
, Status
);
221 ShowError(hwndDlg
, GetLastError());
226 bqb
.status
= BTRFS_BALANCE_STOPPED
;
228 balancing
= bqb
.status
& (BTRFS_BALANCE_RUNNING
| BTRFS_BALANCE_PAUSED
);
231 if (first
|| balance_status
!= BTRFS_BALANCE_STOPPED
) {
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
);
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
);
247 SendMessage(GetDlgItem(hwndDlg
, IDC_BALANCE_PROGRESS
), PBM_SETPOS
, 0, 0);
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
);
254 if (bqb
.status
& BTRFS_BALANCE_ERROR
) {
256 resid
= IDS_BALANCE_FAILED_REMOVAL
;
258 resid
= IDS_BALANCE_FAILED_SHRINK
;
260 resid
= IDS_BALANCE_FAILED
;
262 if (!LoadStringW(module
, resid
, s
, sizeof(s
) / sizeof(WCHAR
))) {
263 ShowError(hwndDlg
, GetLastError());
267 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), s
, bqb
.error
, format_ntstatus(bqb
.error
).c_str()) == STRSAFE_E_INSUFFICIENT_BUFFER
)
270 SetDlgItemTextW(hwndDlg
, IDC_BALANCE_STATUS
, t
);
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
);
277 resid
= IDS_NO_BALANCE
;
279 if (!LoadStringW(module
, resid
, s
, sizeof(s
) / sizeof(WCHAR
))) {
280 ShowError(hwndDlg
, GetLastError());
284 SetDlgItemTextW(hwndDlg
, IDC_BALANCE_STATUS
, s
);
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
);
290 balance_status
= bqb
.status
;
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
);
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
);
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
);
313 EnableWindow(GetDlgItem(hwndDlg
, IDC_START_BALANCE
), FALSE
);
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);
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);
324 balance_status
= bqb
.status
;
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());
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
)
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());
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
)
351 if (!LoadStringW(module
, balance_status
& BTRFS_BALANCE_PAUSED
? IDS_BALANCE_PAUSED
: IDS_BALANCE_RUNNING
, s
, sizeof(s
) / sizeof(WCHAR
))) {
352 ShowError(hwndDlg
, GetLastError());
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
)
364 SetDlgItemTextW(hwndDlg
, IDC_BALANCE_STATUS
, t
);
367 void BtrfsBalance::SaveBalanceOpts(HWND hwndDlg
) {
368 btrfs_balance_opts
* opts
;
376 opts
= &metadata_opts
;
387 RtlZeroMemory(opts
, sizeof(btrfs_balance_opts
));
389 if (IsDlgButtonChecked(hwndDlg
, IDC_PROFILES
) == BST_CHECKED
) {
390 opts
->flags
|= BTRFS_BALANCE_OPTS_PROFILES
;
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
;
401 if (IsDlgButtonChecked(hwndDlg
, IDC_DEVID
) == BST_CHECKED
) {
404 opts
->flags
|= BTRFS_BALANCE_OPTS_DEVID
;
406 sel
= SendMessageW(GetDlgItem(hwndDlg
, IDC_DEVID_COMBO
), CB_GETCURSEL
, 0, 0);
409 opts
->flags
&= ~BTRFS_BALANCE_OPTS_DEVID
;
411 btrfs_device
* bd
= devices
;
416 opts
->devid
= bd
->dev_id
;
422 if (bd
->next_entry
> 0)
423 bd
= (btrfs_device
*)((UINT8
*)bd
+ bd
->next_entry
);
428 if (opts
->devid
== 0)
429 opts
->flags
&= ~BTRFS_BALANCE_OPTS_DEVID
;
433 if (IsDlgButtonChecked(hwndDlg
, IDC_DRANGE
) == BST_CHECKED
) {
436 opts
->flags
|= BTRFS_BALANCE_OPTS_DRANGE
;
438 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_DRANGE_START
), s
, sizeof(s
) / sizeof(WCHAR
));
439 opts
->drange_start
= _wtoi64(s
);
441 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_DRANGE_END
), s
, sizeof(s
) / sizeof(WCHAR
));
442 opts
->drange_end
= _wtoi64(s
);
444 if (opts
->drange_end
< opts
->drange_start
) {
445 ShowStringError(hwndDlg
, IDS_DRANGE_END_BEFORE_START
);
450 if (IsDlgButtonChecked(hwndDlg
, IDC_VRANGE
) == BST_CHECKED
) {
453 opts
->flags
|= BTRFS_BALANCE_OPTS_VRANGE
;
455 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_VRANGE_START
), s
, sizeof(s
) / sizeof(WCHAR
));
456 opts
->vrange_start
= _wtoi64(s
);
458 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_VRANGE_END
), s
, sizeof(s
) / sizeof(WCHAR
));
459 opts
->vrange_end
= _wtoi64(s
);
461 if (opts
->vrange_end
< opts
->vrange_start
) {
462 ShowStringError(hwndDlg
, IDS_VRANGE_END_BEFORE_START
);
467 if (IsDlgButtonChecked(hwndDlg
, IDC_LIMIT
) == BST_CHECKED
) {
470 opts
->flags
|= BTRFS_BALANCE_OPTS_LIMIT
;
472 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_LIMIT_START
), s
, sizeof(s
) / sizeof(WCHAR
));
473 opts
->limit_start
= _wtoi64(s
);
475 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_LIMIT_END
), s
, sizeof(s
) / sizeof(WCHAR
));
476 opts
->limit_end
= _wtoi64(s
);
478 if (opts
->limit_end
< opts
->limit_start
) {
479 ShowStringError(hwndDlg
, IDS_LIMIT_END_BEFORE_START
);
484 if (IsDlgButtonChecked(hwndDlg
, IDC_STRIPES
) == BST_CHECKED
) {
487 opts
->flags
|= BTRFS_BALANCE_OPTS_STRIPES
;
489 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_STRIPES_START
), s
, sizeof(s
) / sizeof(WCHAR
));
490 opts
->stripes_start
= _wtoi(s
);
492 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_STRIPES_END
), s
, sizeof(s
) / sizeof(WCHAR
));
493 opts
->stripes_end
= _wtoi(s
);
495 if (opts
->stripes_end
< opts
->stripes_start
) {
496 ShowStringError(hwndDlg
, IDS_STRIPES_END_BEFORE_START
);
501 if (IsDlgButtonChecked(hwndDlg
, IDC_USAGE
) == BST_CHECKED
) {
504 opts
->flags
|= BTRFS_BALANCE_OPTS_USAGE
;
506 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_USAGE_START
), s
, sizeof(s
) / sizeof(WCHAR
));
507 opts
->usage_start
= _wtoi(s
);
509 GetWindowTextW(GetDlgItem(hwndDlg
, IDC_USAGE_END
), s
, sizeof(s
) / sizeof(WCHAR
));
510 opts
->usage_end
= _wtoi(s
);
512 if (opts
->usage_end
< opts
->usage_start
) {
513 ShowStringError(hwndDlg
, IDS_USAGE_END_BEFORE_START
);
518 if (IsDlgButtonChecked(hwndDlg
, IDC_CONVERT
) == BST_CHECKED
) {
521 opts
->flags
|= BTRFS_BALANCE_OPTS_CONVERT
;
523 sel
= SendMessageW(GetDlgItem(hwndDlg
, IDC_CONVERT_COMBO
), CB_GETCURSEL
, 0, 0);
525 if (sel
== CB_ERR
|| (unsigned int)sel
>= sizeof(convtypes2
) / sizeof(convtypes2
[0]))
526 opts
->flags
&= ~BTRFS_BALANCE_OPTS_CONVERT
;
528 opts
->convert
= convtypes2
[sel
];
530 if (IsDlgButtonChecked(hwndDlg
, IDC_SOFT
) == BST_CHECKED
) opts
->flags
|= BTRFS_BALANCE_OPTS_SOFT
;
534 EndDialog(hwndDlg
, 0);
537 INT_PTR CALLBACK
BtrfsBalance::BalanceOptsDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
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
);
551 opts
= balance_started
? &bqb
.data_opts
: &data_opts
;
555 opts
= balance_started
? &bqb
.metadata_opts
: &metadata_opts
;
559 opts
= balance_started
? &bqb
.system_opts
: &system_opts
;
566 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
568 devcb
= GetDlgItem(hwndDlg
, IDC_DEVID_COMBO
);
570 if (!LoadStringW(module
, IDS_DEVID_LIST
, u
, sizeof(u
) / sizeof(WCHAR
))) {
571 ShowError(hwndDlg
, GetLastError());
577 WCHAR t
[255], v
[255];
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());
588 if (StringCchPrintfW(s
, sizeof(s
) / sizeof(WCHAR
), v
, bd
->device_number
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
591 if (!LoadStringW(module
, IDS_DISK_PART_NUM
, v
, sizeof(v
) / sizeof(WCHAR
))) {
592 ShowError(hwndDlg
, GetLastError());
596 if (StringCchPrintfW(s
, sizeof(s
) / sizeof(WCHAR
), v
, bd
->device_number
, bd
->partition_number
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
600 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), u
, bd
->dev_id
, s
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
603 SendMessage(devcb
, CB_ADDSTRING
, NULL
, (LPARAM
)t
);
605 if (opts
->devid
== bd
->dev_id
)
606 SendMessage(devcb
, CB_SETCURSEL
, num_devices
, 0);
611 num_writeable_devices
++;
613 if (bd
->next_entry
> 0)
614 bd
= (btrfs_device
*)((UINT8
*)bd
+ bd
->next_entry
);
619 convcb
= GetDlgItem(hwndDlg
, IDC_CONVERT_COMBO
);
621 if (num_writeable_devices
== 0)
622 num_writeable_devices
= num_devices
;
625 while (convtypes
[i
] != 0) {
626 if (!LoadStringW(module
, convtypes
[i
], s
, sizeof(s
) / sizeof(WCHAR
))) {
627 ShowError(hwndDlg
, GetLastError());
631 SendMessage(convcb
, CB_ADDSTRING
, NULL
, (LPARAM
)s
);
633 if (opts
->convert
== convtypes2
[i
])
634 SendMessage(convcb
, CB_SETCURSEL
, i
, 0);
638 if (num_writeable_devices
< 2 && i
== 2)
640 else if (num_writeable_devices
< 3 && i
== 4)
642 else if (num_writeable_devices
< 4 && i
== 5)
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
);
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
);
668 CheckDlgButton(hwndDlg
, IDC_USAGE
, opts
->flags
& BTRFS_BALANCE_OPTS_USAGE
? BST_CHECKED
: BST_UNCHECKED
);
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);
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);
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
);
686 if (num_devices
< 2 || balance_started
)
687 EnableWindow(GetDlgItem(hwndDlg
, IDC_DEVID
), FALSE
);
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
);
694 CheckDlgButton(hwndDlg
, IDC_DRANGE
, opts
->flags
& BTRFS_BALANCE_OPTS_DRANGE
? BST_CHECKED
: BST_UNCHECKED
);
696 _itow(opts
->drange_start
, s
, 10);
697 SetDlgItemTextW(hwndDlg
, IDC_DRANGE_START
, s
);
699 _itow(opts
->drange_end
, s
, 10);
700 SetDlgItemTextW(hwndDlg
, IDC_DRANGE_END
, s
);
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
);
708 CheckDlgButton(hwndDlg
, IDC_VRANGE
, opts
->flags
& BTRFS_BALANCE_OPTS_VRANGE
? BST_CHECKED
: BST_UNCHECKED
);
710 _itow(opts
->vrange_start
, s
, 10);
711 SetDlgItemTextW(hwndDlg
, IDC_VRANGE_START
, s
);
713 _itow(opts
->vrange_end
, s
, 10);
714 SetDlgItemTextW(hwndDlg
, IDC_VRANGE_END
, s
);
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
);
722 CheckDlgButton(hwndDlg
, IDC_LIMIT
, opts
->flags
& BTRFS_BALANCE_OPTS_LIMIT
? BST_CHECKED
: BST_UNCHECKED
);
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);
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);
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
);
740 CheckDlgButton(hwndDlg
, IDC_STRIPES
, opts
->flags
& BTRFS_BALANCE_OPTS_STRIPES
? BST_CHECKED
: BST_UNCHECKED
);
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);
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);
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
);
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
);
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
);
769 switch (HIWORD(wParam
)) {
771 switch (LOWORD(wParam
)) {
773 if (balance_status
& (BTRFS_BALANCE_RUNNING
| BTRFS_BALANCE_PAUSED
))
774 EndDialog(hwndDlg
, 0);
776 SaveBalanceOpts(hwndDlg
);
780 EndDialog(hwndDlg
, 0);
784 BOOL enabled
= IsDlgButtonChecked(hwndDlg
, IDC_PROFILES
) == BST_CHECKED
? TRUE
: FALSE
;
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
);
797 BOOL enabled
= IsDlgButtonChecked(hwndDlg
, IDC_USAGE
) == BST_CHECKED
? TRUE
: FALSE
;
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
);
807 BOOL enabled
= IsDlgButtonChecked(hwndDlg
, IDC_DEVID
) == BST_CHECKED
? TRUE
: FALSE
;
809 EnableWindow(GetDlgItem(hwndDlg
, IDC_DEVID_COMBO
), enabled
);
814 BOOL enabled
= IsDlgButtonChecked(hwndDlg
, IDC_DRANGE
) == BST_CHECKED
? TRUE
: FALSE
;
816 EnableWindow(GetDlgItem(hwndDlg
, IDC_DRANGE_START
), enabled
);
817 EnableWindow(GetDlgItem(hwndDlg
, IDC_DRANGE_END
), enabled
);
822 BOOL enabled
= IsDlgButtonChecked(hwndDlg
, IDC_VRANGE
) == BST_CHECKED
? TRUE
: FALSE
;
824 EnableWindow(GetDlgItem(hwndDlg
, IDC_VRANGE_START
), enabled
);
825 EnableWindow(GetDlgItem(hwndDlg
, IDC_VRANGE_END
), enabled
);
830 BOOL enabled
= IsDlgButtonChecked(hwndDlg
, IDC_LIMIT
) == BST_CHECKED
? TRUE
: FALSE
;
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
);
840 BOOL enabled
= IsDlgButtonChecked(hwndDlg
, IDC_STRIPES
) == BST_CHECKED
? TRUE
: FALSE
;
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
);
850 BOOL enabled
= IsDlgButtonChecked(hwndDlg
, IDC_CONVERT
) == BST_CHECKED
? TRUE
: FALSE
;
852 EnableWindow(GetDlgItem(hwndDlg
, IDC_CONVERT_COMBO
), enabled
);
853 EnableWindow(GetDlgItem(hwndDlg
, IDC_SOFT
), enabled
);
865 static INT_PTR CALLBACK
stub_BalanceOptsDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
868 if (uMsg
== WM_INITDIALOG
) {
869 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
870 bb
= (BtrfsBalance
*)lParam
;
872 bb
= (BtrfsBalance
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
876 return bb
->BalanceOptsDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
881 void BtrfsBalance::ShowBalanceOptions(HWND hwndDlg
, UINT8 type
) {
883 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_BALANCE_OPTIONS
), hwndDlg
, stub_BalanceOptsDlgProc
, (LPARAM
)this);
886 INT_PTR CALLBACK
BtrfsBalance::BalanceDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
890 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
892 RtlZeroMemory(&data_opts
, sizeof(btrfs_balance_opts
));
893 RtlZeroMemory(&metadata_opts
, sizeof(btrfs_balance_opts
));
894 RtlZeroMemory(&system_opts
, sizeof(btrfs_balance_opts
));
896 removing
= called_from_RemoveDevice
;
897 shrinking
= called_from_ShrinkDevice
;
898 balance_status
= (removing
|| shrinking
) ? BTRFS_BALANCE_RUNNING
: BTRFS_BALANCE_STOPPED
;
900 RefreshBalanceDlg(hwndDlg
, TRUE
);
903 EnableWindow(GetDlgItem(hwndDlg
, IDC_START_BALANCE
), FALSE
);
904 EnableWindow(GetDlgItem(hwndDlg
, IDC_PAUSE_BALANCE
), FALSE
);
905 EnableWindow(GetDlgItem(hwndDlg
, IDC_CANCEL_BALANCE
), FALSE
);
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
);
912 SetTimer(hwndDlg
, 1, 1000, NULL
);
918 switch (HIWORD(wParam
)) {
920 switch (LOWORD(wParam
)) {
923 KillTimer(hwndDlg
, 1);
924 EndDialog(hwndDlg
, 0);
928 EnableWindow(GetDlgItem(hwndDlg
, IDC_DATA_OPTIONS
), IsDlgButtonChecked(hwndDlg
, IDC_DATA
) == BST_CHECKED
? TRUE
: FALSE
);
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
);
935 EnableWindow(GetDlgItem(hwndDlg
, IDC_METADATA_OPTIONS
), IsDlgButtonChecked(hwndDlg
, IDC_METADATA
) == BST_CHECKED
? TRUE
: FALSE
);
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
);
942 EnableWindow(GetDlgItem(hwndDlg
, IDC_SYSTEM_OPTIONS
), IsDlgButtonChecked(hwndDlg
, IDC_SYSTEM
) == BST_CHECKED
? TRUE
: FALSE
);
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
);
948 case IDC_DATA_OPTIONS
:
949 ShowBalanceOptions(hwndDlg
, 1);
952 case IDC_METADATA_OPTIONS
:
953 ShowBalanceOptions(hwndDlg
, 2);
956 case IDC_SYSTEM_OPTIONS
:
957 ShowBalanceOptions(hwndDlg
, 3);
960 case IDC_START_BALANCE
:
961 StartBalance(hwndDlg
);
964 case IDC_PAUSE_BALANCE
:
965 PauseBalance(hwndDlg
);
966 RefreshBalanceDlg(hwndDlg
, FALSE
);
969 case IDC_CANCEL_BALANCE
:
970 StopBalance(hwndDlg
);
971 RefreshBalanceDlg(hwndDlg
, FALSE
);
979 RefreshBalanceDlg(hwndDlg
, FALSE
);
986 static INT_PTR CALLBACK
stub_BalanceDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
989 if (uMsg
== WM_INITDIALOG
) {
990 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
991 bb
= (BtrfsBalance
*)lParam
;
993 bb
= (BtrfsBalance
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
997 return bb
->BalanceDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
1002 void BtrfsBalance::ShowBalance(HWND hwndDlg
) {
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
);
1014 if (h
!= INVALID_HANDLE_VALUE
) {
1016 IO_STATUS_BLOCK iosb
;
1022 devices
= (btrfs_device
*)malloc(devsize
);
1025 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_GET_DEVICES
, NULL
, 0, devices
, devsize
);
1026 if (Status
== STATUS_BUFFER_OVERFLOW
) {
1031 devices
= (btrfs_device
*)malloc(devsize
);
1040 if (!NT_SUCCESS(Status
)) {
1042 ShowNtStatusError(hwndDlg
, Status
);
1048 ShowError(hwndDlg
, GetLastError());
1056 if (!bd
->readonly
) {
1061 if (bd
->next_entry
> 0)
1062 bd
= (btrfs_device
*)((UINT8
*)bd
+ bd
->next_entry
);
1067 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_BALANCE
), hwndDlg
, stub_BalanceDlgProc
, (LPARAM
)this);
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;
1079 static void unserialize(void* data
, ULONG len
, WCHAR
* s
) {
1084 while (s
[0] != 0 && s
[1] != 0 && len
> 0) {
1085 *d
= from_hex_digit(s
[0]) << 4 | from_hex_digit(s
[1]);
1097 void CALLBACK
StartBalanceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
1098 WCHAR
*s
, *vol
, *block
;
1100 btrfs_start_balance bsb
;
1101 TOKEN_PRIVILEGES tp
;
1104 s
= wcsstr(lpszCmdLine
, L
" ");
1113 RtlZeroMemory(&bsb
, sizeof(btrfs_start_balance
));
1114 unserialize(&bsb
, sizeof(btrfs_start_balance
), block
);
1116 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
)) {
1117 ShowError(hwnd
, GetLastError());
1121 if (!LookupPrivilegeValueW(NULL
, L
"SeManageVolumePrivilege", &luid
)) {
1122 ShowError(hwnd
, GetLastError());
1126 tp
.PrivilegeCount
= 1;
1127 tp
.Privileges
[0].Luid
= luid
;
1128 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
1130 if (!AdjustTokenPrivileges(token
, FALSE
, &tp
, sizeof(TOKEN_PRIVILEGES
), NULL
, NULL
)) {
1131 ShowError(hwnd
, GetLastError());
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
);
1138 if (h
!= INVALID_HANDLE_VALUE
) {
1140 IO_STATUS_BLOCK iosb
;
1142 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_START_BALANCE
, &bsb
, sizeof(btrfs_start_balance
), NULL
, 0);
1144 if (Status
== STATUS_DEVICE_NOT_READY
) {
1145 btrfs_query_scrub bqs
;
1148 Status2
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_QUERY_SCRUB
, NULL
, 0, &bqs
, sizeof(btrfs_query_scrub
));
1150 if ((NT_SUCCESS(Status2
) || Status2
== STATUS_BUFFER_OVERFLOW
) && bqs
.status
!= BTRFS_SCRUB_STOPPED
) {
1151 ShowStringError(hwnd
, IDS_BALANCE_SCRUB_RUNNING
);
1157 if (!NT_SUCCESS(Status
)) {
1158 ShowNtStatusError(hwnd
, Status
);
1165 ShowError(hwnd
, GetLastError());
1173 void CALLBACK
PauseBalanceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
1175 TOKEN_PRIVILEGES tp
;
1178 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
)) {
1179 ShowError(hwnd
, GetLastError());
1183 if (!LookupPrivilegeValueW(NULL
, L
"SeManageVolumePrivilege", &luid
)) {
1184 ShowError(hwnd
, GetLastError());
1188 tp
.PrivilegeCount
= 1;
1189 tp
.Privileges
[0].Luid
= luid
;
1190 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
1192 if (!AdjustTokenPrivileges(token
, FALSE
, &tp
, sizeof(TOKEN_PRIVILEGES
), NULL
, NULL
)) {
1193 ShowError(hwnd
, GetLastError());
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
);
1200 if (h
!= INVALID_HANDLE_VALUE
) {
1202 IO_STATUS_BLOCK iosb
;
1203 btrfs_query_balance bqb2
;
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
);
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);
1221 if (!NT_SUCCESS(Status
)) {
1222 ShowNtStatusError(hwnd
, Status
);
1229 ShowError(hwnd
, GetLastError());
1237 void CALLBACK
StopBalanceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
1239 TOKEN_PRIVILEGES tp
;
1242 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
)) {
1243 ShowError(hwnd
, GetLastError());
1247 if (!LookupPrivilegeValueW(NULL
, L
"SeManageVolumePrivilege", &luid
)) {
1248 ShowError(hwnd
, GetLastError());
1252 tp
.PrivilegeCount
= 1;
1253 tp
.Privileges
[0].Luid
= luid
;
1254 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
1256 if (!AdjustTokenPrivileges(token
, FALSE
, &tp
, sizeof(TOKEN_PRIVILEGES
), NULL
, NULL
)) {
1257 ShowError(hwnd
, GetLastError());
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
);
1264 if (h
!= INVALID_HANDLE_VALUE
) {
1266 IO_STATUS_BLOCK iosb
;
1267 btrfs_query_balance bqb2
;
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
);
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);
1283 if (!NT_SUCCESS(Status
)) {
1284 ShowNtStatusError(hwnd
, Status
);
1291 ShowError(hwnd
, GetLastError());