[ACPPAGE] Visualize custom layers
[reactos.git] / dll / shellext / shellbtrfs / scrub.cpp
1 /* Copyright (c) Mark Harmstone 2017
2 *
3 * This file is part of WinBtrfs.
4 *
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
9 *
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17
18 #include "shellext.h"
19 #include "scrub.h"
20 #include "resource.h"
21 #ifndef __REACTOS__
22 #include "../btrfsioctl.h"
23 #else
24 #include "btrfsioctl.h"
25 #endif
26 #include <shlobj.h>
27 #include <uxtheme.h>
28 #include <stdio.h>
29 #ifndef __REACTOS__
30 #include <strsafe.h>
31 #include <winternl.h>
32 #else
33 #define WIN32_NO_STATUS
34 #include <windef.h>
35 #include <winbase.h>
36 #include <strsafe.h>
37 #include <ndk/iofuncs.h>
38 #include <ndk/iotypes.h>
39 #endif
40 #include <string>
41
42 #define NO_SHLWAPI_STRFCNS
43 #include <shlwapi.h>
44 #include <uxtheme.h>
45
46 void BtrfsScrub::UpdateTextBox(HWND hwndDlg, btrfs_query_scrub* bqs) {
47 btrfs_query_scrub* bqs2 = NULL;
48 BOOL alloc_bqs2 = FALSE;
49 NTSTATUS Status;
50 std::wstring s;
51 WCHAR t[255], u[255], dt[255], tm[255];
52 FILETIME filetime;
53 SYSTEMTIME systime;
54 UINT64 recoverable_errors = 0, unrecoverable_errors = 0;
55
56 if (bqs->num_errors > 0) {
57 HANDLE h;
58 IO_STATUS_BLOCK iosb;
59 ULONG len;
60
61 h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
62 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
63 if (h == INVALID_HANDLE_VALUE) {
64 ShowError(hwndDlg, GetLastError());
65 return;
66 }
67
68 len = 0;
69
70 do {
71 len += 1024;
72
73 if (bqs2)
74 free(bqs2);
75
76 bqs2 = (btrfs_query_scrub*)malloc(len);
77
78 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_QUERY_SCRUB, NULL, 0, bqs2, len);
79
80 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
81 ShowNtStatusError(hwndDlg, Status);
82 CloseHandle(h);
83 free(bqs2);
84 return;
85 }
86 } while (Status == STATUS_BUFFER_OVERFLOW);
87
88 alloc_bqs2 = TRUE;
89
90 CloseHandle(h);
91 } else
92 bqs2 = bqs;
93
94 s[0] = 0;
95
96 // "scrub started"
97 if (bqs2->start_time.QuadPart > 0) {
98 filetime.dwLowDateTime = bqs2->start_time.LowPart;
99 filetime.dwHighDateTime = bqs2->start_time.HighPart;
100
101 if (!FileTimeToSystemTime(&filetime, &systime)) {
102 ShowError(hwndDlg, GetLastError());
103 goto end;
104 }
105
106 if (!SystemTimeToTzSpecificLocalTime(NULL, &systime, &systime)) {
107 ShowError(hwndDlg, GetLastError());
108 goto end;
109 }
110
111 if (!LoadStringW(module, IDS_SCRUB_MSG_STARTED, t, sizeof(t) / sizeof(WCHAR))) {
112 ShowError(hwndDlg, GetLastError());
113 goto end;
114 }
115
116 if (!GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, NULL, dt, sizeof(dt) / sizeof(WCHAR))) {
117 ShowError(hwndDlg, GetLastError());
118 goto end;
119 }
120
121 if (!GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systime, NULL, tm, sizeof(tm) / sizeof(WCHAR))) {
122 ShowError(hwndDlg, GetLastError());
123 goto end;
124 }
125
126 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, dt, tm) == STRSAFE_E_INSUFFICIENT_BUFFER)
127 goto end;
128
129 s += u;
130 s += L"\r\n";
131 }
132
133 // errors
134 if (bqs2->num_errors > 0) {
135 btrfs_scrub_error* bse = &bqs2->errors;
136
137 do {
138 if (bse->recovered)
139 recoverable_errors++;
140 else
141 unrecoverable_errors++;
142
143 if (bse->parity) {
144 if (!LoadStringW(module, IDS_SCRUB_MSG_RECOVERABLE_PARITY, t, sizeof(t) / sizeof(WCHAR))) {
145 ShowError(hwndDlg, GetLastError());
146 goto end;
147 }
148
149 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device) == STRSAFE_E_INSUFFICIENT_BUFFER)
150 goto end;
151 } else if (bse->is_metadata) {
152 int message;
153
154 if (bse->recovered)
155 message = IDS_SCRUB_MSG_RECOVERABLE_METADATA;
156 else if (bse->metadata.firstitem.obj_id == 0 && bse->metadata.firstitem.obj_type == 0 && bse->metadata.firstitem.offset == 0)
157 message = IDS_SCRUB_MSG_UNRECOVERABLE_METADATA;
158 else
159 message = IDS_SCRUB_MSG_UNRECOVERABLE_METADATA_FIRSTITEM;
160
161 if (!LoadStringW(module, message, t, sizeof(t) / sizeof(WCHAR))) {
162 ShowError(hwndDlg, GetLastError());
163 goto end;
164 }
165
166 if (bse->recovered) {
167 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device) == STRSAFE_E_INSUFFICIENT_BUFFER)
168 goto end;
169 } else if (bse->metadata.firstitem.obj_id == 0 && bse->metadata.firstitem.obj_type == 0 && bse->metadata.firstitem.offset == 0) {
170 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device,
171 bse->metadata.root, bse->metadata.level) == STRSAFE_E_INSUFFICIENT_BUFFER)
172 goto end;
173 } else {
174 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device,
175 bse->metadata.root, bse->metadata.level, bse->metadata.firstitem.obj_id, bse->metadata.firstitem.obj_type,
176 bse->metadata.firstitem.offset) == STRSAFE_E_INSUFFICIENT_BUFFER)
177 goto end;
178 }
179 } else {
180 int message;
181
182 if (bse->recovered)
183 message = IDS_SCRUB_MSG_RECOVERABLE_DATA;
184 else if (bse->data.subvol != 0)
185 message = IDS_SCRUB_MSG_UNRECOVERABLE_DATA_SUBVOL;
186 else
187 message = IDS_SCRUB_MSG_UNRECOVERABLE_DATA;
188
189 if (!LoadStringW(module, message, t, sizeof(t) / sizeof(WCHAR))) {
190 ShowError(hwndDlg, GetLastError());
191 goto end;
192 }
193
194 if (bse->recovered) {
195 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device) == STRSAFE_E_INSUFFICIENT_BUFFER)
196 goto end;
197 } else if (bse->data.subvol != 0) {
198 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device, bse->data.subvol,
199 bse->data.filename_length / sizeof(WCHAR), bse->data.filename, bse->data.offset) == STRSAFE_E_INSUFFICIENT_BUFFER)
200 goto end;
201 } else {
202 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, bse->address, bse->device, bse->data.filename_length / sizeof(WCHAR),
203 bse->data.filename, bse->data.offset) == STRSAFE_E_INSUFFICIENT_BUFFER)
204 goto end;
205 }
206 }
207
208 s += u;
209 s += L"\r\n";
210
211 if (bse->next_entry == 0)
212 break;
213 else
214 bse = (btrfs_scrub_error*)((UINT8*)bse + bse->next_entry);
215 } while (TRUE);
216 }
217
218 if (bqs2->finish_time.QuadPart > 0) {
219 WCHAR d1[255], d2[255];
220 float speed;
221
222 // "scrub finished"
223
224 filetime.dwLowDateTime = bqs2->finish_time.LowPart;
225 filetime.dwHighDateTime = bqs2->finish_time.HighPart;
226
227 if (!FileTimeToSystemTime(&filetime, &systime)) {
228 ShowError(hwndDlg, GetLastError());
229 goto end;
230 }
231
232 if (!SystemTimeToTzSpecificLocalTime(NULL, &systime, &systime)) {
233 ShowError(hwndDlg, GetLastError());
234 goto end;
235 }
236
237 if (!LoadStringW(module, IDS_SCRUB_MSG_FINISHED, t, sizeof(t) / sizeof(WCHAR))) {
238 ShowError(hwndDlg, GetLastError());
239 goto end;
240 }
241
242 if (!GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &systime, NULL, dt, sizeof(dt) / sizeof(WCHAR))) {
243 ShowError(hwndDlg, GetLastError());
244 goto end;
245 }
246
247 if (!GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systime, NULL, tm, sizeof(tm) / sizeof(WCHAR))) {
248 ShowError(hwndDlg, GetLastError());
249 goto end;
250 }
251
252 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, dt, tm) == STRSAFE_E_INSUFFICIENT_BUFFER)
253 goto end;
254
255 s += u;
256 s += L"\r\n";
257
258 // summary
259
260 if (!LoadStringW(module, IDS_SCRUB_MSG_SUMMARY, t, sizeof(t) / sizeof(WCHAR))) {
261 ShowError(hwndDlg, GetLastError());
262 goto end;
263 }
264
265 format_size(bqs2->data_scrubbed, d1, sizeof(d1) / sizeof(WCHAR), FALSE);
266
267 speed = (float)bqs2->data_scrubbed / ((float)bqs2->duration / 10000000.0f);
268
269 format_size((UINT64)speed, d2, sizeof(d2) / sizeof(WCHAR), FALSE);
270
271 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, d1, bqs2->duration / 10000000, d2) == STRSAFE_E_INSUFFICIENT_BUFFER)
272 goto end;
273
274 s += u;
275 s += L"\r\n";
276
277 // recoverable errors
278
279 if (!LoadStringW(module, IDS_SCRUB_MSG_SUMMARY_ERRORS_RECOVERABLE, t, sizeof(t) / sizeof(WCHAR))) {
280 ShowError(hwndDlg, GetLastError());
281 goto end;
282 }
283
284 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, recoverable_errors) == STRSAFE_E_INSUFFICIENT_BUFFER)
285 goto end;
286
287 s += u;
288 s += L"\r\n";
289
290 // unrecoverable errors
291
292 if (!LoadStringW(module, IDS_SCRUB_MSG_SUMMARY_ERRORS_UNRECOVERABLE, t, sizeof(t) / sizeof(WCHAR))) {
293 ShowError(hwndDlg, GetLastError());
294 goto end;
295 }
296
297 if (StringCchPrintfW(u, sizeof(u) / sizeof(WCHAR), t, unrecoverable_errors) == STRSAFE_E_INSUFFICIENT_BUFFER)
298 goto end;
299
300 s += u;
301 s += L"\r\n";
302 }
303
304 SetWindowTextW(GetDlgItem(hwndDlg, IDC_SCRUB_INFO), s.c_str());
305
306 end:
307 if (alloc_bqs2)
308 free(bqs2);
309 }
310
311 void BtrfsScrub::RefreshScrubDlg(HWND hwndDlg, BOOL first_time) {
312 HANDLE h;
313 btrfs_query_scrub bqs;
314
315 h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
316 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
317 if (h != INVALID_HANDLE_VALUE) {
318 NTSTATUS Status;
319 IO_STATUS_BLOCK iosb;
320
321 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_QUERY_SCRUB, NULL, 0, &bqs, sizeof(btrfs_query_scrub));
322
323 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
324 ShowNtStatusError(hwndDlg, Status);
325 CloseHandle(h);
326 return;
327 }
328
329 CloseHandle(h);
330 } else {
331 ShowError(hwndDlg, GetLastError());
332 return;
333 }
334
335 if (first_time || status != bqs.status || chunks_left != bqs.chunks_left) {
336 WCHAR s[255];
337
338 if (bqs.status == BTRFS_SCRUB_STOPPED) {
339 EnableWindow(GetDlgItem(hwndDlg, IDC_START_SCRUB), TRUE);
340 EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_SCRUB), FALSE);
341 EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_SCRUB), FALSE);
342
343 if (bqs.error != STATUS_SUCCESS) {
344 WCHAR t[255];
345
346 if (!LoadStringW(module, IDS_SCRUB_FAILED, t, sizeof(t) / sizeof(WCHAR))) {
347 ShowError(hwndDlg, GetLastError());
348 return;
349 }
350
351 if (StringCchPrintfW(s, sizeof(s) / sizeof(WCHAR), t, bqs.error) == STRSAFE_E_INSUFFICIENT_BUFFER)
352 return;
353 } else {
354 if (!LoadStringW(module, bqs.total_chunks == 0 ? IDS_NO_SCRUB : IDS_SCRUB_FINISHED, s, sizeof(s) / sizeof(WCHAR))) {
355 ShowError(hwndDlg, GetLastError());
356 return;
357 }
358 }
359 } else {
360 WCHAR t[255];
361 float pc;
362
363 EnableWindow(GetDlgItem(hwndDlg, IDC_START_SCRUB), FALSE);
364 EnableWindow(GetDlgItem(hwndDlg, IDC_PAUSE_SCRUB), TRUE);
365 EnableWindow(GetDlgItem(hwndDlg, IDC_CANCEL_SCRUB), TRUE);
366
367 if (!LoadStringW(module, bqs.status == BTRFS_SCRUB_PAUSED ? IDS_SCRUB_PAUSED : IDS_SCRUB_RUNNING, t, sizeof(t) / sizeof(WCHAR))) {
368 ShowError(hwndDlg, GetLastError());
369 return;
370 }
371
372 pc = ((float)(bqs.total_chunks - bqs.chunks_left) / (float)bqs.total_chunks) * 100.0f;
373
374 if (StringCchPrintfW(s, sizeof(s) / sizeof(WCHAR), t, bqs.total_chunks - bqs.chunks_left, bqs.total_chunks, pc) == STRSAFE_E_INSUFFICIENT_BUFFER)
375 return;
376 }
377
378 SetDlgItemTextW(hwndDlg, IDC_SCRUB_STATUS, s);
379
380 if (first_time || status != bqs.status) {
381 EnableWindow(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), bqs.status != BTRFS_SCRUB_STOPPED);
382
383 if (bqs.status != BTRFS_SCRUB_STOPPED) {
384 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETRANGE32, 0, (LPARAM)bqs.total_chunks);
385 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETPOS, (WPARAM)(bqs.total_chunks - bqs.chunks_left), 0);
386
387 if (bqs.status == BTRFS_SCRUB_PAUSED)
388 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETSTATE, PBST_PAUSED, 0);
389 else
390 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETSTATE, PBST_NORMAL, 0);
391 } else {
392 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETRANGE32, 0, 0);
393 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETPOS, 0, 0);
394 }
395
396 chunks_left = bqs.chunks_left;
397 }
398 }
399
400 if (bqs.status != BTRFS_SCRUB_STOPPED && chunks_left != bqs.chunks_left) {
401 SendMessageW(GetDlgItem(hwndDlg, IDC_SCRUB_PROGRESS), PBM_SETPOS, (WPARAM)(bqs.total_chunks - bqs.chunks_left), 0);
402 chunks_left = bqs.chunks_left;
403 }
404
405 if (first_time || status != bqs.status || num_errors != bqs.num_errors) {
406 UpdateTextBox(hwndDlg, &bqs);
407
408 num_errors = bqs.num_errors;
409 }
410
411 status = bqs.status;
412 }
413
414 void BtrfsScrub::StartScrub(HWND hwndDlg) {
415 HANDLE h;
416
417 h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
418 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
419 if (h != INVALID_HANDLE_VALUE) {
420 NTSTATUS Status;
421 IO_STATUS_BLOCK iosb;
422
423 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_START_SCRUB, NULL, 0, NULL, 0);
424
425 if (Status == STATUS_DEVICE_NOT_READY) {
426 btrfs_query_balance bqb;
427 NTSTATUS Status2;
428
429 Status2 = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_QUERY_BALANCE, NULL, 0, &bqb, sizeof(btrfs_query_balance));
430
431 if (NT_SUCCESS(Status2) && bqb.status & (BTRFS_BALANCE_RUNNING | BTRFS_BALANCE_PAUSED)) {
432 ShowStringError(hwndDlg, IDS_SCRUB_BALANCE_RUNNING);
433 CloseHandle(h);
434 return;
435 }
436 }
437
438 if (!NT_SUCCESS(Status)) {
439 ShowNtStatusError(hwndDlg, Status);
440 CloseHandle(h);
441 return;
442 }
443
444 RefreshScrubDlg(hwndDlg, TRUE);
445
446 CloseHandle(h);
447 } else {
448 ShowError(hwndDlg, GetLastError());
449 return;
450 }
451 }
452
453 void BtrfsScrub::PauseScrub(HWND hwndDlg) {
454 HANDLE h;
455 btrfs_query_scrub bqs;
456
457 h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
458 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
459 if (h != INVALID_HANDLE_VALUE) {
460 NTSTATUS Status;
461 IO_STATUS_BLOCK iosb;
462
463 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_QUERY_SCRUB, NULL, 0, &bqs, sizeof(btrfs_query_scrub));
464
465 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
466 ShowNtStatusError(hwndDlg, Status);
467 CloseHandle(h);
468 return;
469 }
470
471 if (bqs.status == BTRFS_SCRUB_PAUSED)
472 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_RESUME_SCRUB, NULL, 0, NULL, 0);
473 else
474 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_PAUSE_SCRUB, NULL, 0, NULL, 0);
475
476 if (!NT_SUCCESS(Status)) {
477 ShowNtStatusError(hwndDlg, Status);
478 CloseHandle(h);
479 return;
480 }
481
482 CloseHandle(h);
483 } else {
484 ShowError(hwndDlg, GetLastError());
485 return;
486 }
487 }
488
489 void BtrfsScrub::StopScrub(HWND hwndDlg) {
490 HANDLE h;
491
492 h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
493 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
494 if (h != INVALID_HANDLE_VALUE) {
495 NTSTATUS Status;
496 IO_STATUS_BLOCK iosb;
497
498 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_STOP_SCRUB, NULL, 0, NULL, 0);
499
500 if (!NT_SUCCESS(Status)) {
501 ShowNtStatusError(hwndDlg, Status);
502 CloseHandle(h);
503 return;
504 }
505
506 CloseHandle(h);
507 } else {
508 ShowError(hwndDlg, GetLastError());
509 return;
510 }
511 }
512
513 INT_PTR CALLBACK BtrfsScrub::ScrubDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
514 switch (uMsg) {
515 case WM_INITDIALOG:
516 RefreshScrubDlg(hwndDlg, TRUE);
517 SetTimer(hwndDlg, 1, 1000, NULL);
518 break;
519
520 case WM_COMMAND:
521 switch (HIWORD(wParam)) {
522 case BN_CLICKED:
523 switch (LOWORD(wParam)) {
524 case IDOK:
525 case IDCANCEL:
526 EndDialog(hwndDlg, 0);
527 return TRUE;
528
529 case IDC_START_SCRUB:
530 StartScrub(hwndDlg);
531 return TRUE;
532
533 case IDC_PAUSE_SCRUB:
534 PauseScrub(hwndDlg);
535 return TRUE;
536
537 case IDC_CANCEL_SCRUB:
538 StopScrub(hwndDlg);
539 return TRUE;
540 }
541 break;
542 }
543 break;
544
545 case WM_TIMER:
546 RefreshScrubDlg(hwndDlg, FALSE);
547 break;
548 }
549
550 return FALSE;
551 }
552
553 static INT_PTR CALLBACK stub_ScrubDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
554 BtrfsScrub* bs;
555
556 if (uMsg == WM_INITDIALOG) {
557 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
558 bs = (BtrfsScrub*)lParam;
559 } else {
560 bs = (BtrfsScrub*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
561 }
562
563 if (bs)
564 return bs->ScrubDlgProc(hwndDlg, uMsg, wParam, lParam);
565 else
566 return FALSE;
567 }
568
569 void CALLBACK ShowScrubW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
570 HANDLE token;
571 TOKEN_PRIVILEGES tp;
572 LUID luid;
573 BtrfsScrub* scrub;
574
575 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
576 ShowError(hwnd, GetLastError());
577 return;
578 }
579
580 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) {
581 ShowError(hwnd, GetLastError());
582 goto end;
583 }
584
585 tp.PrivilegeCount = 1;
586 tp.Privileges[0].Luid = luid;
587 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
588
589 if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
590 ShowError(hwnd, GetLastError());
591 goto end;
592 }
593
594 set_dpi_aware();
595
596 scrub = new BtrfsScrub(lpszCmdLine);
597
598 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_SCRUB), hwnd, stub_ScrubDlgProc, (LPARAM)scrub);
599
600 delete scrub;
601
602 end:
603 CloseHandle(token);
604 }
605
606 void CALLBACK StartScrubW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
607 LPWSTR* args;
608 int num_args;
609
610 args = CommandLineToArgvW(lpszCmdLine, &num_args);
611
612 if (!args)
613 return;
614
615 if (num_args >= 1) {
616 HANDLE h, token;
617 LUID luid;
618 TOKEN_PRIVILEGES tp;
619
620 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
621 goto end;
622
623 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid))
624 goto end;
625
626 tp.PrivilegeCount = 1;
627 tp.Privileges[0].Luid = luid;
628 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
629
630 if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
631 goto end;
632
633 CloseHandle(token);
634
635 h = CreateFileW(args[0], FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
636 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
637 if (h != INVALID_HANDLE_VALUE) {
638 IO_STATUS_BLOCK iosb;
639
640 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_START_SCRUB, NULL, 0, NULL, 0);
641
642 CloseHandle(h);
643 }
644 }
645
646 end:
647 LocalFree(args);
648 }
649
650 void CALLBACK StopScrubW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
651 LPWSTR* args;
652 int num_args;
653
654 args = CommandLineToArgvW(lpszCmdLine, &num_args);
655
656 if (!args)
657 return;
658
659 if (num_args >= 1) {
660 HANDLE h, token;
661 LUID luid;
662 TOKEN_PRIVILEGES tp;
663
664 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
665 goto end;
666
667 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid))
668 goto end;
669
670 tp.PrivilegeCount = 1;
671 tp.Privileges[0].Luid = luid;
672 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
673
674 if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
675 goto end;
676
677 CloseHandle(token);
678
679 h = CreateFileW(args[0], FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
680 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
681 if (h != INVALID_HANDLE_VALUE) {
682 IO_STATUS_BLOCK iosb;
683
684 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_STOP_SCRUB, NULL, 0, NULL, 0);
685
686 CloseHandle(h);
687 }
688 }
689
690 end:
691 LocalFree(args);
692 }