1c2c66affSColin Finck /* Copyright (c) Mark Harmstone 2017
2c2c66affSColin Finck *
3c2c66affSColin Finck * This file is part of WinBtrfs.
4c2c66affSColin Finck *
5c2c66affSColin Finck * WinBtrfs is free software: you can redistribute it and/or modify
6c2c66affSColin Finck * it under the terms of the GNU Lesser General Public Licence as published by
7c2c66affSColin Finck * the Free Software Foundation, either version 3 of the Licence, or
8c2c66affSColin Finck * (at your option) any later version.
9c2c66affSColin Finck *
10c2c66affSColin Finck * WinBtrfs is distributed in the hope that it will be useful,
11c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
12c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13c2c66affSColin Finck * GNU Lesser General Public Licence for more details.
14c2c66affSColin Finck *
15c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public Licence
16c2c66affSColin Finck * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17c2c66affSColin Finck
18c2c66affSColin Finck #include "shellext.h"
19c2c66affSColin Finck #include "scrub.h"
20c2c66affSColin Finck #include "resource.h"
21c2c66affSColin Finck #ifndef __REACTOS__
22c2c66affSColin Finck #include "../btrfsioctl.h"
23c2c66affSColin Finck #else
24c2c66affSColin Finck #include "btrfsioctl.h"
25c2c66affSColin Finck #endif
26c2c66affSColin Finck #include <shlobj.h>
27c2c66affSColin Finck #include <uxtheme.h>
28c2c66affSColin Finck #include <stdio.h>
29c2c66affSColin Finck #ifndef __REACTOS__
30c2c66affSColin Finck #include <strsafe.h>
31c2c66affSColin Finck #include <winternl.h>
32c2c66affSColin Finck #else
33c2c66affSColin Finck #define WIN32_NO_STATUS
34c2c66affSColin Finck #include <windef.h>
35c2c66affSColin Finck #include <winbase.h>
36c2c66affSColin Finck #include <strsafe.h>
37c2c66affSColin Finck #include <ndk/iofuncs.h>
38c2c66affSColin Finck #include <ndk/iotypes.h>
39c2c66affSColin Finck #endif
40c2c66affSColin Finck
41c2c66affSColin Finck #define NO_SHLWAPI_STRFCNS
42c2c66affSColin Finck #include <shlwapi.h>
43c2c66affSColin Finck #include <uxtheme.h>
44c2c66affSColin Finck
UpdateTextBox(HWND hwndDlg,btrfs_query_scrub * bqs)45c2c66affSColin Finck void BtrfsScrub::UpdateTextBox(HWND hwndDlg, btrfs_query_scrub* bqs) {
467b718d36SPierre Schweitzer btrfs_query_scrub* bqs2 = nullptr;
477b718d36SPierre Schweitzer bool alloc_bqs2 = false;
48c2c66affSColin Finck NTSTATUS Status;
497b718d36SPierre Schweitzer wstring s, t, u;
507b718d36SPierre Schweitzer WCHAR dt[255], tm[255];
51c2c66affSColin Finck FILETIME filetime;
52c2c66affSColin Finck SYSTEMTIME systime;
537b718d36SPierre Schweitzer uint64_t recoverable_errors = 0, unrecoverable_errors = 0;
54c2c66affSColin Finck
557b718d36SPierre Schweitzer try {
56c2c66affSColin Finck if (bqs->num_errors > 0) {
577b718d36SPierre Schweitzer win_handle h;
58c2c66affSColin Finck IO_STATUS_BLOCK iosb;
59c2c66affSColin Finck ULONG len;
60c2c66affSColin Finck
617b718d36SPierre Schweitzer h = CreateFileW(fn.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
627b718d36SPierre Schweitzer OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
637b718d36SPierre Schweitzer if (h == INVALID_HANDLE_VALUE)
647b718d36SPierre Schweitzer throw last_error(GetLastError());
65c2c66affSColin Finck
66c2c66affSColin Finck len = 0;
67c2c66affSColin Finck
687b718d36SPierre Schweitzer try {
69c2c66affSColin Finck do {
70c2c66affSColin Finck len += 1024;
71c2c66affSColin Finck
727b718d36SPierre Schweitzer if (bqs2) {
73c2c66affSColin Finck free(bqs2);
747b718d36SPierre Schweitzer bqs2 = nullptr;
757b718d36SPierre Schweitzer }
76c2c66affSColin Finck
77c2c66affSColin Finck bqs2 = (btrfs_query_scrub*)malloc(len);
78c2c66affSColin Finck
797b718d36SPierre Schweitzer Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_SCRUB, nullptr, 0, bqs2, len);
80c2c66affSColin Finck
817b718d36SPierre Schweitzer if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
827b718d36SPierre Schweitzer throw ntstatus_error(Status);
83c2c66affSColin Finck } while (Status == STATUS_BUFFER_OVERFLOW);
847b718d36SPierre Schweitzer } catch (...) {
857b718d36SPierre Schweitzer if (bqs2)
867b718d36SPierre Schweitzer free(bqs2);
87c2c66affSColin Finck
887b718d36SPierre Schweitzer throw;
897b718d36SPierre Schweitzer }
90c2c66affSColin Finck
917b718d36SPierre Schweitzer alloc_bqs2 = true;
92c2c66affSColin Finck } else
93c2c66affSColin Finck bqs2 = bqs;
94c2c66affSColin Finck
95c2c66affSColin Finck // "scrub started"
96c2c66affSColin Finck if (bqs2->start_time.QuadPart > 0) {
97c2c66affSColin Finck filetime.dwLowDateTime = bqs2->start_time.LowPart;
98c2c66affSColin Finck filetime.dwHighDateTime = bqs2->start_time.HighPart;
99c2c66affSColin Finck
1007b718d36SPierre Schweitzer if (!FileTimeToSystemTime(&filetime, &systime))
1017b718d36SPierre Schweitzer throw last_error(GetLastError());
102c2c66affSColin Finck
1037b718d36SPierre Schweitzer if (!SystemTimeToTzSpecificLocalTime(nullptr, &systime, &systime))
1047b718d36SPierre Schweitzer throw last_error(GetLastError());
105c2c66affSColin Finck
1067b718d36SPierre Schweitzer if (!load_string(module, IDS_SCRUB_MSG_STARTED, t))
1077b718d36SPierre Schweitzer throw last_error(GetLastError());
108c2c66affSColin Finck
1097b718d36SPierre Schweitzer if (!GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, nullptr, dt, sizeof(dt) / sizeof(WCHAR)))
1107b718d36SPierre Schweitzer throw last_error(GetLastError());
111c2c66affSColin Finck
1127b718d36SPierre Schweitzer if (!GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systime, nullptr, tm, sizeof(tm) / sizeof(WCHAR)))
1137b718d36SPierre Schweitzer throw last_error(GetLastError());
114c2c66affSColin Finck
1157b718d36SPierre Schweitzer wstring_sprintf(u, t, dt, tm);
116c2c66affSColin Finck
117c2c66affSColin Finck s += u;
118c2c66affSColin Finck s += L"\r\n";
119c2c66affSColin Finck }
120c2c66affSColin Finck
121c2c66affSColin Finck // errors
122c2c66affSColin Finck if (bqs2->num_errors > 0) {
123c2c66affSColin Finck btrfs_scrub_error* bse = &bqs2->errors;
124c2c66affSColin Finck
125c2c66affSColin Finck do {
126c2c66affSColin Finck if (bse->recovered)
127c2c66affSColin Finck recoverable_errors++;
128c2c66affSColin Finck else
129c2c66affSColin Finck unrecoverable_errors++;
130c2c66affSColin Finck
131c2c66affSColin Finck if (bse->parity) {
1327b718d36SPierre Schweitzer if (!load_string(module, IDS_SCRUB_MSG_RECOVERABLE_PARITY, t))
1337b718d36SPierre Schweitzer throw last_error(GetLastError());
134c2c66affSColin Finck
1357b718d36SPierre Schweitzer wstring_sprintf(u, t, bse->address, bse->device);
136c2c66affSColin Finck } else if (bse->is_metadata) {
137c2c66affSColin Finck int message;
138c2c66affSColin Finck
139c2c66affSColin Finck if (bse->recovered)
140c2c66affSColin Finck message = IDS_SCRUB_MSG_RECOVERABLE_METADATA;
141c2c66affSColin Finck else if (bse->metadata.firstitem.obj_id == 0 && bse->metadata.firstitem.obj_type == 0 && bse->metadata.firstitem.offset == 0)
142c2c66affSColin Finck message = IDS_SCRUB_MSG_UNRECOVERABLE_METADATA;
143c2c66affSColin Finck else
144c2c66affSColin Finck message = IDS_SCRUB_MSG_UNRECOVERABLE_METADATA_FIRSTITEM;
145c2c66affSColin Finck
1467b718d36SPierre Schweitzer if (!load_string(module, message, t))
1477b718d36SPierre Schweitzer throw last_error(GetLastError());
148c2c66affSColin Finck
1497b718d36SPierre Schweitzer if (bse->recovered)
1507b718d36SPierre Schweitzer wstring_sprintf(u, t, bse->address, bse->device);
1517b718d36SPierre Schweitzer else if (bse->metadata.firstitem.obj_id == 0 && bse->metadata.firstitem.obj_type == 0 && bse->metadata.firstitem.offset == 0)
1527b718d36SPierre Schweitzer wstring_sprintf(u, t, bse->address, bse->device, bse->metadata.root, bse->metadata.level);
1537b718d36SPierre Schweitzer else
1547b718d36SPierre Schweitzer wstring_sprintf(u, t, bse->address, bse->device, bse->metadata.root, bse->metadata.level, bse->metadata.firstitem.obj_id,
1557b718d36SPierre Schweitzer bse->metadata.firstitem.obj_type, bse->metadata.firstitem.offset);
156c2c66affSColin Finck } else {
157c2c66affSColin Finck int message;
158c2c66affSColin Finck
159c2c66affSColin Finck if (bse->recovered)
160c2c66affSColin Finck message = IDS_SCRUB_MSG_RECOVERABLE_DATA;
161c2c66affSColin Finck else if (bse->data.subvol != 0)
162c2c66affSColin Finck message = IDS_SCRUB_MSG_UNRECOVERABLE_DATA_SUBVOL;
163c2c66affSColin Finck else
164c2c66affSColin Finck message = IDS_SCRUB_MSG_UNRECOVERABLE_DATA;
165c2c66affSColin Finck
1667b718d36SPierre Schweitzer if (!load_string(module, message, t))
1677b718d36SPierre Schweitzer throw last_error(GetLastError());
168c2c66affSColin Finck
1697b718d36SPierre Schweitzer if (bse->recovered)
1707b718d36SPierre Schweitzer wstring_sprintf(u, t, bse->address, bse->device);
1717b718d36SPierre Schweitzer else if (bse->data.subvol != 0)
1727b718d36SPierre Schweitzer wstring_sprintf(u, t, bse->address, bse->device, bse->data.subvol,
1737b718d36SPierre Schweitzer bse->data.filename_length / sizeof(WCHAR), bse->data.filename, bse->data.offset);
1747b718d36SPierre Schweitzer else
1757b718d36SPierre Schweitzer wstring_sprintf(u, t, bse->address, bse->device, bse->data.filename_length / sizeof(WCHAR),
1767b718d36SPierre Schweitzer bse->data.filename, bse->data.offset);
177c2c66affSColin Finck }
178c2c66affSColin Finck
179c2c66affSColin Finck s += u;
180c2c66affSColin Finck s += L"\r\n";
181c2c66affSColin Finck
182c2c66affSColin Finck if (bse->next_entry == 0)
183c2c66affSColin Finck break;
184c2c66affSColin Finck else
1857b718d36SPierre Schweitzer bse = (btrfs_scrub_error*)((uint8_t*)bse + bse->next_entry);
1867b718d36SPierre Schweitzer } while (true);
187c2c66affSColin Finck }
188c2c66affSColin Finck
189c2c66affSColin Finck if (bqs2->finish_time.QuadPart > 0) {
1907b718d36SPierre Schweitzer wstring d1, d2;
191c2c66affSColin Finck float speed;
192c2c66affSColin Finck
193c2c66affSColin Finck // "scrub finished"
194c2c66affSColin Finck
195c2c66affSColin Finck filetime.dwLowDateTime = bqs2->finish_time.LowPart;
196c2c66affSColin Finck filetime.dwHighDateTime = bqs2->finish_time.HighPart;
197c2c66affSColin Finck
1987b718d36SPierre Schweitzer if (!FileTimeToSystemTime(&filetime, &systime))
1997b718d36SPierre Schweitzer throw last_error(GetLastError());
200c2c66affSColin Finck
2017b718d36SPierre Schweitzer if (!SystemTimeToTzSpecificLocalTime(nullptr, &systime, &systime))
2027b718d36SPierre Schweitzer throw last_error(GetLastError());
203c2c66affSColin Finck
2047b718d36SPierre Schweitzer if (!load_string(module, IDS_SCRUB_MSG_FINISHED, t))
2057b718d36SPierre Schweitzer throw last_error(GetLastError());
206c2c66affSColin Finck
2077b718d36SPierre Schweitzer if (!GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, nullptr, dt, sizeof(dt) / sizeof(WCHAR)))
2087b718d36SPierre Schweitzer throw last_error(GetLastError());
209c2c66affSColin Finck
2107b718d36SPierre Schweitzer if (!GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systime, nullptr, tm, sizeof(tm) / sizeof(WCHAR)))
2117b718d36SPierre Schweitzer throw last_error(GetLastError());
212c2c66affSColin Finck
2137b718d36SPierre Schweitzer wstring_sprintf(u, t, dt, tm);
214c2c66affSColin Finck
215c2c66affSColin Finck s += u;
216c2c66affSColin Finck s += L"\r\n";
217c2c66affSColin Finck
218c2c66affSColin Finck // summary
219c2c66affSColin Finck
2207b718d36SPierre Schweitzer if (!load_string(module, IDS_SCRUB_MSG_SUMMARY, t))
2217b718d36SPierre Schweitzer throw last_error(GetLastError());
222c2c66affSColin Finck
2237b718d36SPierre Schweitzer format_size(bqs2->data_scrubbed, d1, false);
224c2c66affSColin Finck
225c2c66affSColin Finck speed = (float)bqs2->data_scrubbed / ((float)bqs2->duration / 10000000.0f);
226c2c66affSColin Finck
2277b718d36SPierre Schweitzer format_size((uint64_t)speed, d2, false);
228c2c66affSColin Finck
2297b718d36SPierre Schweitzer wstring_sprintf(u, t, d1.c_str(), bqs2->duration / 10000000, d2.c_str());
230c2c66affSColin Finck
231c2c66affSColin Finck s += u;
232c2c66affSColin Finck s += L"\r\n";
233c2c66affSColin Finck
234c2c66affSColin Finck // recoverable errors
235c2c66affSColin Finck
2367b718d36SPierre Schweitzer if (!load_string(module, IDS_SCRUB_MSG_SUMMARY_ERRORS_RECOVERABLE, t))
2377b718d36SPierre Schweitzer throw last_error(GetLastError());
238c2c66affSColin Finck
2397b718d36SPierre Schweitzer wstring_sprintf(u, t, recoverable_errors);
240c2c66affSColin Finck
241c2c66affSColin Finck s += u;
242c2c66affSColin Finck s += L"\r\n";
243c2c66affSColin Finck
244c2c66affSColin Finck // unrecoverable errors
245c2c66affSColin Finck
2467b718d36SPierre Schweitzer if (!load_string(module, IDS_SCRUB_MSG_SUMMARY_ERRORS_UNRECOVERABLE, t))
2477b718d36SPierre Schweitzer throw last_error(GetLastError());
248c2c66affSColin Finck
2497b718d36SPierre Schweitzer wstring_sprintf(u, t, unrecoverable_errors);
250c2c66affSColin Finck
251c2c66affSColin Finck s += u;
252c2c66affSColin Finck s += L"\r\n";
253c2c66affSColin Finck }
254c2c66affSColin Finck
255c2c66affSColin Finck SetWindowTextW(GetDlgItem(hwndDlg, IDC_SCRUB_INFO), s.c_str());
2567b718d36SPierre Schweitzer } catch (...) {
2577b718d36SPierre Schweitzer if (alloc_bqs2)
2587b718d36SPierre Schweitzer free(bqs2);
259c2c66affSColin Finck
2607b718d36SPierre Schweitzer throw;
2617b718d36SPierre Schweitzer }
2627b718d36SPierre Schweitzer
263c2c66affSColin Finck if (alloc_bqs2)
264c2c66affSColin Finck free(bqs2);
265c2c66affSColin Finck }
266c2c66affSColin Finck
RefreshScrubDlg(HWND hwndDlg,bool first_time)2677b718d36SPierre Schweitzer void BtrfsScrub::RefreshScrubDlg(HWND hwndDlg, bool first_time) {
268c2c66affSColin Finck btrfs_query_scrub bqs;
269c2c66affSColin Finck
2707b718d36SPierre Schweitzer {
2717b718d36SPierre Schweitzer win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
2727b718d36SPierre Schweitzer OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
273c2c66affSColin Finck if (h != INVALID_HANDLE_VALUE) {
274c2c66affSColin Finck NTSTATUS Status;
275c2c66affSColin Finck IO_STATUS_BLOCK iosb;
276c2c66affSColin Finck
2777b718d36SPierre Schweitzer Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_SCRUB, nullptr, 0, &bqs, sizeof(btrfs_query_scrub));
278c2c66affSColin Finck
2797b718d36SPierre Schweitzer if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
2807b718d36SPierre Schweitzer throw ntstatus_error(Status);
2817b718d36SPierre Schweitzer } else
2827b718d36SPierre Schweitzer throw last_error(GetLastError());
283c2c66affSColin Finck }
284c2c66affSColin Finck
285c2c66affSColin Finck if (first_time || status != bqs.status || chunks_left != bqs.chunks_left) {
2867b718d36SPierre Schweitzer wstring s;
287c2c66affSColin Finck
288c2c66affSColin Finck if (bqs.status == BTRFS_SCRUB_STOPPED) {
2897b718d36SPierre Schweitzer EnableWindow(GetDlgItem(hwndDlg, IDC_START_SCRUB), true);
2907b718d36SPierre Schweitzer EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_SCRUB), false);
2917b718d36SPierre Schweitzer EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_SCRUB), false);
292c2c66affSColin Finck
293c2c66affSColin Finck if (bqs.error != STATUS_SUCCESS) {
2947b718d36SPierre Schweitzer wstring t;
295c2c66affSColin Finck
2967b718d36SPierre Schweitzer if (!load_string(module, IDS_SCRUB_FAILED, t))
2977b718d36SPierre Schweitzer throw last_error(GetLastError());
298c2c66affSColin Finck
2997b718d36SPierre Schweitzer wstring_sprintf(s, t, bqs.error);
300c2c66affSColin Finck } else {
3017b718d36SPierre Schweitzer if (!load_string(module, bqs.total_chunks == 0 ? IDS_NO_SCRUB : IDS_SCRUB_FINISHED, s))
3027b718d36SPierre Schweitzer throw last_error(GetLastError());
303c2c66affSColin Finck }
304c2c66affSColin Finck } else {
3057b718d36SPierre Schweitzer wstring t;
306c2c66affSColin Finck float pc;
307c2c66affSColin Finck
3087b718d36SPierre Schweitzer EnableWindow(GetDlgItem(hwndDlg, IDC_START_SCRUB), false);
3097b718d36SPierre Schweitzer EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_SCRUB), true);
3107b718d36SPierre Schweitzer EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_SCRUB), true);
311c2c66affSColin Finck
3127b718d36SPierre Schweitzer if (!load_string(module, bqs.status == BTRFS_SCRUB_PAUSED ? IDS_SCRUB_PAUSED : IDS_SCRUB_RUNNING, t))
3137b718d36SPierre Schweitzer throw last_error(GetLastError());
314c2c66affSColin Finck
315c2c66affSColin Finck pc = ((float)(bqs.total_chunks - bqs.chunks_left) / (float)bqs.total_chunks) * 100.0f;
316c2c66affSColin Finck
3177b718d36SPierre Schweitzer wstring_sprintf(s, t, bqs.total_chunks - bqs.chunks_left, bqs.total_chunks, pc);
318c2c66affSColin Finck }
319c2c66affSColin Finck
3207b718d36SPierre Schweitzer SetDlgItemTextW(hwndDlg, IDC_SCRUB_STATUS, s.c_str());
321c2c66affSColin Finck
322c2c66affSColin Finck if (first_time || status != bqs.status) {
323c2c66affSColin Finck EnableWindow(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), bqs.status != BTRFS_SCRUB_STOPPED);
324c2c66affSColin Finck
325c2c66affSColin Finck if (bqs.status != BTRFS_SCRUB_STOPPED) {
326c2c66affSColin Finck SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETRANGE32, 0, (LPARAM)bqs.total_chunks);
327c2c66affSColin Finck SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETPOS, (WPARAM)(bqs.total_chunks - bqs.chunks_left), 0);
328c2c66affSColin Finck
329c2c66affSColin Finck if (bqs.status == BTRFS_SCRUB_PAUSED)
330c2c66affSColin Finck SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETSTATE, PBST_PAUSED, 0);
331c2c66affSColin Finck else
332c2c66affSColin Finck SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETSTATE, PBST_NORMAL, 0);
333c2c66affSColin Finck } else {
334c2c66affSColin Finck SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETRANGE32, 0, 0);
335c2c66affSColin Finck SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETPOS, 0, 0);
336c2c66affSColin Finck }
337c2c66affSColin Finck
338c2c66affSColin Finck chunks_left = bqs.chunks_left;
339c2c66affSColin Finck }
340c2c66affSColin Finck }
341c2c66affSColin Finck
342c2c66affSColin Finck if (bqs.status != BTRFS_SCRUB_STOPPED && chunks_left != bqs.chunks_left) {
343c2c66affSColin Finck SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETPOS, (WPARAM)(bqs.total_chunks - bqs.chunks_left), 0);
344c2c66affSColin Finck chunks_left = bqs.chunks_left;
345c2c66affSColin Finck }
346c2c66affSColin Finck
347c2c66affSColin Finck if (first_time || status != bqs.status || num_errors != bqs.num_errors) {
348c2c66affSColin Finck UpdateTextBox(hwndDlg, &bqs);
349c2c66affSColin Finck
350c2c66affSColin Finck num_errors = bqs.num_errors;
351c2c66affSColin Finck }
352c2c66affSColin Finck
353c2c66affSColin Finck status = bqs.status;
354c2c66affSColin Finck }
355c2c66affSColin Finck
StartScrub(HWND hwndDlg)356c2c66affSColin Finck void BtrfsScrub::StartScrub(HWND hwndDlg) {
3577b718d36SPierre Schweitzer win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
3587b718d36SPierre Schweitzer OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
359c2c66affSColin Finck
360c2c66affSColin Finck if (h != INVALID_HANDLE_VALUE) {
361c2c66affSColin Finck NTSTATUS Status;
362c2c66affSColin Finck IO_STATUS_BLOCK iosb;
363c2c66affSColin Finck
3647b718d36SPierre Schweitzer Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_START_SCRUB, nullptr, 0, nullptr, 0);
365c2c66affSColin Finck
366c2c66affSColin Finck if (Status == STATUS_DEVICE_NOT_READY) {
367c2c66affSColin Finck btrfs_query_balance bqb;
368c2c66affSColin Finck NTSTATUS Status2;
369c2c66affSColin Finck
3707b718d36SPierre Schweitzer Status2 = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_BALANCE, nullptr, 0, &bqb, sizeof(btrfs_query_balance));
371c2c66affSColin Finck
3727b718d36SPierre Schweitzer if (NT_SUCCESS(Status2) && bqb.status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED))
3737b718d36SPierre Schweitzer throw string_error(IDS_SCRUB_BALANCE_RUNNING);
374c2c66affSColin Finck }
375c2c66affSColin Finck
3767b718d36SPierre Schweitzer if (!NT_SUCCESS(Status))
3777b718d36SPierre Schweitzer throw ntstatus_error(Status);
378c2c66affSColin Finck
3797b718d36SPierre Schweitzer RefreshScrubDlg(hwndDlg, true);
3807b718d36SPierre Schweitzer } else
3817b718d36SPierre Schweitzer throw last_error(GetLastError());
382c2c66affSColin Finck }
383c2c66affSColin Finck
PauseScrub(HWND hwndDlg)384c2c66affSColin Finck void BtrfsScrub::PauseScrub(HWND hwndDlg) {
385c2c66affSColin Finck btrfs_query_scrub bqs;
386c2c66affSColin Finck
3877b718d36SPierre Schweitzer win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
3887b718d36SPierre Schweitzer OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
3897b718d36SPierre Schweitzer
390c2c66affSColin Finck if (h != INVALID_HANDLE_VALUE) {
391c2c66affSColin Finck NTSTATUS Status;
392c2c66affSColin Finck IO_STATUS_BLOCK iosb;
393c2c66affSColin Finck
3947b718d36SPierre Schweitzer Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_QUERY_SCRUB, nullptr, 0, &bqs, sizeof(btrfs_query_scrub));
395c2c66affSColin Finck
3967b718d36SPierre Schweitzer if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
3977b718d36SPierre Schweitzer throw ntstatus_error(Status);
398c2c66affSColin Finck
399c2c66affSColin Finck if (bqs.status == BTRFS_SCRUB_PAUSED)
4007b718d36SPierre Schweitzer Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESUME_SCRUB, nullptr, 0, nullptr, 0);
401c2c66affSColin Finck else
4027b718d36SPierre Schweitzer Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_PAUSE_SCRUB, nullptr, 0, nullptr, 0);
403c2c66affSColin Finck
4047b718d36SPierre Schweitzer if (!NT_SUCCESS(Status))
4057b718d36SPierre Schweitzer throw ntstatus_error(Status);
4067b718d36SPierre Schweitzer } else
4077b718d36SPierre Schweitzer throw last_error(GetLastError());
408c2c66affSColin Finck }
409c2c66affSColin Finck
StopScrub(HWND hwndDlg)410c2c66affSColin Finck void BtrfsScrub::StopScrub(HWND hwndDlg) {
4117b718d36SPierre Schweitzer win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
4127b718d36SPierre Schweitzer OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
413c2c66affSColin Finck
414c2c66affSColin Finck if (h != INVALID_HANDLE_VALUE) {
415c2c66affSColin Finck NTSTATUS Status;
416c2c66affSColin Finck IO_STATUS_BLOCK iosb;
417c2c66affSColin Finck
4187b718d36SPierre Schweitzer Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_STOP_SCRUB, nullptr, 0, nullptr, 0);
419c2c66affSColin Finck
4207b718d36SPierre Schweitzer if (!NT_SUCCESS(Status))
4217b718d36SPierre Schweitzer throw ntstatus_error(Status);
4227b718d36SPierre Schweitzer } else
4237b718d36SPierre Schweitzer throw last_error(GetLastError());
424c2c66affSColin Finck }
425c2c66affSColin Finck
ScrubDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)426c2c66affSColin Finck INT_PTR CALLBACK BtrfsScrub::ScrubDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
4277b718d36SPierre Schweitzer try {
428c2c66affSColin Finck switch (uMsg) {
429c2c66affSColin Finck case WM_INITDIALOG:
4307b718d36SPierre Schweitzer RefreshScrubDlg(hwndDlg, true);
4317b718d36SPierre Schweitzer SetTimer(hwndDlg, 1, 1000, nullptr);
432c2c66affSColin Finck break;
433c2c66affSColin Finck
434c2c66affSColin Finck case WM_COMMAND:
435c2c66affSColin Finck switch (HIWORD(wParam)) {
436c2c66affSColin Finck case BN_CLICKED:
437c2c66affSColin Finck switch (LOWORD(wParam)) {
438c2c66affSColin Finck case IDOK:
439c2c66affSColin Finck case IDCANCEL:
440c2c66affSColin Finck EndDialog(hwndDlg, 0);
4417b718d36SPierre Schweitzer return true;
442c2c66affSColin Finck
443c2c66affSColin Finck case IDC_START_SCRUB:
444c2c66affSColin Finck StartScrub(hwndDlg);
4457b718d36SPierre Schweitzer return true;
446c2c66affSColin Finck
447c2c66affSColin Finck case IDC_PAUSE_SCRUB:
448c2c66affSColin Finck PauseScrub(hwndDlg);
4497b718d36SPierre Schweitzer return true;
450c2c66affSColin Finck
451c2c66affSColin Finck case IDC_CANCEL_SCRUB:
452c2c66affSColin Finck StopScrub(hwndDlg);
4537b718d36SPierre Schweitzer return true;
454c2c66affSColin Finck }
455c2c66affSColin Finck break;
456c2c66affSColin Finck }
457c2c66affSColin Finck break;
458c2c66affSColin Finck
459c2c66affSColin Finck case WM_TIMER:
4607b718d36SPierre Schweitzer RefreshScrubDlg(hwndDlg, false);
461c2c66affSColin Finck break;
462c2c66affSColin Finck }
4637b718d36SPierre Schweitzer } catch (const exception& e) {
4647b718d36SPierre Schweitzer error_message(hwndDlg, e.what());
4657b718d36SPierre Schweitzer }
466c2c66affSColin Finck
4677b718d36SPierre Schweitzer return false;
468c2c66affSColin Finck }
469c2c66affSColin Finck
stub_ScrubDlgProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)470c2c66affSColin Finck static INT_PTR CALLBACK stub_ScrubDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
471c2c66affSColin Finck BtrfsScrub* bs;
472c2c66affSColin Finck
473c2c66affSColin Finck if (uMsg == WM_INITDIALOG) {
474c2c66affSColin Finck SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
475c2c66affSColin Finck bs = (BtrfsScrub*)lParam;
476c2c66affSColin Finck } else {
477c2c66affSColin Finck bs = (BtrfsScrub*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
478c2c66affSColin Finck }
479c2c66affSColin Finck
480c2c66affSColin Finck if (bs)
481c2c66affSColin Finck return bs->ScrubDlgProc(hwndDlg, uMsg, wParam, lParam);
482c2c66affSColin Finck else
4837b718d36SPierre Schweitzer return false;
484c2c66affSColin Finck }
485c2c66affSColin Finck
ShowScrubW(HWND hwnd,HINSTANCE hinst,LPWSTR lpszCmdLine,int nCmdShow)486*06042735SVincent Franchomme extern "C" void CALLBACK ShowScrubW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
4877b718d36SPierre Schweitzer try {
4887b718d36SPierre Schweitzer win_handle token;
489c2c66affSColin Finck TOKEN_PRIVILEGES tp;
490c2c66affSColin Finck LUID luid;
491c2c66affSColin Finck
4927b718d36SPierre Schweitzer if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
4937b718d36SPierre Schweitzer throw last_error(GetLastError());
494c2c66affSColin Finck
4957b718d36SPierre Schweitzer if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid))
4967b718d36SPierre Schweitzer throw last_error(GetLastError());
497c2c66affSColin Finck
498c2c66affSColin Finck tp.PrivilegeCount = 1;
499c2c66affSColin Finck tp.Privileges[0].Luid = luid;
500c2c66affSColin Finck tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
501c2c66affSColin Finck
5027b718d36SPierre Schweitzer if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr))
5037b718d36SPierre Schweitzer throw last_error(GetLastError());
504c2c66affSColin Finck
505c2c66affSColin Finck set_dpi_aware();
506c2c66affSColin Finck
5077b718d36SPierre Schweitzer BtrfsScrub scrub(lpszCmdLine);
508c2c66affSColin Finck
5097b718d36SPierre Schweitzer DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_SCRUB), hwnd, stub_ScrubDlgProc, (LPARAM)&scrub);
5107b718d36SPierre Schweitzer } catch (const exception& e) {
5117b718d36SPierre Schweitzer error_message(hwnd, e.what());
5127b718d36SPierre Schweitzer }
513c2c66affSColin Finck }
514c2c66affSColin Finck
StartScrubW(HWND hwnd,HINSTANCE hinst,LPWSTR lpszCmdLine,int nCmdShow)515*06042735SVincent Franchomme extern "C" void CALLBACK StartScrubW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
5167b718d36SPierre Schweitzer vector<wstring> args;
517c2c66affSColin Finck
5187b718d36SPierre Schweitzer command_line_to_args(lpszCmdLine, args);
519c2c66affSColin Finck
5207b718d36SPierre Schweitzer if (args.size() >= 1) {
521c2c66affSColin Finck LUID luid;
522c2c66affSColin Finck TOKEN_PRIVILEGES tp;
523c2c66affSColin Finck
5247b718d36SPierre Schweitzer {
5257b718d36SPierre Schweitzer win_handle token;
526c2c66affSColin Finck
5277b718d36SPierre Schweitzer if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
5287b718d36SPierre Schweitzer return;
5297b718d36SPierre Schweitzer
5307b718d36SPierre Schweitzer if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid))
5317b718d36SPierre Schweitzer return;
532c2c66affSColin Finck
533c2c66affSColin Finck tp.PrivilegeCount = 1;
534c2c66affSColin Finck tp.Privileges[0].Luid = luid;
535c2c66affSColin Finck tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
536c2c66affSColin Finck
5377b718d36SPierre Schweitzer if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr))
5387b718d36SPierre Schweitzer return;
5392da53310SPierre Schweitzer }
540c2c66affSColin Finck
5417b718d36SPierre Schweitzer win_handle h = CreateFileW(args[0].c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
5427b718d36SPierre Schweitzer OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
543c2c66affSColin Finck if (h != INVALID_HANDLE_VALUE) {
544c2c66affSColin Finck IO_STATUS_BLOCK iosb;
545c2c66affSColin Finck
5467b718d36SPierre Schweitzer NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_START_SCRUB, nullptr, 0, nullptr, 0);
547c2c66affSColin Finck }
548c2c66affSColin Finck }
549c2c66affSColin Finck }
550c2c66affSColin Finck
StopScrubW(HWND hwnd,HINSTANCE hinst,LPWSTR lpszCmdLine,int nCmdShow)551*06042735SVincent Franchomme extern "C" void CALLBACK StopScrubW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
5527b718d36SPierre Schweitzer vector<wstring> args;
553c2c66affSColin Finck
5547b718d36SPierre Schweitzer command_line_to_args(lpszCmdLine, args);
555c2c66affSColin Finck
5567b718d36SPierre Schweitzer if (args.size() >= 1) {
557c2c66affSColin Finck LUID luid;
558c2c66affSColin Finck TOKEN_PRIVILEGES tp;
559c2c66affSColin Finck
5607b718d36SPierre Schweitzer {
5617b718d36SPierre Schweitzer win_handle token;
562c2c66affSColin Finck
5637b718d36SPierre Schweitzer if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
5647b718d36SPierre Schweitzer return;
5657b718d36SPierre Schweitzer
5667b718d36SPierre Schweitzer if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid))
5677b718d36SPierre Schweitzer return;
568c2c66affSColin Finck
569c2c66affSColin Finck tp.PrivilegeCount = 1;
570c2c66affSColin Finck tp.Privileges[0].Luid = luid;
571c2c66affSColin Finck tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
572c2c66affSColin Finck
5737b718d36SPierre Schweitzer if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr))
5747b718d36SPierre Schweitzer return;
5757b718d36SPierre Schweitzer }
576c2c66affSColin Finck
5777b718d36SPierre Schweitzer win_handle h = CreateFileW(args[0].c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
5787b718d36SPierre Schweitzer OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
579c2c66affSColin Finck if (h != INVALID_HANDLE_VALUE) {
580c2c66affSColin Finck IO_STATUS_BLOCK iosb;
581c2c66affSColin Finck
5827b718d36SPierre Schweitzer NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_STOP_SCRUB, nullptr, 0, nullptr, 0);
583c2c66affSColin Finck }
584c2c66affSColin Finck }
585c2c66affSColin Finck }
586