1 /* Copyright (c) Mark Harmstone 2016-17
3 * This file is part of WinBtrfs.
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
18 #define ISOLATION_AWARE_ENABLED 1
19 #define STRSAFE_NO_DEPRECATE
27 #define WIN32_NO_STATUS
31 #include <ndk/iofuncs.h>
32 #include <ndk/iotypes.h>
35 #define NO_SHLWAPI_STRFCNS
39 #include "volpropsheet.h"
42 HRESULT __stdcall
BtrfsVolPropSheet::QueryInterface(REFIID riid
, void **ppObj
) {
43 if (riid
== IID_IUnknown
|| riid
== IID_IShellPropSheetExt
) {
44 *ppObj
= static_cast<IShellPropSheetExt
*>(this);
47 } else if (riid
== IID_IShellExtInit
) {
48 *ppObj
= static_cast<IShellExtInit
*>(this);
57 HRESULT __stdcall
BtrfsVolPropSheet::Initialize(PCIDLIST_ABSOLUTE pidlFolder
, IDataObject
* pdtobj
, HKEY hkeyProgID
) {
60 FORMATETC format
= { CF_HDROP
, NULL
, DVASPECT_CONTENT
, -1, TYMED_HGLOBAL
};
69 stgm
.tymed
= TYMED_HGLOBAL
;
71 if (FAILED(pdtobj
->GetData(&format
, &stgm
)))
76 hdrop
= (HDROP
)GlobalLock(stgm
.hGlobal
);
79 ReleaseStgMedium(&stgm
);
84 num_files
= DragQueryFileW((HDROP
)stgm
.hGlobal
, 0xFFFFFFFF, NULL
, 0);
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
);
95 if (h
!= INVALID_HANDLE_VALUE
) {
103 devices
= (btrfs_device
*)malloc(devsize
);
106 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_GET_DEVICES
, NULL
, 0, devices
, devsize
);
107 if (Status
== STATUS_BUFFER_OVERFLOW
) {
112 devices
= (btrfs_device
*)malloc(devsize
);
124 if (!NT_SUCCESS(Status
)) {
130 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_GET_UUID
, NULL
, 0, &uuid
, sizeof(BTRFS_UUID
));
131 uuid_set
= NT_SUCCESS(Status
);
134 balance
= new BtrfsBalance(fn
);
158 void BtrfsVolPropSheet::FormatUsage(HWND hwndDlg
, WCHAR
* s
, ULONG size
, btrfs_usage
* usage
) {
160 UINT64 num_devs
, k
, dev_size
, dev_alloc
, data_size
, data_alloc
, metadata_size
, metadata_alloc
;
164 WCHAR t
[255], u
[255], v
[255];
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
};
179 if (bd
->next_entry
> 0)
180 bd
= (btrfs_device
*)((UINT8
*)bd
+ bd
->next_entry
);
185 devs
= (dev
*)malloc(sizeof(dev
) * num_devs
);
186 memset(devs
, 0, sizeof(dev
) * num_devs
);
195 if (!LoadStringW(module
, IDS_MISSING
, u
, sizeof(u
) / sizeof(WCHAR
))) {
196 ShowError(hwndDlg
, GetLastError());
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());
212 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), u
, bd
->device_number
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
215 devs
[k
].name
= (WCHAR
*)malloc((wcslen(t
) + 1) * sizeof(WCHAR
));
216 wcscpy(devs
[k
].name
, t
);
218 if (!LoadStringW(module
, IDS_DISK_PART_NUM
, u
, sizeof(u
) / sizeof(WCHAR
))) {
219 ShowError(hwndDlg
, GetLastError());
223 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), u
, bd
->device_number
, bd
->partition_number
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
226 devs
[k
].name
= (WCHAR
*)malloc((wcslen(t
) + 1) * sizeof(WCHAR
));
227 wcscpy(devs
[k
].name
, t
);
230 devs
[k
].dev_id
= bd
->dev_id
;
232 devs
[k
].size
= bd
->size
;
234 dev_size
+= bd
->size
;
238 if (bd
->next_entry
> 0)
239 bd
= (btrfs_device
*)((UINT8
*)bd
+ bd
->next_entry
);
245 data_size
= data_alloc
= 0;
246 metadata_size
= metadata_alloc
= 0;
250 for (k
= 0; k
< bue
->num_devices
; k
++) {
251 dev_alloc
+= bue
->devices
[k
].alloc
;
253 if (bue
->type
& BLOCK_FLAG_DATA
) {
254 data_alloc
+= bue
->devices
[k
].alloc
;
257 if (bue
->type
& BLOCK_FLAG_METADATA
) {
258 metadata_alloc
+= bue
->devices
[k
].alloc
;
262 if (bue
->type
& BLOCK_FLAG_DATA
) {
263 data_size
+= bue
->size
;
266 if (bue
->type
& BLOCK_FLAG_METADATA
) {
267 metadata_size
+= bue
->size
;
270 if (bue
->next_entry
> 0)
271 bue
= (btrfs_usage
*)((UINT8
*)bue
+ bue
->next_entry
);
278 if (!LoadStringW(module
, IDS_USAGE_DEV_SIZE
, u
, sizeof(u
) / sizeof(WCHAR
))) {
279 ShowError(hwndDlg
, GetLastError());
283 format_size(dev_size
, v
, sizeof(v
) / sizeof(WCHAR
), FALSE
);
285 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), u
, v
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
288 if (StringCchCatW(s
, size
, t
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
291 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
296 if (!LoadStringW(module
, IDS_USAGE_DEV_ALLOC
, u
, sizeof(u
) / sizeof(WCHAR
))) {
297 ShowError(hwndDlg
, GetLastError());
301 format_size(dev_alloc
, v
, sizeof(v
) / sizeof(WCHAR
), FALSE
);
303 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), u
, v
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
306 if (StringCchCatW(s
, size
, t
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
309 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
312 // device unallocated
314 if (!LoadStringW(module
, IDS_USAGE_DEV_UNALLOC
, u
, sizeof(u
) / sizeof(WCHAR
))) {
315 ShowError(hwndDlg
, GetLastError());
319 format_size(dev_size
- dev_alloc
, v
, sizeof(v
) / sizeof(WCHAR
), FALSE
);
321 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), u
, v
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
324 if (StringCchCatW(s
, size
, t
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
327 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
332 if (data_alloc
> 0) {
333 if (!LoadStringW(module
, IDS_USAGE_DATA_RATIO
, u
, sizeof(u
) / sizeof(WCHAR
))) {
334 ShowError(hwndDlg
, GetLastError());
338 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), u
, (float)data_alloc
/ (float)data_size
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
341 if (StringCchCatW(s
, size
, t
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
344 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
350 if (!LoadStringW(module
, IDS_USAGE_METADATA_RATIO
, u
, sizeof(u
) / sizeof(WCHAR
))) {
351 ShowError(hwndDlg
, GetLastError());
355 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), u
, (float)metadata_alloc
/ (float)metadata_size
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
358 if (StringCchCatW(s
, size
, t
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
361 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
364 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
367 for (i
= 0; i
< sizeof(types
) / sizeof(types
[0]); i
++) {
368 for (j
= 0; j
< sizeof(duptypes
) / sizeof(duptypes
[0]); j
++) {
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];
377 if (bue
->type
& BLOCK_FLAG_DATA
&& bue
->type
& BLOCK_FLAG_METADATA
&& (types
[i
] == BLOCK_FLAG_DATA
|| types
[i
] == BLOCK_FLAG_METADATA
))
380 if (!LoadStringW(module
, typestrings
[i
], typestring
, sizeof(typestring
) / sizeof(WCHAR
))) {
381 ShowError(hwndDlg
, GetLastError());
385 if (!LoadStringW(module
, dupstrings
[j
], dupstring
, sizeof(dupstring
) / sizeof(WCHAR
))) {
386 ShowError(hwndDlg
, GetLastError());
390 format_size(bue
->size
, sizestring
, sizeof(sizestring
) / sizeof(WCHAR
), FALSE
);
391 format_size(bue
->used
, usedstring
, sizeof(usedstring
) / sizeof(WCHAR
), FALSE
);
393 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), typestring
, dupstring
, sizestring
, usedstring
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
396 if (StringCchCatW(s
, size
, t
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
399 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
402 for (k
= 0; k
< bue
->num_devices
; k
++) {
406 format_size(bue
->devices
[k
].alloc
, sizestring
, sizeof(sizestring
) / sizeof(WCHAR
), FALSE
);
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
)
413 if (StringCchCatW(s
, size
, t
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
416 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
419 devs
[l
].alloc
+= bue
->devices
[k
].alloc
;
427 if (!LoadStringW(module
, IDS_UNKNOWN_DEVICE
, typestring
, sizeof(typestring
) / sizeof(WCHAR
))) {
428 ShowError(hwndDlg
, GetLastError());
432 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), typestring
, bue
->devices
[k
].dev_id
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
435 if (StringCchCatW(s
, size
, t
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
438 if (StringCchCatW(s
, size
, L
"\t") == STRSAFE_E_INSUFFICIENT_BUFFER
)
441 if (StringCchCatW(s
, size
, sizestring
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
444 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
449 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
455 if (bue
->next_entry
> 0)
456 bue
= (btrfs_usage
*)((UINT8
*)bue
+ bue
->next_entry
);
463 if (!LoadStringW(module
, IDS_USAGE_UNALLOC
, t
, sizeof(t
) / sizeof(WCHAR
))) {
464 ShowError(hwndDlg
, GetLastError());
468 if (StringCchCatW(s
, size
, t
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
471 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
474 for (k
= 0; k
< num_devs
; k
++) {
475 WCHAR sizestring
[255];
477 format_size(devs
[k
].size
- devs
[k
].alloc
, sizestring
, sizeof(sizestring
) / sizeof(WCHAR
), FALSE
);
479 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), L
"%s\t%s", devs
[k
].name
, sizestring
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
482 if (StringCchCatW(s
, size
, t
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
485 if (StringCchCatW(s
, size
, L
"\r\n") == STRSAFE_E_INSUFFICIENT_BUFFER
)
491 for (k
= 0; k
< num_devs
; k
++) {
492 if (devs
[k
].name
) free(devs
[k
].name
);
499 void BtrfsVolPropSheet::RefreshUsage(HWND hwndDlg
) {
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
);
507 if (h
!= INVALID_HANDLE_VALUE
) {
509 IO_STATUS_BLOCK iosb
;
510 ULONG devsize
, usagesize
, i
;
515 devices
= (btrfs_device
*)malloc(devsize
);
518 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_GET_DEVICES
, NULL
, 0, devices
, devsize
);
519 if (Status
== STATUS_BUFFER_OVERFLOW
) {
524 devices
= (btrfs_device
*)malloc(devsize
);
533 if (!NT_SUCCESS(Status
)) {
541 usage
= (btrfs_usage
*)malloc(usagesize
);
544 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_GET_USAGE
, NULL
, 0, usage
, usagesize
);
545 if (Status
== STATUS_BUFFER_OVERFLOW
) {
550 usage
= (btrfs_usage
*)malloc(usagesize
);
559 if (!NT_SUCCESS(Status
)) {
571 FormatUsage(hwndDlg
, s
, sizeof(s
) / sizeof(WCHAR
), usage
);
573 SetDlgItemTextW(hwndDlg
, IDC_USAGE_BOX
, s
);
578 INT_PTR CALLBACK
BtrfsVolPropSheet::UsageDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
587 IO_STATUS_BLOCK iosb
;
589 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
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
);
594 if (h
!= INVALID_HANDLE_VALUE
) {
600 usage
= (btrfs_usage
*)malloc(usagesize
);
603 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_GET_USAGE
, NULL
, 0, usage
, usagesize
);
604 if (Status
== STATUS_BUFFER_OVERFLOW
) {
609 usage
= (btrfs_usage
*)malloc(usagesize
);
618 if (!NT_SUCCESS(Status
)) {
626 FormatUsage(hwndDlg
, s
, sizeof(s
) / sizeof(WCHAR
), usage
);
628 SetDlgItemTextW(hwndDlg
, IDC_USAGE_BOX
, s
);
637 switch (HIWORD(wParam
)) {
639 switch (LOWORD(wParam
)) {
642 EndDialog(hwndDlg
, 0);
645 case IDC_USAGE_REFRESH
:
646 RefreshUsage(hwndDlg
);
657 static INT_PTR CALLBACK
stub_UsageDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
658 BtrfsVolPropSheet
* bvps
;
660 if (uMsg
== WM_INITDIALOG
) {
661 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
662 bvps
= (BtrfsVolPropSheet
*)lParam
;
664 bvps
= (BtrfsVolPropSheet
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
668 return bvps
->UsageDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
673 void BtrfsVolPropSheet::ShowUsage(HWND hwndDlg
) {
674 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_VOL_USAGE
), hwndDlg
, stub_UsageDlgProc
, (LPARAM
)this);
677 static void add_lv_column(HWND list
, int string
, int cx
) {
681 if (!LoadStringW(module
, string
, s
, sizeof(s
) / sizeof(WCHAR
))) {
682 ShowError(GetParent(list
), GetLastError());
686 lvc
.mask
= LVCF_TEXT
|LVCF_WIDTH
;
689 SendMessageW(list
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&lvc
);
692 static int CALLBACK
lv_sort(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
) {
693 if (lParam1
< lParam2
)
695 else if (lParam1
> lParam2
)
701 static UINT64
find_dev_alloc(UINT64 dev_id
, btrfs_usage
* usage
) {
711 for (k
= 0; k
< bue
->num_devices
; k
++) {
712 if (bue
->devices
[k
].dev_id
== dev_id
)
713 alloc
+= bue
->devices
[k
].alloc
;
716 if (bue
->next_entry
> 0)
717 bue
= (btrfs_usage
*)((UINT8
*)bue
+ bue
->next_entry
);
725 void BtrfsVolPropSheet::RefreshDevList(HWND devlist
) {
728 IO_STATUS_BLOCK iosb
;
729 ULONG usagesize
, devsize
;
733 UINT64 num_rw_devices
;
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
);
738 if (h
== INVALID_HANDLE_VALUE
) {
739 ShowError(GetParent(devlist
), GetLastError());
749 devices
= (btrfs_device
*)malloc(devsize
);
752 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_GET_DEVICES
, NULL
, 0, devices
, devsize
);
753 if (Status
== STATUS_BUFFER_OVERFLOW
) {
758 devices
= (btrfs_device
*)malloc(devsize
);
767 if (!NT_SUCCESS(Status
)) {
777 usage
= (btrfs_usage
*)malloc(usagesize
);
780 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_GET_USAGE
, NULL
, 0, usage
, usagesize
);
781 if (Status
== STATUS_BUFFER_OVERFLOW
) {
786 usage
= (btrfs_usage
*)malloc(usagesize
);
798 if (!NT_SUCCESS(Status
)) {
806 SendMessageW(devlist
, LVM_DELETEALLITEMS
, 0, 0);
813 WCHAR s
[255], u
[255];
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
;
823 StringCchPrintfW(s
, sizeof(s
) / sizeof(WCHAR
), L
"%llu", bd
->dev_id
);
826 SendMessageW(devlist
, LVM_INSERTITEMW
, 0, (LPARAM
)&lvi
);
830 lvi
.mask
= LVIF_TEXT
;
834 if (!LoadStringW(module
, IDS_MISSING
, u
, sizeof(u
) / sizeof(WCHAR
))) {
835 ShowError(GetParent(devlist
), GetLastError());
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());
849 if (StringCchPrintfW(s
, sizeof(s
) / sizeof(WCHAR
), u
, bd
->device_number
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
852 if (!LoadStringW(module
, IDS_DISK_PART_NUM
, u
, sizeof(u
) / sizeof(WCHAR
))) {
853 ShowError(GetParent(devlist
), GetLastError());
857 if (StringCchPrintfW(s
, sizeof(s
) / sizeof(WCHAR
), u
, bd
->device_number
, bd
->partition_number
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
863 SendMessageW(devlist
, LVM_SETITEMW
, 0, (LPARAM
)&lvi
);
868 LoadStringW(module
, bd
->readonly
? IDS_DEVLIST_READONLY_YES
: IDS_DEVLIST_READONLY_NO
, s
, sizeof(s
) / sizeof(WCHAR
));
870 SendMessageW(devlist
, LVM_SETITEMW
, 0, (LPARAM
)&lvi
);
878 format_size(bd
->size
, s
, sizeof(s
) / sizeof(WCHAR
), FALSE
);
880 SendMessageW(devlist
, LVM_SETITEMW
, 0, (LPARAM
)&lvi
);
884 alloc
= find_dev_alloc(bd
->dev_id
, usage
);
887 format_size(alloc
, s
, sizeof(s
) / sizeof(WCHAR
), FALSE
);
889 SendMessageW(devlist
, LVM_SETITEMW
, 0, (LPARAM
)&lvi
);
893 StringCchPrintfW(s
, sizeof(s
) / sizeof(WCHAR
), L
"%1.1f%%", (float)alloc
* 100.0f
/ (float)bd
->size
);
896 SendMessageW(devlist
, LVM_SETITEMW
, 0, (LPARAM
)&lvi
);
900 if (bd
->next_entry
> 0)
901 bd
= (btrfs_device
*)((UINT8
*)bd
+ bd
->next_entry
);
908 SendMessageW(devlist
, LVM_SORTITEMS
, 0, (LPARAM
)lv_sort
);
910 EnableWindow(GetDlgItem(GetParent(devlist
), IDC_DEVICE_ADD
), num_rw_devices
> 0);
911 EnableWindow(GetDlgItem(GetParent(devlist
), IDC_DEVICE_REMOVE
), num_rw_devices
> 1);
914 void BtrfsVolPropSheet::ResetStats(HWND hwndDlg
) {
916 WCHAR t
[MAX_PATH
+ 100], sel
[10];
917 SHELLEXECUTEINFOW sei
;
919 _itow(stats_dev
, sel
, 10);
922 GetModuleFileNameW(module
, t
+ 1, (sizeof(t
) / sizeof(WCHAR
)) - 1);
923 wcscat(t
, L
"\",ResetStats ");
928 RtlZeroMemory(&sei
, sizeof(sei
));
930 sei
.cbSize
= sizeof(sei
);
932 sei
.lpVerb
= L
"runas";
933 sei
.lpFile
= L
"rundll32.exe";
934 sei
.lpParameters
= t
;
936 sei
.fMask
= SEE_MASK_NOCLOSEPROCESS
;
938 if (!ShellExecuteExW(&sei
)) {
939 ShowError(hwndDlg
, GetLastError());
943 WaitForSingleObject(sei
.hProcess
, INFINITE
);
944 CloseHandle(sei
.hProcess
);
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
);
949 if (h
!= INVALID_HANDLE_VALUE
) {
951 IO_STATUS_BLOCK iosb
;
958 devices
= (btrfs_device
*)malloc(devsize
);
961 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_GET_DEVICES
, NULL
, 0, devices
, devsize
);
962 if (Status
== STATUS_BUFFER_OVERFLOW
) {
967 devices
= (btrfs_device
*)malloc(devsize
);
979 EndDialog(hwndDlg
, 0);
982 INT_PTR CALLBACK
BtrfsVolPropSheet::StatsDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
986 WCHAR s
[255], t
[255];
987 btrfs_device
*bd
, *dev
= NULL
;
990 static int stat_ids
[] = { IDC_WRITE_ERRS
, IDC_READ_ERRS
, IDC_FLUSH_ERRS
, IDC_CORRUPTION_ERRS
, IDC_GENERATION_ERRS
};
995 if (bd
->dev_id
== stats_dev
) {
1000 if (bd
->next_entry
> 0)
1001 bd
= (btrfs_device
*)((UINT8
*)bd
+ bd
->next_entry
);
1007 EndDialog(hwndDlg
, 0);
1008 ShowStringError(hwndDlg
, IDS_CANNOT_FIND_DEVICE
);
1012 GetDlgItemTextW(hwndDlg
, IDC_DEVICE_ID
, s
, sizeof(s
) / sizeof(WCHAR
));
1014 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), s
, dev
->dev_id
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
1017 SetDlgItemTextW(hwndDlg
, IDC_DEVICE_ID
, t
);
1019 for (i
= 0; i
< 5; i
++) {
1020 GetDlgItemTextW(hwndDlg
, stat_ids
[i
], s
, sizeof(s
) / sizeof(WCHAR
));
1022 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), s
, dev
->stats
[i
]) == STRSAFE_E_INSUFFICIENT_BUFFER
)
1025 SetDlgItemTextW(hwndDlg
, stat_ids
[i
], t
);
1028 SendMessageW(GetDlgItem(hwndDlg
, IDC_RESET_STATS
), BCM_SETSHIELD
, 0, TRUE
);
1029 EnableWindow(GetDlgItem(hwndDlg
, IDC_RESET_STATS
), !readonly
);
1035 switch (HIWORD(wParam
)) {
1037 switch (LOWORD(wParam
)) {
1040 EndDialog(hwndDlg
, 0);
1043 case IDC_RESET_STATS
:
1044 ResetStats(hwndDlg
);
1055 static INT_PTR CALLBACK
stub_StatsDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
1056 BtrfsVolPropSheet
* bvps
;
1058 if (uMsg
== WM_INITDIALOG
) {
1059 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
1060 bvps
= (BtrfsVolPropSheet
*)lParam
;
1062 bvps
= (BtrfsVolPropSheet
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
1066 return bvps
->StatsDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
1071 void BtrfsVolPropSheet::ShowStats(HWND hwndDlg
, UINT64 devid
) {
1074 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_DEVICE_STATS
), hwndDlg
, stub_StatsDlgProc
, (LPARAM
)this);
1077 INT_PTR CALLBACK
BtrfsVolPropSheet::DeviceDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
1085 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
1087 devlist
= GetDlgItem(hwndDlg
, IDC_DEVLIST
);
1089 GetClientRect(devlist
, &rect
);
1090 w
= rect
.right
- rect
.left
;
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);
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
);
1103 RefreshDevList(devlist
);
1109 switch (HIWORD(wParam
)) {
1111 switch (LOWORD(wParam
)) {
1114 KillTimer(hwndDlg
, 1);
1115 EndDialog(hwndDlg
, 0);
1118 case IDC_DEVICE_ADD
:
1120 WCHAR t
[MAX_PATH
+ 100];
1121 SHELLEXECUTEINFOW sei
;
1124 GetModuleFileNameW(module
, t
+ 1, (sizeof(t
) / sizeof(WCHAR
)) - 1);
1125 wcscat(t
, L
"\",AddDevice ");
1128 RtlZeroMemory(&sei
, sizeof(sei
));
1130 sei
.cbSize
= sizeof(sei
);
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
;
1138 if (!ShellExecuteExW(&sei
)) {
1139 ShowError(hwndDlg
, GetLastError());
1143 WaitForSingleObject(sei
.hProcess
, INFINITE
);
1144 CloseHandle(sei
.hProcess
);
1146 RefreshDevList(GetDlgItem(hwndDlg
, IDC_DEVLIST
));
1151 case IDC_DEVICE_REFRESH
:
1152 RefreshDevList(GetDlgItem(hwndDlg
, IDC_DEVLIST
));
1155 case IDC_DEVICE_SHOW_STATS
:
1157 WCHAR sel
[MAX_PATH
];
1162 devlist
= GetDlgItem(hwndDlg
, IDC_DEVLIST
);
1164 index
= SendMessageW(devlist
, LVM_GETNEXTITEM
, -1, LVNI_SELECTED
);
1169 RtlZeroMemory(&lvi
, sizeof(LVITEMW
));
1170 lvi
.mask
= LVIF_TEXT
;
1174 lvi
.cchTextMax
= sizeof(sel
) / sizeof(WCHAR
);
1175 SendMessageW(devlist
, LVM_GETITEMW
, 0, (LPARAM
)&lvi
);
1177 ShowStats(hwndDlg
, _wtoi(sel
));
1181 case IDC_DEVICE_REMOVE
:
1183 WCHAR t
[2*MAX_PATH
+ 100], sel
[MAX_PATH
], sel2
[MAX_PATH
], mess
[255], mess2
[255], title
[255];
1185 SHELLEXECUTEINFOW sei
;
1189 devlist
= GetDlgItem(hwndDlg
, IDC_DEVLIST
);
1191 index
= SendMessageW(devlist
, LVM_GETNEXTITEM
, -1, LVNI_SELECTED
);
1196 RtlZeroMemory(&lvi
, sizeof(LVITEMW
));
1197 lvi
.mask
= LVIF_TEXT
;
1201 lvi
.cchTextMax
= sizeof(sel
) / sizeof(WCHAR
);
1202 SendMessageW(devlist
, LVM_GETITEMW
, 0, (LPARAM
)&lvi
);
1206 lvi
.cchTextMax
= sizeof(sel2
) / sizeof(WCHAR
);
1207 SendMessageW(devlist
, LVM_GETITEMW
, 0, (LPARAM
)&lvi
);
1209 if (!LoadStringW(module
, IDS_REMOVE_DEVICE_CONFIRMATION
, mess
, sizeof(mess
) / sizeof(WCHAR
))) {
1210 ShowError(hwndDlg
, GetLastError());
1214 if (StringCchPrintfW(mess2
, sizeof(mess2
) / sizeof(WCHAR
), mess
, sel
, sel2
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
1217 if (!LoadStringW(module
, IDS_CONFIRMATION_TITLE
, title
, sizeof(title
) / sizeof(WCHAR
))) {
1218 ShowError(hwndDlg
, GetLastError());
1222 if (MessageBoxW(hwndDlg
, mess2
, title
, MB_YESNO
) != IDYES
)
1226 GetModuleFileNameW(module
, t
+ 1, (sizeof(t
) / sizeof(WCHAR
)) - 1);
1227 wcscat(t
, L
"\",RemoveDevice ");
1232 RtlZeroMemory(&sei
, sizeof(sei
));
1234 sei
.cbSize
= sizeof(sei
);
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
;
1242 if (!ShellExecuteExW(&sei
)) {
1243 ShowError(hwndDlg
, GetLastError());
1247 WaitForSingleObject(sei
.hProcess
, INFINITE
);
1248 CloseHandle(sei
.hProcess
);
1250 RefreshDevList(GetDlgItem(hwndDlg
, IDC_DEVLIST
));
1255 case IDC_DEVICE_RESIZE
:
1260 WCHAR sel
[100], t
[2*MAX_PATH
+ 100];
1261 SHELLEXECUTEINFOW sei
;
1263 devlist
= GetDlgItem(hwndDlg
, IDC_DEVLIST
);
1265 index
= SendMessageW(devlist
, LVM_GETNEXTITEM
, -1, LVNI_SELECTED
);
1270 RtlZeroMemory(&lvi
, sizeof(LVITEMW
));
1271 lvi
.mask
= LVIF_TEXT
;
1275 lvi
.cchTextMax
= sizeof(sel
) / sizeof(WCHAR
);
1276 SendMessageW(devlist
, LVM_GETITEMW
, 0, (LPARAM
)&lvi
);
1279 GetModuleFileNameW(module
, t
+ 1, (sizeof(t
) / sizeof(WCHAR
)) - 1);
1280 wcscat(t
, L
"\",ResizeDevice ");
1285 RtlZeroMemory(&sei
, sizeof(sei
));
1287 sei
.cbSize
= sizeof(sei
);
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
;
1295 if (!ShellExecuteExW(&sei
)) {
1296 ShowError(hwndDlg
, GetLastError());
1300 WaitForSingleObject(sei
.hProcess
, INFINITE
);
1301 CloseHandle(sei
.hProcess
);
1303 RefreshDevList(GetDlgItem(hwndDlg
, IDC_DEVLIST
));
1311 switch (((LPNMHDR
)lParam
)->code
) {
1312 case LVN_ITEMCHANGED
:
1314 NMLISTVIEW
* nmv
= (NMLISTVIEW
*)lParam
;
1316 EnableWindow(GetDlgItem(hwndDlg
, IDC_DEVICE_SHOW_STATS
), nmv
->uNewState
& LVIS_SELECTED
);
1318 if (nmv
->uNewState
& LVIS_SELECTED
&& !readonly
) {
1321 BOOL device_readonly
= FALSE
;
1323 WCHAR sel
[MAX_PATH
];
1326 devlist
= GetDlgItem(hwndDlg
, IDC_DEVLIST
);
1328 RtlZeroMemory(&lvi
, sizeof(LVITEMW
));
1329 lvi
.mask
= LVIF_TEXT
;
1330 lvi
.iItem
= nmv
->iItem
;
1333 lvi
.cchTextMax
= sizeof(sel
) / sizeof(WCHAR
);
1334 SendMessageW(devlist
, LVM_GETITEMW
, 0, (LPARAM
)&lvi
);
1340 if (bd
->dev_id
== devid
) {
1341 device_readonly
= bd
->readonly
;
1345 if (bd
->next_entry
> 0)
1346 bd
= (btrfs_device
*)((UINT8
*)bd
+ bd
->next_entry
);
1351 EnableWindow(GetDlgItem(hwndDlg
, IDC_DEVICE_RESIZE
), !device_readonly
);
1353 EnableWindow(GetDlgItem(hwndDlg
, IDC_DEVICE_RESIZE
), FALSE
);
1364 static INT_PTR CALLBACK
stub_DeviceDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
1365 BtrfsVolPropSheet
* bvps
;
1367 if (uMsg
== WM_INITDIALOG
) {
1368 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
1369 bvps
= (BtrfsVolPropSheet
*)lParam
;
1371 bvps
= (BtrfsVolPropSheet
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
1375 return bvps
->DeviceDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
1380 void BtrfsVolPropSheet::ShowDevices(HWND hwndDlg
) {
1381 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_DEVICES
), hwndDlg
, stub_DeviceDlgProc
, (LPARAM
)this);
1384 void BtrfsVolPropSheet::ShowScrub(HWND hwndDlg
) {
1385 WCHAR t
[MAX_PATH
+ 100];
1386 SHELLEXECUTEINFOW sei
;
1389 GetModuleFileNameW(module
, t
+ 1, (sizeof(t
) / sizeof(WCHAR
)) - 1);
1390 wcscat(t
, L
"\",ShowScrub ");
1393 RtlZeroMemory(&sei
, sizeof(sei
));
1395 sei
.cbSize
= sizeof(sei
);
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
;
1403 if (!ShellExecuteExW(&sei
)) {
1404 ShowError(hwndDlg
, GetLastError());
1408 WaitForSingleObject(sei
.hProcess
, INFINITE
);
1409 CloseHandle(sei
.hProcess
);
1412 static INT_PTR CALLBACK
PropSheetDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
1416 PROPSHEETPAGE
* psp
= (PROPSHEETPAGE
*)lParam
;
1417 BtrfsVolPropSheet
* bps
= (BtrfsVolPropSheet
*)psp
->lParam
;
1420 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
1422 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)bps
);
1424 bps
->readonly
= TRUE
;
1428 if (!bd
->readonly
) {
1429 bps
->readonly
= FALSE
;
1433 if (bd
->next_entry
> 0)
1434 bd
= (btrfs_device
*)((UINT8
*)bd
+ bd
->next_entry
);
1439 if (bps
->uuid_set
) {
1440 WCHAR s
[255], t
[255];
1442 GetDlgItemTextW(hwndDlg
, IDC_UUID
, s
, sizeof(s
) / sizeof(WCHAR
));
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
);
1450 SetDlgItemTextW(hwndDlg
, IDC_UUID
, L
"");
1452 SetDlgItemTextW(hwndDlg
, IDC_UUID
, L
"");
1454 SendMessageW(GetDlgItem(hwndDlg
, IDC_VOL_SCRUB
), BCM_SETSHIELD
, 0, TRUE
);
1461 switch (((LPNMHDR
)lParam
)->code
) {
1462 case PSN_KILLACTIVE
:
1463 SetWindowLongPtrW(hwndDlg
, DWLP_MSGRESULT
, FALSE
);
1471 BtrfsVolPropSheet
* bps
= (BtrfsVolPropSheet
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
1474 switch (HIWORD(wParam
)) {
1476 switch (LOWORD(wParam
)) {
1477 case IDC_VOL_SHOW_USAGE
:
1478 bps
->ShowUsage(hwndDlg
);
1481 case IDC_VOL_BALANCE
:
1482 bps
->balance
->ShowBalance(hwndDlg
);
1485 case IDC_VOL_DEVICES
:
1486 bps
->ShowDevices(hwndDlg
);
1490 bps
->ShowScrub(hwndDlg
);
1504 HRESULT __stdcall
BtrfsVolPropSheet::AddPages(LPFNADDPROPSHEETPAGE pfnAddPage
, LPARAM lParam
) {
1506 HPROPSHEETPAGE hPage
;
1507 INITCOMMONCONTROLSEX icex
;
1512 icex
.dwSize
= sizeof(icex
);
1513 icex
.dwICC
= ICC_LINK_CLASS
;
1515 if (!InitCommonControlsEx(&icex
))
1516 MessageBoxW(NULL
, L
"InitCommonControlsEx failed", L
"Error", MB_ICONERROR
);
1518 psp
.dwSize
= sizeof(psp
);
1519 psp
.dwFlags
= PSP_USEREFPARENT
| PSP_USETITLE
;
1520 psp
.hInstance
= module
;
1521 psp
.pszTemplate
= MAKEINTRESOURCE(IDD_VOL_PROP_SHEET
);
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;
1529 hPage
= CreatePropertySheetPage(&psp
);
1532 if (pfnAddPage(hPage
, lParam
)) {
1536 DestroyPropertySheetPage(hPage
);
1538 return E_OUTOFMEMORY
;
1543 HRESULT __stdcall
BtrfsVolPropSheet::ReplacePage(UINT uPageID
, LPFNADDPROPSHEETPAGE pfnReplacePage
, LPARAM lParam
) {
1551 void CALLBACK
ResetStatsW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
1554 TOKEN_PRIVILEGES tp
;
1557 WCHAR
*s
, *vol
, *dev
;
1558 IO_STATUS_BLOCK iosb
;
1562 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
)) {
1563 ShowError(hwnd
, GetLastError());
1567 if (!LookupPrivilegeValueW(NULL
, L
"SeManageVolumePrivilege", &luid
)) {
1568 ShowError(hwnd
, GetLastError());
1572 tp
.PrivilegeCount
= 1;
1573 tp
.Privileges
[0].Luid
= luid
;
1574 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
1576 if (!AdjustTokenPrivileges(token
, FALSE
, &tp
, sizeof(TOKEN_PRIVILEGES
), NULL
, NULL
)) {
1577 ShowError(hwnd
, GetLastError());
1581 s
= wcsstr(lpszCmdLine
, L
"|");
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
);
1597 if (h
== INVALID_HANDLE_VALUE
) {
1598 ShowError(hwnd
, GetLastError());
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
);