[NTDLL] Allow shimdata to override the process manifest.
[reactos.git] / dll / shellext / shellbtrfs / volpropsheet.cpp
1 /* Copyright (c) Mark Harmstone 2016-17
2 *
3 * This file is part of WinBtrfs.
4 *
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
9 *
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17
18 #define ISOLATION_AWARE_ENABLED 1
19 #define STRSAFE_NO_DEPRECATE
20
21 #include "shellext.h"
22 #ifndef __REACTOS__
23 #include <windows.h>
24 #include <strsafe.h>
25 #include <winternl.h>
26 #else
27 #define WIN32_NO_STATUS
28 #include <windef.h>
29 #include <winbase.h>
30 #include <strsafe.h>
31 #include <ndk/iofuncs.h>
32 #include <ndk/iotypes.h>
33 #endif
34
35 #define NO_SHLWAPI_STRFCNS
36 #include <shlwapi.h>
37 #include <uxtheme.h>
38
39 #include "volpropsheet.h"
40 #include "resource.h"
41
42 HRESULT __stdcall BtrfsVolPropSheet::QueryInterface(REFIID riid, void **ppObj) {
43 if (riid == IID_IUnknown || riid == IID_IShellPropSheetExt) {
44 *ppObj = static_cast<IShellPropSheetExt*>(this);
45 AddRef();
46 return S_OK;
47 } else if (riid == IID_IShellExtInit) {
48 *ppObj = static_cast<IShellExtInit*>(this);
49 AddRef();
50 return S_OK;
51 }
52
53 *ppObj = NULL;
54 return E_NOINTERFACE;
55 }
56
57 HRESULT __stdcall BtrfsVolPropSheet::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgID) {
58 HANDLE h;
59 ULONG num_files;
60 FORMATETC format = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
61 HDROP hdrop;
62
63 if (pidlFolder)
64 return E_FAIL;
65
66 if (!pdtobj)
67 return E_FAIL;
68
69 stgm.tymed = TYMED_HGLOBAL;
70
71 if (FAILED(pdtobj->GetData(&format, &stgm)))
72 return E_INVALIDARG;
73
74 stgm_set = TRUE;
75
76 hdrop = (HDROP)GlobalLock(stgm.hGlobal);
77
78 if (!hdrop) {
79 ReleaseStgMedium(&stgm);
80 stgm_set = FALSE;
81 return E_INVALIDARG;
82 }
83
84 num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, NULL, 0);
85
86 if (num_files > 1) {
87 GlobalUnlock(hdrop);
88 return E_FAIL;
89 }
90
91 if (DragQueryFileW((HDROP)stgm.hGlobal, 0, fn, sizeof(fn) / sizeof(MAX_PATH))) {
92 h = CreateFileW(fn, FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
93 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
94
95 if (h != INVALID_HANDLE_VALUE) {
96 NTSTATUS Status;
97 IO_STATUS_BLOCK iosb;
98 ULONG devsize, i;
99
100 i = 0;
101 devsize = 1024;
102
103 devices = (btrfs_device*)malloc(devsize);
104
105 while (TRUE) {
106 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_DEVICES, NULL, 0, devices, devsize);
107 if (Status == STATUS_BUFFER_OVERFLOW) {
108 if (i < 8) {
109 devsize += 1024;
110
111 free(devices);
112 devices = (btrfs_device*)malloc(devsize);
113
114 i++;
115 } else {
116 CloseHandle(h);
117 GlobalUnlock(hdrop);
118 return E_FAIL;
119 }
120 } else
121 break;
122 }
123
124 if (!NT_SUCCESS(Status)) {
125 CloseHandle(h);
126 GlobalUnlock(hdrop);
127 return E_FAIL;
128 }
129
130 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_UUID, NULL, 0, &uuid, sizeof(BTRFS_UUID));
131 uuid_set = NT_SUCCESS(Status);
132
133 ignore = FALSE;
134 balance = new BtrfsBalance(fn);
135
136 CloseHandle(h);
137 } else {
138 GlobalUnlock(hdrop);
139 return E_FAIL;
140 }
141 } else {
142 GlobalUnlock(hdrop);
143 return E_FAIL;
144 }
145
146 GlobalUnlock(hdrop);
147
148 return S_OK;
149 }
150
151 typedef struct {
152 UINT64 dev_id;
153 WCHAR* name;
154 UINT64 alloc;
155 UINT64 size;
156 } dev;
157
158 void BtrfsVolPropSheet::FormatUsage(HWND hwndDlg, WCHAR* s, ULONG size, btrfs_usage* usage) {
159 UINT8 i, j;
160 UINT64 num_devs, k, dev_size, dev_alloc, data_size, data_alloc, metadata_size, metadata_alloc;
161 btrfs_device* bd;
162 dev* devs = NULL;
163 btrfs_usage* bue;
164 WCHAR t[255], u[255], v[255];
165
166 static const UINT64 types[] = { BLOCK_FLAG_DATA, BLOCK_FLAG_DATA | BLOCK_FLAG_METADATA, BLOCK_FLAG_METADATA, BLOCK_FLAG_SYSTEM };
167 static const ULONG typestrings[] = { IDS_USAGE_DATA, IDS_USAGE_MIXED, IDS_USAGE_METADATA, IDS_USAGE_SYSTEM };
168 static const UINT64 duptypes[] = { 0, BLOCK_FLAG_DUPLICATE, BLOCK_FLAG_RAID0, BLOCK_FLAG_RAID1, BLOCK_FLAG_RAID10, BLOCK_FLAG_RAID5, BLOCK_FLAG_RAID6 };
169 static const ULONG dupstrings[] = { IDS_SINGLE, IDS_DUP, IDS_RAID0, IDS_RAID1, IDS_RAID10, IDS_RAID5, IDS_RAID6 };
170
171 s[0] = 0;
172
173 num_devs = 0;
174 bd = devices;
175
176 while (TRUE) {
177 num_devs++;
178
179 if (bd->next_entry > 0)
180 bd = (btrfs_device*)((UINT8*)bd + bd->next_entry);
181 else
182 break;
183 }
184
185 devs = (dev*)malloc(sizeof(dev) * num_devs);
186 memset(devs, 0, sizeof(dev) * num_devs);
187
188 bd = devices;
189 k = 0;
190
191 dev_size = 0;
192
193 while (TRUE) {
194 if (bd->missing) {
195 if (!LoadStringW(module, IDS_MISSING, u, sizeof(u) / sizeof(WCHAR))) {
196 ShowError(hwndDlg, GetLastError());
197 goto end;
198 }
199
200 devs[k].name = (WCHAR*)malloc((wcslen(u) + 1) * sizeof(WCHAR));
201 wcscpy(devs[k].name, u);
202 } else if (bd->device_number == 0xffffffff) {
203 devs[k].name = (WCHAR*)malloc(bd->namelen + sizeof(WCHAR));
204 memcpy(devs[k].name, bd->name, bd->namelen);
205 devs[k].name[bd->namelen / sizeof(WCHAR)] = 0;
206 } else if (bd->partition_number == 0) {
207 if (!LoadStringW(module, IDS_DISK_NUM, u, sizeof(u) / sizeof(WCHAR))) {
208 ShowError(hwndDlg, GetLastError());
209 goto end;
210 }
211
212 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), u, bd->device_number) == STRSAFE_E_INSUFFICIENT_BUFFER)
213 goto end;
214
215 devs[k].name = (WCHAR*)malloc((wcslen(t) + 1) * sizeof(WCHAR));
216 wcscpy(devs[k].name, t);
217 } else {
218 if (!LoadStringW(module, IDS_DISK_PART_NUM, u, sizeof(u) / sizeof(WCHAR))) {
219 ShowError(hwndDlg, GetLastError());
220 goto end;
221 }
222
223 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), u, bd->device_number, bd->partition_number) == STRSAFE_E_INSUFFICIENT_BUFFER)
224 goto end;
225
226 devs[k].name = (WCHAR*)malloc((wcslen(t) + 1) * sizeof(WCHAR));
227 wcscpy(devs[k].name, t);
228 }
229
230 devs[k].dev_id = bd->dev_id;
231 devs[k].alloc = 0;
232 devs[k].size = bd->size;
233
234 dev_size += bd->size;
235
236 k++;
237
238 if (bd->next_entry > 0)
239 bd = (btrfs_device*)((UINT8*)bd + bd->next_entry);
240 else
241 break;
242 }
243
244 dev_alloc = 0;
245 data_size = data_alloc = 0;
246 metadata_size = metadata_alloc = 0;
247
248 bue = usage;
249 while (TRUE) {
250 for (k = 0; k < bue->num_devices; k++) {
251 dev_alloc += bue->devices[k].alloc;
252
253 if (bue->type & BLOCK_FLAG_DATA) {
254 data_alloc += bue->devices[k].alloc;
255 }
256
257 if (bue->type & BLOCK_FLAG_METADATA) {
258 metadata_alloc += bue->devices[k].alloc;
259 }
260 }
261
262 if (bue->type & BLOCK_FLAG_DATA) {
263 data_size += bue->size;
264 }
265
266 if (bue->type & BLOCK_FLAG_METADATA) {
267 metadata_size += bue->size;
268 }
269
270 if (bue->next_entry > 0)
271 bue = (btrfs_usage*)((UINT8*)bue + bue->next_entry);
272 else
273 break;
274 }
275
276 // device size
277
278 if (!LoadStringW(module, IDS_USAGE_DEV_SIZE, u, sizeof(u) / sizeof(WCHAR))) {
279 ShowError(hwndDlg, GetLastError());
280 goto end;
281 }
282
283 format_size(dev_size, v, sizeof(v) / sizeof(WCHAR), FALSE);
284
285 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), u, v) == STRSAFE_E_INSUFFICIENT_BUFFER)
286 goto end;
287
288 if (StringCchCatW(s, size, t) == STRSAFE_E_INSUFFICIENT_BUFFER)
289 goto end;
290
291 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
292 goto end;
293
294 // device allocated
295
296 if (!LoadStringW(module, IDS_USAGE_DEV_ALLOC, u, sizeof(u) / sizeof(WCHAR))) {
297 ShowError(hwndDlg, GetLastError());
298 goto end;
299 }
300
301 format_size(dev_alloc, v, sizeof(v) / sizeof(WCHAR), FALSE);
302
303 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), u, v) == STRSAFE_E_INSUFFICIENT_BUFFER)
304 goto end;
305
306 if (StringCchCatW(s, size, t) == STRSAFE_E_INSUFFICIENT_BUFFER)
307 goto end;
308
309 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
310 goto end;
311
312 // device unallocated
313
314 if (!LoadStringW(module, IDS_USAGE_DEV_UNALLOC, u, sizeof(u) / sizeof(WCHAR))) {
315 ShowError(hwndDlg, GetLastError());
316 goto end;
317 }
318
319 format_size(dev_size - dev_alloc, v, sizeof(v) / sizeof(WCHAR), FALSE);
320
321 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), u, v) == STRSAFE_E_INSUFFICIENT_BUFFER)
322 goto end;
323
324 if (StringCchCatW(s, size, t) == STRSAFE_E_INSUFFICIENT_BUFFER)
325 goto end;
326
327 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
328 goto end;
329
330 // data ratio
331
332 if (data_alloc > 0) {
333 if (!LoadStringW(module, IDS_USAGE_DATA_RATIO, u, sizeof(u) / sizeof(WCHAR))) {
334 ShowError(hwndDlg, GetLastError());
335 goto end;
336 }
337
338 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), u, (float)data_alloc / (float)data_size) == STRSAFE_E_INSUFFICIENT_BUFFER)
339 goto end;
340
341 if (StringCchCatW(s, size, t) == STRSAFE_E_INSUFFICIENT_BUFFER)
342 goto end;
343
344 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
345 goto end;
346 }
347
348 // metadata ratio
349
350 if (!LoadStringW(module, IDS_USAGE_METADATA_RATIO, u, sizeof(u) / sizeof(WCHAR))) {
351 ShowError(hwndDlg, GetLastError());
352 goto end;
353 }
354
355 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), u, (float)metadata_alloc / (float)metadata_size) == STRSAFE_E_INSUFFICIENT_BUFFER)
356 goto end;
357
358 if (StringCchCatW(s, size, t) == STRSAFE_E_INSUFFICIENT_BUFFER)
359 goto end;
360
361 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
362 goto end;
363
364 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
365 goto end;
366
367 for (i = 0; i < sizeof(types) / sizeof(types[0]); i++) {
368 for (j = 0; j < sizeof(duptypes) / sizeof(duptypes[0]); j++) {
369 bue = usage;
370
371 while (TRUE) {
372 if ((bue->type & types[i]) == types[i] &&
373 ((duptypes[j] == 0 && (bue->type & (BLOCK_FLAG_DUPLICATE | BLOCK_FLAG_RAID0 | BLOCK_FLAG_RAID1 | BLOCK_FLAG_RAID10 | BLOCK_FLAG_RAID5 | BLOCK_FLAG_RAID6)) == 0)
374 || bue->type & duptypes[j])) {
375 WCHAR typestring[255], dupstring[255], sizestring[255], usedstring[255];
376
377 if (bue->type & BLOCK_FLAG_DATA && bue->type & BLOCK_FLAG_METADATA && (types[i] == BLOCK_FLAG_DATA || types[i] == BLOCK_FLAG_METADATA))
378 break;
379
380 if (!LoadStringW(module, typestrings[i], typestring, sizeof(typestring) / sizeof(WCHAR))) {
381 ShowError(hwndDlg, GetLastError());
382 goto end;
383 }
384
385 if (!LoadStringW(module, dupstrings[j], dupstring, sizeof(dupstring) / sizeof(WCHAR))) {
386 ShowError(hwndDlg, GetLastError());
387 goto end;
388 }
389
390 format_size(bue->size, sizestring, sizeof(sizestring) / sizeof(WCHAR), FALSE);
391 format_size(bue->used, usedstring, sizeof(usedstring) / sizeof(WCHAR), FALSE);
392
393 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), typestring, dupstring, sizestring, usedstring) == STRSAFE_E_INSUFFICIENT_BUFFER)
394 goto end;
395
396 if (StringCchCatW(s, size, t) == STRSAFE_E_INSUFFICIENT_BUFFER)
397 goto end;
398
399 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
400 goto end;
401
402 for (k = 0; k < bue->num_devices; k++) {
403 UINT64 l;
404 BOOL found = FALSE;
405
406 format_size(bue->devices[k].alloc, sizestring, sizeof(sizestring) / sizeof(WCHAR), FALSE);
407
408 for (l = 0; l < num_devs; l++) {
409 if (devs[l].dev_id == bue->devices[k].dev_id) {
410 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), L"%s\t%s", devs[l].name, sizestring) == STRSAFE_E_INSUFFICIENT_BUFFER)
411 goto end;
412
413 if (StringCchCatW(s, size, t) == STRSAFE_E_INSUFFICIENT_BUFFER)
414 goto end;
415
416 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
417 goto end;
418
419 devs[l].alloc += bue->devices[k].alloc;
420
421 found = TRUE;
422 break;
423 }
424 }
425
426 if (!found) {
427 if (!LoadStringW(module, IDS_UNKNOWN_DEVICE, typestring, sizeof(typestring) / sizeof(WCHAR))) {
428 ShowError(hwndDlg, GetLastError());
429 goto end;
430 }
431
432 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), typestring, bue->devices[k].dev_id) == STRSAFE_E_INSUFFICIENT_BUFFER)
433 goto end;
434
435 if (StringCchCatW(s, size, t) == STRSAFE_E_INSUFFICIENT_BUFFER)
436 goto end;
437
438 if (StringCchCatW(s, size, L"\t") == STRSAFE_E_INSUFFICIENT_BUFFER)
439 goto end;
440
441 if (StringCchCatW(s, size, sizestring) == STRSAFE_E_INSUFFICIENT_BUFFER)
442 goto end;
443
444 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
445 goto end;
446 }
447 }
448
449 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
450 goto end;
451
452 break;
453 }
454
455 if (bue->next_entry > 0)
456 bue = (btrfs_usage*)((UINT8*)bue + bue->next_entry);
457 else
458 break;
459 }
460 }
461 }
462
463 if (!LoadStringW(module, IDS_USAGE_UNALLOC, t, sizeof(t) / sizeof(WCHAR))) {
464 ShowError(hwndDlg, GetLastError());
465 goto end;
466 }
467
468 if (StringCchCatW(s, size, t) == STRSAFE_E_INSUFFICIENT_BUFFER)
469 goto end;
470
471 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
472 goto end;
473
474 for (k = 0; k < num_devs; k++) {
475 WCHAR sizestring[255];
476
477 format_size(devs[k].size - devs[k].alloc, sizestring, sizeof(sizestring) / sizeof(WCHAR), FALSE);
478
479 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), L"%s\t%s", devs[k].name, sizestring) == STRSAFE_E_INSUFFICIENT_BUFFER)
480 goto end;
481
482 if (StringCchCatW(s, size, t) == STRSAFE_E_INSUFFICIENT_BUFFER)
483 goto end;
484
485 if (StringCchCatW(s, size, L"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER)
486 goto end;
487 }
488
489 end:
490 if (devs) {
491 for (k = 0; k < num_devs; k++) {
492 if (devs[k].name) free(devs[k].name);
493 }
494
495 free(devs);
496 }
497 }
498
499 void BtrfsVolPropSheet::RefreshUsage(HWND hwndDlg) {
500 HANDLE h;
501 WCHAR s[4096];
502 btrfs_usage* usage;
503
504 h = CreateFileW(fn, FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
505 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
506
507 if (h != INVALID_HANDLE_VALUE) {
508 NTSTATUS Status;
509 IO_STATUS_BLOCK iosb;
510 ULONG devsize, usagesize, i;
511
512 i = 0;
513 devsize = 1024;
514
515 devices = (btrfs_device*)malloc(devsize);
516
517 while (TRUE) {
518 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_DEVICES, NULL, 0, devices, devsize);
519 if (Status == STATUS_BUFFER_OVERFLOW) {
520 if (i < 8) {
521 devsize += 1024;
522
523 free(devices);
524 devices = (btrfs_device*)malloc(devsize);
525
526 i++;
527 } else
528 return;
529 } else
530 break;
531 }
532
533 if (!NT_SUCCESS(Status)) {
534 CloseHandle(h);
535 return;
536 }
537
538 i = 0;
539 usagesize = 1024;
540
541 usage = (btrfs_usage*)malloc(usagesize);
542
543 while (TRUE) {
544 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_USAGE, NULL, 0, usage, usagesize);
545 if (Status == STATUS_BUFFER_OVERFLOW) {
546 if (i < 8) {
547 usagesize += 1024;
548
549 free(usage);
550 usage = (btrfs_usage*)malloc(usagesize);
551
552 i++;
553 } else
554 return;
555 } else
556 break;
557 }
558
559 if (!NT_SUCCESS(Status)) {
560 free(usage);
561 CloseHandle(h);
562 return;
563 }
564
565 ignore = FALSE;
566
567 CloseHandle(h);
568 } else
569 return;
570
571 FormatUsage(hwndDlg, s, sizeof(s) / sizeof(WCHAR), usage);
572
573 SetDlgItemTextW(hwndDlg, IDC_USAGE_BOX, s);
574
575 free(usage);
576 }
577
578 INT_PTR CALLBACK BtrfsVolPropSheet::UsageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
579 switch (uMsg) {
580 case WM_INITDIALOG:
581 {
582 WCHAR s[4096];
583 int i;
584 ULONG usagesize;
585 NTSTATUS Status;
586 HANDLE h;
587 IO_STATUS_BLOCK iosb;
588
589 EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
590
591 h = CreateFileW(fn, FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
592 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
593
594 if (h != INVALID_HANDLE_VALUE) {
595 btrfs_usage* usage;
596
597 i = 0;
598 usagesize = 1024;
599
600 usage = (btrfs_usage*)malloc(usagesize);
601
602 while (TRUE) {
603 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_USAGE, NULL, 0, usage, usagesize);
604 if (Status == STATUS_BUFFER_OVERFLOW) {
605 if (i < 8) {
606 usagesize += 1024;
607
608 free(usage);
609 usage = (btrfs_usage*)malloc(usagesize);
610
611 i++;
612 } else
613 break;
614 } else
615 break;
616 }
617
618 if (!NT_SUCCESS(Status)) {
619 free(usage);
620 CloseHandle(h);
621 break;
622 }
623
624 CloseHandle(h);
625
626 FormatUsage(hwndDlg, s, sizeof(s) / sizeof(WCHAR), usage);
627
628 SetDlgItemTextW(hwndDlg, IDC_USAGE_BOX, s);
629
630 free(usage);
631 }
632
633 break;
634 }
635
636 case WM_COMMAND:
637 switch (HIWORD(wParam)) {
638 case BN_CLICKED:
639 switch (LOWORD(wParam)) {
640 case IDOK:
641 case IDCANCEL:
642 EndDialog(hwndDlg, 0);
643 return TRUE;
644
645 case IDC_USAGE_REFRESH:
646 RefreshUsage(hwndDlg);
647 return TRUE;
648 }
649 break;
650 }
651 break;
652 }
653
654 return FALSE;
655 }
656
657 static INT_PTR CALLBACK stub_UsageDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
658 BtrfsVolPropSheet* bvps;
659
660 if (uMsg == WM_INITDIALOG) {
661 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
662 bvps = (BtrfsVolPropSheet*)lParam;
663 } else {
664 bvps = (BtrfsVolPropSheet*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
665 }
666
667 if (bvps)
668 return bvps->UsageDlgProc(hwndDlg, uMsg, wParam, lParam);
669 else
670 return FALSE;
671 }
672
673 void BtrfsVolPropSheet::ShowUsage(HWND hwndDlg) {
674 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_VOL_USAGE), hwndDlg, stub_UsageDlgProc, (LPARAM)this);
675 }
676
677 static void add_lv_column(HWND list, int string, int cx) {
678 LVCOLUMNW lvc;
679 WCHAR s[255];
680
681 if (!LoadStringW(module, string, s, sizeof(s) / sizeof(WCHAR))) {
682 ShowError(GetParent(list), GetLastError());
683 return;
684 }
685
686 lvc.mask = LVCF_TEXT|LVCF_WIDTH;
687 lvc.pszText = s;
688 lvc.cx = cx;
689 SendMessageW(list, LVM_INSERTCOLUMNW, 0, (LPARAM)&lvc);
690 }
691
692 static int CALLBACK lv_sort(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) {
693 if (lParam1 < lParam2)
694 return -1;
695 else if (lParam1 > lParam2)
696 return 1;
697 else
698 return 0;
699 }
700
701 static UINT64 find_dev_alloc(UINT64 dev_id, btrfs_usage* usage) {
702 btrfs_usage* bue;
703 UINT64 alloc;
704
705 alloc = 0;
706
707 bue = usage;
708 while (TRUE) {
709 UINT64 k;
710
711 for (k = 0; k < bue->num_devices; k++) {
712 if (bue->devices[k].dev_id == dev_id)
713 alloc += bue->devices[k].alloc;
714 }
715
716 if (bue->next_entry > 0)
717 bue = (btrfs_usage*)((UINT8*)bue + bue->next_entry);
718 else
719 break;
720 }
721
722 return alloc;
723 }
724
725 void BtrfsVolPropSheet::RefreshDevList(HWND devlist) {
726 HANDLE h;
727 NTSTATUS Status;
728 IO_STATUS_BLOCK iosb;
729 ULONG usagesize, devsize;
730 btrfs_usage* usage;
731 btrfs_device* bd;
732 int i;
733 UINT64 num_rw_devices;
734
735 h = CreateFileW(fn, FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
736 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
737
738 if (h == INVALID_HANDLE_VALUE) {
739 ShowError(GetParent(devlist), GetLastError());
740 return;
741 }
742
743 i = 0;
744 devsize = 1024;
745
746 if (devices)
747 free(devices);
748
749 devices = (btrfs_device*)malloc(devsize);
750
751 while (TRUE) {
752 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_DEVICES, NULL, 0, devices, devsize);
753 if (Status == STATUS_BUFFER_OVERFLOW) {
754 if (i < 8) {
755 devsize += 1024;
756
757 free(devices);
758 devices = (btrfs_device*)malloc(devsize);
759
760 i++;
761 } else
762 return;
763 } else
764 break;
765 }
766
767 if (!NT_SUCCESS(Status)) {
768 CloseHandle(h);
769 return;
770 }
771
772 bd = devices;
773
774 i = 0;
775 usagesize = 1024;
776
777 usage = (btrfs_usage*)malloc(usagesize);
778
779 while (TRUE) {
780 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_USAGE, NULL, 0, usage, usagesize);
781 if (Status == STATUS_BUFFER_OVERFLOW) {
782 if (i < 8) {
783 usagesize += 1024;
784
785 free(usage);
786 usage = (btrfs_usage*)malloc(usagesize);
787
788 i++;
789 } else {
790 free(usage);
791 CloseHandle(h);
792 return;
793 }
794 } else
795 break;
796 }
797
798 if (!NT_SUCCESS(Status)) {
799 free(usage);
800 CloseHandle(h);
801 return;
802 }
803
804 CloseHandle(h);
805
806 SendMessageW(devlist, LVM_DELETEALLITEMS, 0, 0);
807
808 num_rw_devices = 0;
809
810 i = 0;
811 while (TRUE) {
812 LVITEMW lvi;
813 WCHAR s[255], u[255];
814 UINT64 alloc;
815
816 // ID
817
818 RtlZeroMemory(&lvi, sizeof(LVITEMW));
819 lvi.mask = LVIF_TEXT | LVIF_PARAM;
820 lvi.iItem = SendMessageW(devlist, LVM_GETITEMCOUNT, 0, 0);
821 lvi.lParam = bd->dev_id;
822
823 StringCchPrintfW(s, sizeof(s) / sizeof(WCHAR), L"%llu", bd->dev_id);
824 lvi.pszText = s;
825
826 SendMessageW(devlist, LVM_INSERTITEMW, 0, (LPARAM)&lvi);
827
828 // description
829
830 lvi.mask = LVIF_TEXT;
831 lvi.iSubItem = 1;
832
833 if (bd->missing) {
834 if (!LoadStringW(module, IDS_MISSING, u, sizeof(u) / sizeof(WCHAR))) {
835 ShowError(GetParent(devlist), GetLastError());
836 break;
837 }
838
839 wcscpy(s, u);
840 } else if (bd->device_number == 0xffffffff) {
841 memcpy(s, bd->name, bd->namelen);
842 s[bd->namelen / sizeof(WCHAR)] = 0;
843 } else if (bd->partition_number == 0) {
844 if (!LoadStringW(module, IDS_DISK_NUM, u, sizeof(u) / sizeof(WCHAR))) {
845 ShowError(GetParent(devlist), GetLastError());
846 break;
847 }
848
849 if (StringCchPrintfW(s, sizeof(s) / sizeof(WCHAR), u, bd->device_number) == STRSAFE_E_INSUFFICIENT_BUFFER)
850 break;
851 } else {
852 if (!LoadStringW(module, IDS_DISK_PART_NUM, u, sizeof(u) / sizeof(WCHAR))) {
853 ShowError(GetParent(devlist), GetLastError());
854 break;
855 }
856
857 if (StringCchPrintfW(s, sizeof(s) / sizeof(WCHAR), u, bd->device_number, bd->partition_number) == STRSAFE_E_INSUFFICIENT_BUFFER)
858 break;
859 }
860
861 lvi.pszText = s;
862
863 SendMessageW(devlist, LVM_SETITEMW, 0, (LPARAM)&lvi);
864
865 // readonly
866
867 lvi.iSubItem = 2;
868 LoadStringW(module, bd->readonly ? IDS_DEVLIST_READONLY_YES : IDS_DEVLIST_READONLY_NO, s, sizeof(s) / sizeof(WCHAR));
869 lvi.pszText = s;
870 SendMessageW(devlist, LVM_SETITEMW, 0, (LPARAM)&lvi);
871
872 if (!bd->readonly)
873 num_rw_devices++;
874
875 // size
876
877 lvi.iSubItem = 3;
878 format_size(bd->size, s, sizeof(s) / sizeof(WCHAR), FALSE);
879 lvi.pszText = s;
880 SendMessageW(devlist, LVM_SETITEMW, 0, (LPARAM)&lvi);
881
882 // alloc
883
884 alloc = find_dev_alloc(bd->dev_id, usage);
885
886 lvi.iSubItem = 4;
887 format_size(alloc, s, sizeof(s) / sizeof(WCHAR), FALSE);
888 lvi.pszText = s;
889 SendMessageW(devlist, LVM_SETITEMW, 0, (LPARAM)&lvi);
890
891 // alloc %
892
893 StringCchPrintfW(s, sizeof(s) / sizeof(WCHAR), L"%1.1f%%", (float)alloc * 100.0f / (float)bd->size);
894 lvi.iSubItem = 5;
895 lvi.pszText = s;
896 SendMessageW(devlist, LVM_SETITEMW, 0, (LPARAM)&lvi);
897
898 i++;
899
900 if (bd->next_entry > 0)
901 bd = (btrfs_device*)((UINT8*)bd + bd->next_entry);
902 else
903 break;
904 }
905
906 free(usage);
907
908 SendMessageW(devlist, LVM_SORTITEMS, 0, (LPARAM)lv_sort);
909
910 EnableWindow(GetDlgItem(GetParent(devlist), IDC_DEVICE_ADD), num_rw_devices > 0);
911 EnableWindow(GetDlgItem(GetParent(devlist), IDC_DEVICE_REMOVE), num_rw_devices > 1);
912 }
913
914 void BtrfsVolPropSheet::ResetStats(HWND hwndDlg) {
915 HANDLE h;
916 WCHAR t[MAX_PATH + 100], sel[10];
917 SHELLEXECUTEINFOW sei;
918
919 _itow(stats_dev, sel, 10);
920
921 t[0] = '"';
922 GetModuleFileNameW(module, t + 1, (sizeof(t) / sizeof(WCHAR)) - 1);
923 wcscat(t, L"\",ResetStats ");
924 wcscat(t, fn);
925 wcscat(t, L"|");
926 wcscat(t, sel);
927
928 RtlZeroMemory(&sei, sizeof(sei));
929
930 sei.cbSize = sizeof(sei);
931 sei.hwnd = hwndDlg;
932 sei.lpVerb = L"runas";
933 sei.lpFile = L"rundll32.exe";
934 sei.lpParameters = t;
935 sei.nShow = SW_SHOW;
936 sei.fMask = SEE_MASK_NOCLOSEPROCESS;
937
938 if (!ShellExecuteExW(&sei)) {
939 ShowError(hwndDlg, GetLastError());
940 return;
941 }
942
943 WaitForSingleObject(sei.hProcess, INFINITE);
944 CloseHandle(sei.hProcess);
945
946 h = CreateFileW(fn, FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
947 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
948
949 if (h != INVALID_HANDLE_VALUE) {
950 NTSTATUS Status;
951 IO_STATUS_BLOCK iosb;
952 ULONG devsize, i;
953
954 i = 0;
955 devsize = 1024;
956
957 free(devices);
958 devices = (btrfs_device*)malloc(devsize);
959
960 while (TRUE) {
961 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_DEVICES, NULL, 0, devices, devsize);
962 if (Status == STATUS_BUFFER_OVERFLOW) {
963 if (i < 8) {
964 devsize += 1024;
965
966 free(devices);
967 devices = (btrfs_device*)malloc(devsize);
968
969 i++;
970 } else
971 break;
972 } else
973 break;
974 }
975
976 CloseHandle(h);
977 }
978
979 EndDialog(hwndDlg, 0);
980 }
981
982 INT_PTR CALLBACK BtrfsVolPropSheet::StatsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
983 switch (uMsg) {
984 case WM_INITDIALOG:
985 {
986 WCHAR s[255], t[255];
987 btrfs_device *bd, *dev = NULL;
988 int i;
989
990 static int stat_ids[] = { IDC_WRITE_ERRS, IDC_READ_ERRS, IDC_FLUSH_ERRS, IDC_CORRUPTION_ERRS, IDC_GENERATION_ERRS };
991
992 bd = devices;
993
994 while (TRUE) {
995 if (bd->dev_id == stats_dev) {
996 dev = bd;
997 break;
998 }
999
1000 if (bd->next_entry > 0)
1001 bd = (btrfs_device*)((UINT8*)bd + bd->next_entry);
1002 else
1003 break;
1004 }
1005
1006 if (!dev) {
1007 EndDialog(hwndDlg, 0);
1008 ShowStringError(hwndDlg, IDS_CANNOT_FIND_DEVICE);
1009 return FALSE;
1010 }
1011
1012 GetDlgItemTextW(hwndDlg, IDC_DEVICE_ID, s, sizeof(s) / sizeof(WCHAR));
1013
1014 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), s, dev->dev_id) == STRSAFE_E_INSUFFICIENT_BUFFER)
1015 return FALSE;
1016
1017 SetDlgItemTextW(hwndDlg, IDC_DEVICE_ID, t);
1018
1019 for (i = 0; i < 5; i++) {
1020 GetDlgItemTextW(hwndDlg, stat_ids[i], s, sizeof(s) / sizeof(WCHAR));
1021
1022 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), s, dev->stats[i]) == STRSAFE_E_INSUFFICIENT_BUFFER)
1023 return FALSE;
1024
1025 SetDlgItemTextW(hwndDlg, stat_ids[i], t);
1026 }
1027
1028 SendMessageW(GetDlgItem(hwndDlg, IDC_RESET_STATS), BCM_SETSHIELD, 0, TRUE);
1029 EnableWindow(GetDlgItem(hwndDlg, IDC_RESET_STATS), !readonly);
1030
1031 break;
1032 }
1033
1034 case WM_COMMAND:
1035 switch (HIWORD(wParam)) {
1036 case BN_CLICKED:
1037 switch (LOWORD(wParam)) {
1038 case IDOK:
1039 case IDCANCEL:
1040 EndDialog(hwndDlg, 0);
1041 return TRUE;
1042
1043 case IDC_RESET_STATS:
1044 ResetStats(hwndDlg);
1045 return TRUE;
1046 }
1047 break;
1048 }
1049 break;
1050 }
1051
1052 return FALSE;
1053 }
1054
1055 static INT_PTR CALLBACK stub_StatsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
1056 BtrfsVolPropSheet* bvps;
1057
1058 if (uMsg == WM_INITDIALOG) {
1059 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
1060 bvps = (BtrfsVolPropSheet*)lParam;
1061 } else {
1062 bvps = (BtrfsVolPropSheet*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1063 }
1064
1065 if (bvps)
1066 return bvps->StatsDlgProc(hwndDlg, uMsg, wParam, lParam);
1067 else
1068 return FALSE;
1069 }
1070
1071 void BtrfsVolPropSheet::ShowStats(HWND hwndDlg, UINT64 devid) {
1072 stats_dev = devid;
1073
1074 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_DEVICE_STATS), hwndDlg, stub_StatsDlgProc, (LPARAM)this);
1075 }
1076
1077 INT_PTR CALLBACK BtrfsVolPropSheet::DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
1078 switch (uMsg) {
1079 case WM_INITDIALOG:
1080 {
1081 HWND devlist;
1082 RECT rect;
1083 ULONG w;
1084
1085 EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
1086
1087 devlist = GetDlgItem(hwndDlg, IDC_DEVLIST);
1088
1089 GetClientRect(devlist, &rect);
1090 w = rect.right - rect.left;
1091
1092 add_lv_column(devlist, IDS_DEVLIST_ALLOC_PC, w * 5 / 44);
1093 add_lv_column(devlist, IDS_DEVLIST_ALLOC, w * 6 / 44);
1094 add_lv_column(devlist, IDS_DEVLIST_SIZE, w * 6 / 44);
1095 add_lv_column(devlist, IDS_DEVLIST_READONLY, w * 7 / 44);
1096 add_lv_column(devlist, IDS_DEVLIST_DESC, w * 16 / 44);
1097 add_lv_column(devlist, IDS_DEVLIST_ID, w * 4 / 44);
1098
1099 SendMessageW(GetDlgItem(hwndDlg, IDC_DEVICE_ADD), BCM_SETSHIELD, 0, TRUE);
1100 SendMessageW(GetDlgItem(hwndDlg, IDC_DEVICE_REMOVE), BCM_SETSHIELD, 0, TRUE);
1101 SendMessageW(GetDlgItem(hwndDlg, IDC_DEVICE_RESIZE), BCM_SETSHIELD, 0, TRUE);
1102
1103 RefreshDevList(devlist);
1104
1105 break;
1106 }
1107
1108 case WM_COMMAND:
1109 switch (HIWORD(wParam)) {
1110 case BN_CLICKED:
1111 switch (LOWORD(wParam)) {
1112 case IDOK:
1113 case IDCANCEL:
1114 KillTimer(hwndDlg, 1);
1115 EndDialog(hwndDlg, 0);
1116 return TRUE;
1117
1118 case IDC_DEVICE_ADD:
1119 {
1120 WCHAR t[MAX_PATH + 100];
1121 SHELLEXECUTEINFOW sei;
1122
1123 t[0] = '"';
1124 GetModuleFileNameW(module, t + 1, (sizeof(t) / sizeof(WCHAR)) - 1);
1125 wcscat(t, L"\",AddDevice ");
1126 wcscat(t, fn);
1127
1128 RtlZeroMemory(&sei, sizeof(sei));
1129
1130 sei.cbSize = sizeof(sei);
1131 sei.hwnd = hwndDlg;
1132 sei.lpVerb = L"runas";
1133 sei.lpFile = L"rundll32.exe";
1134 sei.lpParameters = t;
1135 sei.nShow = SW_SHOW;
1136 sei.fMask = SEE_MASK_NOCLOSEPROCESS;
1137
1138 if (!ShellExecuteExW(&sei)) {
1139 ShowError(hwndDlg, GetLastError());
1140 return TRUE;
1141 }
1142
1143 WaitForSingleObject(sei.hProcess, INFINITE);
1144 CloseHandle(sei.hProcess);
1145
1146 RefreshDevList(GetDlgItem(hwndDlg, IDC_DEVLIST));
1147
1148 return TRUE;
1149 }
1150
1151 case IDC_DEVICE_REFRESH:
1152 RefreshDevList(GetDlgItem(hwndDlg, IDC_DEVLIST));
1153 return TRUE;
1154
1155 case IDC_DEVICE_SHOW_STATS:
1156 {
1157 WCHAR sel[MAX_PATH];
1158 HWND devlist;
1159 int index;
1160 LVITEMW lvi;
1161
1162 devlist = GetDlgItem(hwndDlg, IDC_DEVLIST);
1163
1164 index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
1165
1166 if (index == -1)
1167 return TRUE;
1168
1169 RtlZeroMemory(&lvi, sizeof(LVITEMW));
1170 lvi.mask = LVIF_TEXT;
1171 lvi.iItem = index;
1172 lvi.iSubItem = 0;
1173 lvi.pszText = sel;
1174 lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR);
1175 SendMessageW(devlist, LVM_GETITEMW, 0, (LPARAM)&lvi);
1176
1177 ShowStats(hwndDlg, _wtoi(sel));
1178 return TRUE;
1179 }
1180
1181 case IDC_DEVICE_REMOVE:
1182 {
1183 WCHAR t[2*MAX_PATH + 100], sel[MAX_PATH], sel2[MAX_PATH], mess[255], mess2[255], title[255];
1184 HWND devlist;
1185 SHELLEXECUTEINFOW sei;
1186 int index;
1187 LVITEMW lvi;
1188
1189 devlist = GetDlgItem(hwndDlg, IDC_DEVLIST);
1190
1191 index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
1192
1193 if (index == -1)
1194 return TRUE;
1195
1196 RtlZeroMemory(&lvi, sizeof(LVITEMW));
1197 lvi.mask = LVIF_TEXT;
1198 lvi.iItem = index;
1199 lvi.iSubItem = 0;
1200 lvi.pszText = sel;
1201 lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR);
1202 SendMessageW(devlist, LVM_GETITEMW, 0, (LPARAM)&lvi);
1203
1204 lvi.iSubItem = 1;
1205 lvi.pszText = sel2;
1206 lvi.cchTextMax = sizeof(sel2) / sizeof(WCHAR);
1207 SendMessageW(devlist, LVM_GETITEMW, 0, (LPARAM)&lvi);
1208
1209 if (!LoadStringW(module, IDS_REMOVE_DEVICE_CONFIRMATION, mess, sizeof(mess) / sizeof(WCHAR))) {
1210 ShowError(hwndDlg, GetLastError());
1211 return TRUE;
1212 }
1213
1214 if (StringCchPrintfW(mess2, sizeof(mess2) / sizeof(WCHAR), mess, sel, sel2) == STRSAFE_E_INSUFFICIENT_BUFFER)
1215 return TRUE;
1216
1217 if (!LoadStringW(module, IDS_CONFIRMATION_TITLE, title, sizeof(title) / sizeof(WCHAR))) {
1218 ShowError(hwndDlg, GetLastError());
1219 return TRUE;
1220 }
1221
1222 if (MessageBoxW(hwndDlg, mess2, title, MB_YESNO) != IDYES)
1223 return TRUE;
1224
1225 t[0] = '"';
1226 GetModuleFileNameW(module, t + 1, (sizeof(t) / sizeof(WCHAR)) - 1);
1227 wcscat(t, L"\",RemoveDevice ");
1228 wcscat(t, fn);
1229 wcscat(t, L"|");
1230 wcscat(t, sel);
1231
1232 RtlZeroMemory(&sei, sizeof(sei));
1233
1234 sei.cbSize = sizeof(sei);
1235 sei.hwnd = hwndDlg;
1236 sei.lpVerb = L"runas";
1237 sei.lpFile = L"rundll32.exe";
1238 sei.lpParameters = t;
1239 sei.nShow = SW_SHOW;
1240 sei.fMask = SEE_MASK_NOCLOSEPROCESS;
1241
1242 if (!ShellExecuteExW(&sei)) {
1243 ShowError(hwndDlg, GetLastError());
1244 return TRUE;
1245 }
1246
1247 WaitForSingleObject(sei.hProcess, INFINITE);
1248 CloseHandle(sei.hProcess);
1249
1250 RefreshDevList(GetDlgItem(hwndDlg, IDC_DEVLIST));
1251
1252 return TRUE;
1253 }
1254
1255 case IDC_DEVICE_RESIZE:
1256 {
1257 HWND devlist;
1258 int index;
1259 LVITEMW lvi;
1260 WCHAR sel[100], t[2*MAX_PATH + 100];
1261 SHELLEXECUTEINFOW sei;
1262
1263 devlist = GetDlgItem(hwndDlg, IDC_DEVLIST);
1264
1265 index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
1266
1267 if (index == -1)
1268 return TRUE;
1269
1270 RtlZeroMemory(&lvi, sizeof(LVITEMW));
1271 lvi.mask = LVIF_TEXT;
1272 lvi.iItem = index;
1273 lvi.iSubItem = 0;
1274 lvi.pszText = sel;
1275 lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR);
1276 SendMessageW(devlist, LVM_GETITEMW, 0, (LPARAM)&lvi);
1277
1278 t[0] = '"';
1279 GetModuleFileNameW(module, t + 1, (sizeof(t) / sizeof(WCHAR)) - 1);
1280 wcscat(t, L"\",ResizeDevice ");
1281 wcscat(t, fn);
1282 wcscat(t, L"|");
1283 wcscat(t, sel);
1284
1285 RtlZeroMemory(&sei, sizeof(sei));
1286
1287 sei.cbSize = sizeof(sei);
1288 sei.hwnd = hwndDlg;
1289 sei.lpVerb = L"runas";
1290 sei.lpFile = L"rundll32.exe";
1291 sei.lpParameters = t;
1292 sei.nShow = SW_SHOW;
1293 sei.fMask = SEE_MASK_NOCLOSEPROCESS;
1294
1295 if (!ShellExecuteExW(&sei)) {
1296 ShowError(hwndDlg, GetLastError());
1297 return TRUE;
1298 }
1299
1300 WaitForSingleObject(sei.hProcess, INFINITE);
1301 CloseHandle(sei.hProcess);
1302
1303 RefreshDevList(GetDlgItem(hwndDlg, IDC_DEVLIST));
1304 }
1305 }
1306 break;
1307 }
1308 break;
1309
1310 case WM_NOTIFY:
1311 switch (((LPNMHDR)lParam)->code) {
1312 case LVN_ITEMCHANGED:
1313 {
1314 NMLISTVIEW* nmv = (NMLISTVIEW*)lParam;
1315
1316 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_SHOW_STATS), nmv->uNewState & LVIS_SELECTED);
1317
1318 if (nmv->uNewState & LVIS_SELECTED && !readonly) {
1319 HWND devlist;
1320 btrfs_device* bd;
1321 BOOL device_readonly = FALSE;
1322 LVITEMW lvi;
1323 WCHAR sel[MAX_PATH];
1324 UINT64 devid;
1325
1326 devlist = GetDlgItem(hwndDlg, IDC_DEVLIST);
1327
1328 RtlZeroMemory(&lvi, sizeof(LVITEMW));
1329 lvi.mask = LVIF_TEXT;
1330 lvi.iItem = nmv->iItem;
1331 lvi.iSubItem = 0;
1332 lvi.pszText = sel;
1333 lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR);
1334 SendMessageW(devlist, LVM_GETITEMW, 0, (LPARAM)&lvi);
1335 devid = _wtoi(sel);
1336
1337 bd = devices;
1338
1339 while (TRUE) {
1340 if (bd->dev_id == devid) {
1341 device_readonly = bd->readonly;
1342 break;
1343 }
1344
1345 if (bd->next_entry > 0)
1346 bd = (btrfs_device*)((UINT8*)bd + bd->next_entry);
1347 else
1348 break;
1349 }
1350
1351 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_RESIZE), !device_readonly);
1352 } else
1353 EnableWindow(GetDlgItem(hwndDlg, IDC_DEVICE_RESIZE), FALSE);
1354
1355 break;
1356 }
1357 }
1358 break;
1359 }
1360
1361 return FALSE;
1362 }
1363
1364 static INT_PTR CALLBACK stub_DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
1365 BtrfsVolPropSheet* bvps;
1366
1367 if (uMsg == WM_INITDIALOG) {
1368 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
1369 bvps = (BtrfsVolPropSheet*)lParam;
1370 } else {
1371 bvps = (BtrfsVolPropSheet*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1372 }
1373
1374 if (bvps)
1375 return bvps->DeviceDlgProc(hwndDlg, uMsg, wParam, lParam);
1376 else
1377 return FALSE;
1378 }
1379
1380 void BtrfsVolPropSheet::ShowDevices(HWND hwndDlg) {
1381 DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_DEVICES), hwndDlg, stub_DeviceDlgProc, (LPARAM)this);
1382 }
1383
1384 void BtrfsVolPropSheet::ShowScrub(HWND hwndDlg) {
1385 WCHAR t[MAX_PATH + 100];
1386 SHELLEXECUTEINFOW sei;
1387
1388 t[0] = '"';
1389 GetModuleFileNameW(module, t + 1, (sizeof(t) / sizeof(WCHAR)) - 1);
1390 wcscat(t, L"\",ShowScrub ");
1391 wcscat(t, fn);
1392
1393 RtlZeroMemory(&sei, sizeof(sei));
1394
1395 sei.cbSize = sizeof(sei);
1396 sei.hwnd = hwndDlg;
1397 sei.lpVerb = L"runas";
1398 sei.lpFile = L"rundll32.exe";
1399 sei.lpParameters = t;
1400 sei.nShow = SW_SHOW;
1401 sei.fMask = SEE_MASK_NOCLOSEPROCESS;
1402
1403 if (!ShellExecuteExW(&sei)) {
1404 ShowError(hwndDlg, GetLastError());
1405 return;
1406 }
1407
1408 WaitForSingleObject(sei.hProcess, INFINITE);
1409 CloseHandle(sei.hProcess);
1410 }
1411
1412 static INT_PTR CALLBACK PropSheetDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
1413 switch (uMsg) {
1414 case WM_INITDIALOG:
1415 {
1416 PROPSHEETPAGE* psp = (PROPSHEETPAGE*)lParam;
1417 BtrfsVolPropSheet* bps = (BtrfsVolPropSheet*)psp->lParam;
1418 btrfs_device* bd;
1419
1420 EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
1421
1422 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)bps);
1423
1424 bps->readonly = TRUE;
1425 bd = bps->devices;
1426
1427 while (TRUE) {
1428 if (!bd->readonly) {
1429 bps->readonly = FALSE;
1430 break;
1431 }
1432
1433 if (bd->next_entry > 0)
1434 bd = (btrfs_device*)((UINT8*)bd + bd->next_entry);
1435 else
1436 break;
1437 }
1438
1439 if (bps->uuid_set) {
1440 WCHAR s[255], t[255];
1441
1442 GetDlgItemTextW(hwndDlg, IDC_UUID, s, sizeof(s) / sizeof(WCHAR));
1443
1444 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), s,
1445 bps->uuid.uuid[0], bps->uuid.uuid[1], bps->uuid.uuid[2], bps->uuid.uuid[3], bps->uuid.uuid[4], bps->uuid.uuid[5], bps->uuid.uuid[6], bps->uuid.uuid[7],
1446 bps->uuid.uuid[8], bps->uuid.uuid[9], bps->uuid.uuid[10], bps->uuid.uuid[11], bps->uuid.uuid[12], bps->uuid.uuid[13], bps->uuid.uuid[14], bps->uuid.uuid[15]
1447 ) != STRSAFE_E_INSUFFICIENT_BUFFER)
1448 SetDlgItemTextW(hwndDlg, IDC_UUID, t);
1449 else
1450 SetDlgItemTextW(hwndDlg, IDC_UUID, L"");
1451 } else
1452 SetDlgItemTextW(hwndDlg, IDC_UUID, L"");
1453
1454 SendMessageW(GetDlgItem(hwndDlg, IDC_VOL_SCRUB), BCM_SETSHIELD, 0, TRUE);
1455
1456 return FALSE;
1457 }
1458
1459 case WM_NOTIFY:
1460 {
1461 switch (((LPNMHDR)lParam)->code) {
1462 case PSN_KILLACTIVE:
1463 SetWindowLongPtrW(hwndDlg, DWLP_MSGRESULT, FALSE);
1464 break;
1465 }
1466 break;
1467 }
1468
1469 case WM_COMMAND:
1470 {
1471 BtrfsVolPropSheet* bps = (BtrfsVolPropSheet*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1472
1473 if (bps) {
1474 switch (HIWORD(wParam)) {
1475 case BN_CLICKED: {
1476 switch (LOWORD(wParam)) {
1477 case IDC_VOL_SHOW_USAGE:
1478 bps->ShowUsage(hwndDlg);
1479 break;
1480
1481 case IDC_VOL_BALANCE:
1482 bps->balance->ShowBalance(hwndDlg);
1483 break;
1484
1485 case IDC_VOL_DEVICES:
1486 bps->ShowDevices(hwndDlg);
1487 break;
1488
1489 case IDC_VOL_SCRUB:
1490 bps->ShowScrub(hwndDlg);
1491 break;
1492 }
1493 }
1494 }
1495 }
1496
1497 break;
1498 }
1499 }
1500
1501 return FALSE;
1502 }
1503
1504 HRESULT __stdcall BtrfsVolPropSheet::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) {
1505 PROPSHEETPAGE psp;
1506 HPROPSHEETPAGE hPage;
1507 INITCOMMONCONTROLSEX icex;
1508
1509 if (ignore)
1510 return S_OK;
1511
1512 icex.dwSize = sizeof(icex);
1513 icex.dwICC = ICC_LINK_CLASS;
1514
1515 if (!InitCommonControlsEx(&icex))
1516 MessageBoxW(NULL, L"InitCommonControlsEx failed", L"Error", MB_ICONERROR);
1517
1518 psp.dwSize = sizeof(psp);
1519 psp.dwFlags = PSP_USEREFPARENT | PSP_USETITLE;
1520 psp.hInstance = module;
1521 psp.pszTemplate = MAKEINTRESOURCE(IDD_VOL_PROP_SHEET);
1522 psp.hIcon = 0;
1523 psp.pszTitle = MAKEINTRESOURCE(IDS_VOL_PROP_SHEET_TITLE);
1524 psp.pfnDlgProc = (DLGPROC)PropSheetDlgProc;
1525 psp.pcRefParent = (UINT*)&objs_loaded;
1526 psp.pfnCallback = NULL;
1527 psp.lParam = (LPARAM)this;
1528
1529 hPage = CreatePropertySheetPage(&psp);
1530
1531 if (hPage) {
1532 if (pfnAddPage(hPage, lParam)) {
1533 this->AddRef();
1534 return S_OK;
1535 } else
1536 DestroyPropertySheetPage(hPage);
1537 } else
1538 return E_OUTOFMEMORY;
1539
1540 return E_FAIL;
1541 }
1542
1543 HRESULT __stdcall BtrfsVolPropSheet::ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE pfnReplacePage, LPARAM lParam) {
1544 return S_OK;
1545 }
1546
1547 #ifdef __cplusplus
1548 extern "C" {
1549 #endif
1550
1551 void CALLBACK ResetStatsW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
1552 HANDLE token, h;
1553 NTSTATUS Status;
1554 TOKEN_PRIVILEGES tp;
1555 LUID luid;
1556 UINT64 devid;
1557 WCHAR *s, *vol, *dev;
1558 IO_STATUS_BLOCK iosb;
1559
1560 set_dpi_aware();
1561
1562 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
1563 ShowError(hwnd, GetLastError());
1564 return;
1565 }
1566
1567 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) {
1568 ShowError(hwnd, GetLastError());
1569 goto end;
1570 }
1571
1572 tp.PrivilegeCount = 1;
1573 tp.Privileges[0].Luid = luid;
1574 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
1575
1576 if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
1577 ShowError(hwnd, GetLastError());
1578 goto end;
1579 }
1580
1581 s = wcsstr(lpszCmdLine, L"|");
1582 if (!s)
1583 goto end;
1584
1585 s[0] = 0;
1586
1587 vol = lpszCmdLine;
1588 dev = &s[1];
1589
1590 devid = _wtoi(dev);
1591 if (devid == 0)
1592 goto end;
1593
1594 h = CreateFileW(vol, FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
1595 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
1596
1597 if (h == INVALID_HANDLE_VALUE) {
1598 ShowError(hwnd, GetLastError());
1599 goto end;
1600 }
1601
1602 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_RESET_STATS, &devid, sizeof(UINT64), NULL, 0);
1603 if (!NT_SUCCESS(Status)) {
1604 ShowNtStatusError(hwnd, Status);
1605
1606 CloseHandle(h);
1607 goto end;
1608 }
1609
1610 CloseHandle(h);
1611
1612 end:
1613 CloseHandle(token);
1614 }
1615
1616 #ifdef __cplusplus
1617 }
1618 #endif