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
35 #include <ndk/rtlfuncs.h>
36 #include <ndk/obfuncs.h>
40 DEFINE_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME
, 0x7f108a28L
, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62);
42 static std::wstring
get_mountdev_name(HANDLE h
) {
45 MOUNTDEV_NAME mdn
, *mdn2
;
49 Status
= NtDeviceIoControlFile(h
, NULL
, NULL
, NULL
, &iosb
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
50 NULL
, 0, &mdn
, sizeof(MOUNTDEV_NAME
));
51 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
)
54 mdnsize
= offsetof(MOUNTDEV_NAME
, Name
[0]) + mdn
.NameLength
;
56 mdn2
= (MOUNTDEV_NAME
*)malloc(mdnsize
);
58 Status
= NtDeviceIoControlFile(h
, NULL
, NULL
, NULL
, &iosb
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
59 NULL
, 0, mdn2
, mdnsize
);
60 if (!NT_SUCCESS(Status
)) {
65 name
= std::wstring(mdn2
->Name
, mdn2
->NameLength
/ sizeof(WCHAR
));
72 static void find_devices(HWND hwnd
, const GUID
* guid
, HANDLE mountmgr
, std::vector
<device
>* device_list
) {
75 static WCHAR dosdevices
[] = L
"\\DosDevices\\";
77 h
= SetupDiGetClassDevs(guid
, NULL
, 0, DIGCF_DEVICEINTERFACE
| DIGCF_PRESENT
);
79 if (h
!= INVALID_HANDLE_VALUE
) {
81 SP_DEVICE_INTERFACE_DATA did
;
83 did
.cbSize
= sizeof(did
);
85 if (!SetupDiEnumDeviceInterfaces(h
, NULL
, guid
, index
, &did
))
90 SP_DEVICE_INTERFACE_DETAIL_DATA_W
* detail
;
93 dd
.cbSize
= sizeof(dd
);
95 SetupDiGetDeviceInterfaceDetailW(h
, &did
, NULL
, 0, &size
, NULL
);
97 detail
= (SP_DEVICE_INTERFACE_DETAIL_DATA_W
*)malloc(size
);
98 memset(detail
, 0, size
);
100 detail
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
);
102 if (SetupDiGetDeviceInterfaceDetailW(h
, &did
, detail
, size
, &size
, &dd
)) {
106 STORAGE_DEVICE_NUMBER sdn
;
107 IO_STATUS_BLOCK iosb
;
109 OBJECT_ATTRIBUTES attr
;
110 GET_LENGTH_INFORMATION gli
;
114 path
.Buffer
= detail
->DevicePath
;
115 path
.Length
= path
.MaximumLength
= wcslen(detail
->DevicePath
) * sizeof(WCHAR
);
117 if (path
.Length
> 4 * sizeof(WCHAR
) && path
.Buffer
[0] == '\\' && path
.Buffer
[1] == '\\' && path
.Buffer
[2] == '?' && path
.Buffer
[3] == '\\')
118 path
.Buffer
[1] = '?';
120 InitializeObjectAttributes(&attr
, &path
, 0, NULL
, NULL
);
122 Status
= NtOpenFile(&file
, FILE_GENERIC_READ
, &attr
, &iosb
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, FILE_SYNCHRONOUS_IO_ALERT
);
124 if (!NT_SUCCESS(Status
))
127 dev
.pnp_name
= detail
->DevicePath
;
129 Status
= NtDeviceIoControlFile(file
, NULL
, NULL
, NULL
, &iosb
, IOCTL_DISK_GET_LENGTH_INFO
, NULL
, 0, &gli
, sizeof(GET_LENGTH_INFORMATION
));
130 if (!NT_SUCCESS(Status
))
133 dev
.size
= gli
.Length
.QuadPart
;
135 Status
= NtDeviceIoControlFile(file
, NULL
, NULL
, NULL
, &iosb
, IOCTL_STORAGE_GET_DEVICE_NUMBER
, NULL
, 0, &sdn
, sizeof(STORAGE_DEVICE_NUMBER
));
136 if (!NT_SUCCESS(Status
)) {
137 dev
.disk_num
= 0xffffffff;
138 dev
.part_num
= 0xffffffff;
140 dev
.disk_num
= sdn
.DeviceNumber
;
141 dev
.part_num
= sdn
.PartitionNumber
;
144 dev
.friendly_name
= L
"";
147 dev
.has_parts
= FALSE
;
149 dev
.multi_device
= FALSE
;
151 dev
.is_disk
= RtlCompareMemory(guid
, &GUID_DEVINTERFACE_DISK
, sizeof(GUID
)) == sizeof(GUID
);
154 STORAGE_PROPERTY_QUERY spq
;
155 STORAGE_DEVICE_DESCRIPTOR sdd
, *sdd2
;
157 DRIVE_LAYOUT_INFORMATION_EX
* dli
;
159 spq
.PropertyId
= StorageDeviceProperty
;
160 spq
.QueryType
= PropertyStandardQuery
;
161 spq
.AdditionalParameters
[0] = 0;
163 Status
= NtDeviceIoControlFile(file
, NULL
, NULL
, NULL
, &iosb
, IOCTL_STORAGE_QUERY_PROPERTY
,
164 &spq
, sizeof(STORAGE_PROPERTY_QUERY
), &sdd
, sizeof(STORAGE_DEVICE_DESCRIPTOR
));
166 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
) {
167 sdd2
= (STORAGE_DEVICE_DESCRIPTOR
*)malloc(sdd
.Size
);
169 Status
= NtDeviceIoControlFile(file
, NULL
, NULL
, NULL
, &iosb
, IOCTL_STORAGE_QUERY_PROPERTY
,
170 &spq
, sizeof(STORAGE_PROPERTY_QUERY
), sdd2
, sdd
.Size
);
171 if (NT_SUCCESS(Status
)) {
176 if (sdd2
->VendorIdOffset
!= 0) {
177 desc2
+= (char*)((UINT8
*)sdd2
+ sdd2
->VendorIdOffset
);
179 while (desc2
.length() > 0 && desc2
[desc2
.length() - 1] == ' ')
180 desc2
= desc2
.substr(0, desc2
.length() - 1);
183 if (sdd2
->ProductIdOffset
!= 0) {
184 if (sdd2
->VendorIdOffset
!= 0 && desc2
.length() != 0 && desc2
[desc2
.length() - 1] != ' ')
187 desc2
+= (char*)((UINT8
*)sdd2
+ sdd2
->ProductIdOffset
);
189 while (desc2
.length() > 0 && desc2
[desc2
.length() - 1] == ' ')
190 desc2
= desc2
.substr(0, desc2
.length() - 1);
193 if (sdd2
->VendorIdOffset
!= 0 || sdd2
->ProductIdOffset
!= 0) {
196 ss
= MultiByteToWideChar(CP_OEMCP
, MB_PRECOMPOSED
, desc2
.c_str(), -1, NULL
, 0);
199 WCHAR
* desc3
= (WCHAR
*)malloc(ss
* sizeof(WCHAR
));
201 if (MultiByteToWideChar(CP_OEMCP
, MB_PRECOMPOSED
, desc2
.c_str(), -1, desc3
, ss
* sizeof(WCHAR
)))
202 dev
.friendly_name
= desc3
;
221 dli
= (DRIVE_LAYOUT_INFORMATION_EX
*)malloc(dlisize
);
223 Status
= NtDeviceIoControlFile(file
, NULL
, NULL
, NULL
, &iosb
, IOCTL_DISK_GET_DRIVE_LAYOUT_EX
,
224 NULL
, 0, dli
, dlisize
);
225 } while (Status
== STATUS_BUFFER_TOO_SMALL
);
227 if (NT_SUCCESS(Status
) && dli
->PartitionCount
> 0)
228 dev
.has_parts
= TRUE
;
233 MOUNTMGR_MOUNT_POINT
* mmp
;
234 MOUNTMGR_MOUNT_POINTS mmps
;
236 mmpsize
= sizeof(MOUNTMGR_MOUNT_POINT
) + path
.Length
;
238 mmp
= (MOUNTMGR_MOUNT_POINT
*)malloc(mmpsize
);
240 RtlZeroMemory(mmp
, sizeof(MOUNTMGR_MOUNT_POINT
));
241 mmp
->DeviceNameOffset
= sizeof(MOUNTMGR_MOUNT_POINT
);
242 mmp
->DeviceNameLength
= path
.Length
;
243 RtlCopyMemory(&mmp
[1], path
.Buffer
, path
.Length
);
245 Status
= NtDeviceIoControlFile(mountmgr
, NULL
, NULL
, NULL
, &iosb
, IOCTL_MOUNTMGR_QUERY_POINTS
,
246 mmp
, mmpsize
, &mmps
, sizeof(MOUNTMGR_MOUNT_POINTS
));
247 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
) {
248 MOUNTMGR_MOUNT_POINTS
* mmps2
;
250 mmps2
= (MOUNTMGR_MOUNT_POINTS
*)malloc(mmps
.Size
);
252 Status
= NtDeviceIoControlFile(mountmgr
, NULL
, NULL
, NULL
, &iosb
, IOCTL_MOUNTMGR_QUERY_POINTS
,
253 mmp
, mmpsize
, mmps2
, mmps
.Size
);
255 if (NT_SUCCESS(Status
)) {
258 for (i
= 0; i
< mmps2
->NumberOfMountPoints
; i
++) {
259 WCHAR
* symlink
= (WCHAR
*)((UINT8
*)mmps2
+ mmps2
->MountPoints
[i
].SymbolicLinkNameOffset
);
261 if (mmps2
->MountPoints
[i
].SymbolicLinkNameLength
== 0x1c &&
262 RtlCompareMemory(symlink
, dosdevices
, wcslen(dosdevices
) * sizeof(WCHAR
)) == wcslen(dosdevices
) * sizeof(WCHAR
) &&
281 if (!dev
.is_disk
|| !dev
.has_parts
) {
283 while (fs_ident
[i
].name
) {
284 if (i
== 0 || fs_ident
[i
].kboff
!= fs_ident
[i
-1].kboff
) {
287 off
.QuadPart
= fs_ident
[i
].kboff
* 1024;
288 Status
= NtReadFile(file
, NULL
, NULL
, NULL
, &iosb
, sb
, sizeof(sb
), &off
, NULL
);
291 if (NT_SUCCESS(Status
)) {
292 if (RtlCompareMemory(sb
+ fs_ident
[i
].sboff
, fs_ident
[i
].magic
, fs_ident
[i
].magiclen
) == fs_ident
[i
].magiclen
) {
293 dev
.fstype
= fs_ident
[i
].name
;
295 if (dev
.fstype
== L
"Btrfs") {
296 superblock
* bsb
= (superblock
*)sb
;
298 RtlCopyMemory(&dev
.fs_uuid
, &bsb
->uuid
, sizeof(BTRFS_UUID
));
299 RtlCopyMemory(&dev
.dev_uuid
, &bsb
->dev_item
.device_uuid
, sizeof(BTRFS_UUID
));
309 if (dev
.fstype
== L
"Btrfs" && RtlCompareMemory(guid
, &GUID_DEVINTERFACE_DISK
, sizeof(GUID
)) != sizeof(GUID
)) {
311 std::wstring pref
= L
"\\Device\\Btrfs{";
313 name
= get_mountdev_name(file
);
315 if (name
.length() > pref
.length() && RtlCompareMemory(name
.c_str(), pref
.c_str(), pref
.length() * sizeof(WCHAR
)) == pref
.length() * sizeof(WCHAR
))
320 device_list
->push_back(dev
);
330 } while (SetupDiEnumDeviceInterfaces(h
, NULL
, guid
, index
, &did
));
332 SetupDiDestroyDeviceInfoList(h
);
334 ShowError(hwnd
, GetLastError());
339 static bool sort_devices(device i
, device j
) {
340 if (i
.disk_num
< j
.disk_num
)
343 if (i
.disk_num
== j
.disk_num
&& i
.part_num
< j
.part_num
)
349 void BtrfsDeviceAdd::populate_device_tree(HWND tree
) {
350 HWND hwnd
= GetParent(tree
);
352 ULONG last_disk_num
= 0xffffffff;
355 OBJECT_ATTRIBUTES attr
;
357 IO_STATUS_BLOCK iosb
;
358 HANDLE mountmgr
, btrfsh
;
359 btrfs_filesystem
* bfs
= NULL
;
361 static WCHAR btrfs
[] = L
"\\Btrfs";
365 RtlInitUnicodeString(&us
, MOUNTMGR_DEVICE_NAME
);
366 InitializeObjectAttributes(&attr
, &us
, 0, NULL
, NULL
);
368 Status
= NtOpenFile(&mountmgr
, FILE_GENERIC_READ
| FILE_GENERIC_WRITE
, &attr
, &iosb
,
369 FILE_SHARE_READ
, FILE_SYNCHRONOUS_IO_ALERT
);
370 if (!NT_SUCCESS(Status
)) {
371 MessageBoxW(hwnd
, L
"Could not get handle to mount manager.", L
"Error", MB_ICONERROR
);
375 us
.Length
= us
.MaximumLength
= wcslen(btrfs
) * sizeof(WCHAR
);
378 InitializeObjectAttributes(&attr
, &us
, 0, NULL
, NULL
);
380 Status
= NtOpenFile(&btrfsh
, SYNCHRONIZE
| FILE_READ_ATTRIBUTES
, &attr
, &iosb
,
381 FILE_SHARE_READ
| FILE_SHARE_WRITE
, FILE_SYNCHRONOUS_IO_ALERT
);
382 if (NT_SUCCESS(Status
)) {
389 bfs
= (btrfs_filesystem
*)malloc(bfssize
);
391 Status
= NtDeviceIoControlFile(btrfsh
, NULL
, NULL
, NULL
, &iosb
, IOCTL_BTRFS_QUERY_FILESYSTEMS
, NULL
, 0, bfs
, bfssize
);
392 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
) {
397 } while (Status
== STATUS_BUFFER_OVERFLOW
);
399 if (bfs
&& bfs
->num_devices
== 0) { // no mounted filesystems found
406 find_devices(hwnd
, &GUID_DEVINTERFACE_DISK
, mountmgr
, &device_list
);
407 find_devices(hwnd
, &GUID_DEVINTERFACE_VOLUME
, mountmgr
, &device_list
);
408 find_devices(hwnd
, &GUID_DEVINTERFACE_HIDDEN_VOLUME
, mountmgr
, &device_list
);
412 std::sort(device_list
.begin(), device_list
.end(), sort_devices
);
414 for (i
= 0; i
< device_list
.size(); i
++) {
415 if (!device_list
[i
].ignore
) {
421 if (device_list
[i
].disk_num
!= 0xffffffff && device_list
[i
].disk_num
== last_disk_num
)
422 tis
.hParent
= diskitem
;
424 tis
.hParent
= TVI_ROOT
;
426 tis
.hInsertAfter
= TVI_LAST
;
427 tis
.itemex
.mask
= TVIF_TEXT
| TVIF_STATE
| TVIF_PARAM
;
428 tis
.itemex
.state
= TVIS_EXPANDED
;
429 tis
.itemex
.stateMask
= TVIS_EXPANDED
;
431 if (device_list
[i
].disk_num
!= 0xffffffff) {
432 WCHAR t
[255], u
[255];
434 if (!LoadStringW(module
, device_list
[i
].part_num
!= 0 ? IDS_PARTITION
: IDS_DISK_NUM
, t
, sizeof(t
) / sizeof(WCHAR
))) {
435 ShowError(hwnd
, GetLastError());
439 if (StringCchPrintfW(u
, sizeof(u
) / sizeof(WCHAR
), t
, device_list
[i
].part_num
!= 0 ? device_list
[i
].part_num
: device_list
[i
].disk_num
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
444 name
= device_list
[i
].pnp_name
;
446 // match child Btrfs devices to their parent
447 if (bfs
&& device_list
[i
].drive
== L
"" && device_list
[i
].fstype
== L
"Btrfs") {
448 btrfs_filesystem
* bfs2
= bfs
;
451 if (RtlCompareMemory(&bfs2
->uuid
, &device_list
[i
].fs_uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
453 btrfs_filesystem_device
* dev
;
455 for (j
= 0; j
< bfs2
->num_devices
; j
++) {
459 dev
= (btrfs_filesystem_device
*)((UINT8
*)dev
+ offsetof(btrfs_filesystem_device
, name
[0]) + dev
->name_length
);
461 if (RtlCompareMemory(&device_list
[i
].dev_uuid
, &device_list
[i
].dev_uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
462 for (k
= 0; k
< device_list
.size(); k
++) {
463 if (k
!= i
&& device_list
[k
].fstype
== L
"Btrfs" && device_list
[k
].drive
!= L
"" &&
464 RtlCompareMemory(&device_list
[k
].fs_uuid
, &device_list
[i
].fs_uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
465 device_list
[i
].drive
= device_list
[k
].drive
;
470 device_list
[i
].multi_device
= bfs2
->num_devices
> 1;
479 if (bfs2
->next_entry
!= 0)
480 bfs2
= (btrfs_filesystem
*)((UINT8
*)bfs2
+ bfs2
->next_entry
);
488 if (device_list
[i
].friendly_name
!= L
"") {
489 name
+= device_list
[i
].friendly_name
;
493 if (device_list
[i
].drive
!= L
"") {
494 name
+= device_list
[i
].drive
;
498 if (device_list
[i
].fstype
!= L
"") {
499 name
+= device_list
[i
].fstype
;
503 format_size(device_list
[i
].size
, size
, sizeof(size
) / sizeof(WCHAR
), FALSE
);
508 tis
.itemex
.pszText
= (WCHAR
*)name
.c_str();
509 tis
.itemex
.cchTextMax
= name
.length();
510 tis
.itemex
.lParam
= (LPARAM
)&device_list
[i
];
512 item
= (HTREEITEM
)SendMessageW(tree
, TVM_INSERTITEMW
, 0, (LPARAM
)&tis
);
514 MessageBoxW(hwnd
, L
"TVM_INSERTITEM failed", L
"Error", MB_ICONERROR
);
518 if (device_list
[i
].part_num
== 0) {
520 last_disk_num
= device_list
[i
].disk_num
;
526 void BtrfsDeviceAdd::AddDevice(HWND hwndDlg
) {
527 WCHAR mess
[255], title
[255];
530 OBJECT_ATTRIBUTES attr
;
531 IO_STATUS_BLOCK iosb
;
535 EndDialog(hwndDlg
, 0);
539 if (sel
->fstype
!= L
"") {
542 if (!LoadStringW(module
, IDS_ADD_DEVICE_CONFIRMATION_FS
, s
, sizeof(s
) / sizeof(WCHAR
))) {
543 ShowError(hwndDlg
, GetLastError());
547 if (StringCchPrintfW(mess
, sizeof(mess
) / sizeof(WCHAR
), s
, sel
->fstype
.c_str()) == STRSAFE_E_INSUFFICIENT_BUFFER
)
550 if (!LoadStringW(module
, IDS_ADD_DEVICE_CONFIRMATION
, mess
, sizeof(mess
) / sizeof(WCHAR
))) {
551 ShowError(hwndDlg
, GetLastError());
556 if (!LoadStringW(module
, IDS_CONFIRMATION_TITLE
, title
, sizeof(title
) / sizeof(WCHAR
))) {
557 ShowError(hwndDlg
, GetLastError());
561 if (MessageBoxW(hwndDlg
, mess
, title
, MB_YESNO
) != IDYES
)
564 h
= CreateFileW(cmdline
, FILE_TRAVERSE
| FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
,
565 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, NULL
);
567 if (h
== INVALID_HANDLE_VALUE
) {
568 ShowError(hwndDlg
, GetLastError());
572 vn
.Length
= vn
.MaximumLength
= sel
->pnp_name
.length() * sizeof(WCHAR
);
573 vn
.Buffer
= (WCHAR
*)sel
->pnp_name
.c_str();
575 InitializeObjectAttributes(&attr
, &vn
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, NULL
, NULL
);
577 Status
= NtOpenFile(&h2
, FILE_GENERIC_READ
| FILE_GENERIC_WRITE
, &attr
, &iosb
, FILE_SHARE_READ
, FILE_SYNCHRONOUS_IO_ALERT
);
578 if (!NT_SUCCESS(Status
)) {
579 ShowNtStatusError(hwndDlg
, Status
);
585 Status
= NtFsControlFile(h2
, NULL
, NULL
, NULL
, &iosb
, FSCTL_LOCK_VOLUME
, NULL
, 0, NULL
, 0);
586 if (!NT_SUCCESS(Status
)) {
587 WCHAR t
[255], u
[255];
589 if (!LoadStringW(module
, IDS_LOCK_FAILED
, t
, sizeof(t
) / sizeof(WCHAR
))) {
590 ShowError(hwnd
, GetLastError());
594 if (StringCchPrintfW(u
, sizeof(u
) / sizeof(WCHAR
), t
, Status
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
597 if (!LoadStringW(module
, IDS_ERROR
, title
, sizeof(title
) / sizeof(WCHAR
))) {
598 ShowError(hwndDlg
, GetLastError());
602 MessageBoxW(hwndDlg
, u
, title
, MB_ICONERROR
);
610 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_ADD_DEVICE
, &h2
, sizeof(HANDLE
), NULL
, 0);
611 if (!NT_SUCCESS(Status
)) {
612 ShowNtStatusError(hwndDlg
, Status
);
619 Status
= NtFsControlFile(h2
, NULL
, NULL
, NULL
, &iosb
, FSCTL_DISMOUNT_VOLUME
, NULL
, 0, NULL
, 0);
620 if (!NT_SUCCESS(Status
))
621 ShowNtStatusError(hwndDlg
, Status
);
623 Status
= NtFsControlFile(h2
, NULL
, NULL
, NULL
, &iosb
, FSCTL_UNLOCK_VOLUME
, NULL
, 0, NULL
, 0);
624 if (!NT_SUCCESS(Status
))
625 ShowNtStatusError(hwndDlg
, Status
);
631 EndDialog(hwndDlg
, 0);
634 INT_PTR CALLBACK
BtrfsDeviceAdd::DeviceAddDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
638 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
639 populate_device_tree(GetDlgItem(hwndDlg
, IDC_DEVICE_TREE
));
640 EnableWindow(GetDlgItem(hwndDlg
, IDOK
), FALSE
);
645 switch (HIWORD(wParam
)) {
647 switch (LOWORD(wParam
)) {
653 EndDialog(hwndDlg
, 0);
661 switch (((LPNMHDR
)lParam
)->code
) {
662 case TVN_SELCHANGEDW
:
664 NMTREEVIEWW
* nmtv
= (NMTREEVIEWW
*)lParam
;
668 RtlZeroMemory(&tvi
, sizeof(TVITEMW
));
669 tvi
.hItem
= nmtv
->itemNew
.hItem
;
670 tvi
.mask
= TVIF_PARAM
| TVIF_HANDLE
;
672 if (SendMessageW(GetDlgItem(hwndDlg
, IDC_DEVICE_TREE
), TVM_GETITEMW
, 0, (LPARAM
)&tvi
))
673 sel
= tvi
.lParam
== 0 ? NULL
: (device
*)tvi
.lParam
;
678 enable
= (!sel
->is_disk
|| !sel
->has_parts
) && !sel
->multi_device
;
680 EnableWindow(GetDlgItem(hwndDlg
, IDOK
), enable
);
690 static INT_PTR CALLBACK
stub_DeviceAddDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
693 if (uMsg
== WM_INITDIALOG
) {
694 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
695 bda
= (BtrfsDeviceAdd
*)lParam
;
697 bda
= (BtrfsDeviceAdd
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
701 return bda
->DeviceAddDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
706 void BtrfsDeviceAdd::ShowDialog() {
707 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_DEVICE_ADD
), hwnd
, stub_DeviceAddDlgProc
, (LPARAM
)this);
710 BtrfsDeviceAdd::BtrfsDeviceAdd(HINSTANCE hinst
, HWND hwnd
, WCHAR
* cmdline
) {
713 this->cmdline
= cmdline
;
718 void BtrfsDeviceResize::do_resize(HWND hwndDlg
) {
721 IO_STATUS_BLOCK iosb
;
724 h
= CreateFileW(fn
, FILE_TRAVERSE
| FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
,
725 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, NULL
);
727 if (h
== INVALID_HANDLE_VALUE
) {
728 ShowError(hwndDlg
, GetLastError());
735 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_RESIZE
, &br
, sizeof(btrfs_resize
), NULL
, 0);
737 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
)) {
738 ShowNtStatusError(hwndDlg
, Status
);
745 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
) {
746 WCHAR s
[255], t
[255], u
[255];
748 LoadStringW(module
, IDS_RESIZE_SUCCESSFUL
, s
, sizeof(s
) / sizeof(WCHAR
));
749 format_size(new_size
, u
, sizeof(u
) / sizeof(WCHAR
), TRUE
);
750 StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), s
, dev_id
, u
);
751 MessageBoxW(hwndDlg
, t
, L
"", MB_OK
);
753 EndDialog(hwndDlg
, 0);
758 par
= GetParent(hwndDlg
);
759 EndDialog(hwndDlg
, 0);
761 bb
= new BtrfsBalance(fn
, FALSE
, TRUE
);
763 bb
->ShowBalance(par
);
769 INT_PTR CALLBACK
BtrfsDeviceResize::DeviceResizeDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
774 WCHAR s
[255], t
[255], u
[255];
776 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
778 GetDlgItemTextW(hwndDlg
, IDC_RESIZE_DEVICE_ID
, s
, sizeof(s
) / sizeof(WCHAR
));
779 StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), s
, dev_id
);
780 SetDlgItemTextW(hwndDlg
, IDC_RESIZE_DEVICE_ID
, t
);
782 h
= CreateFileW(fn
, FILE_TRAVERSE
| FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
,
783 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, NULL
);
785 if (h
!= INVALID_HANDLE_VALUE
) {
787 IO_STATUS_BLOCK iosb
;
788 btrfs_device
*devices
, *bd
;
794 devices
= (btrfs_device
*)malloc(devsize
);
797 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_GET_DEVICES
, NULL
, 0, devices
, devsize
);
798 if (Status
== STATUS_BUFFER_OVERFLOW
) {
802 devices
= (btrfs_device
*)malloc(devsize
);
807 if (!NT_SUCCESS(Status
)) {
816 if (bd
->dev_id
== dev_id
) {
817 memcpy(&dev_info
, bd
, sizeof(btrfs_device
));
822 if (bd
->next_entry
> 0)
823 bd
= (btrfs_device
*)((UINT8
*)bd
+ bd
->next_entry
);
837 GetDlgItemTextW(hwndDlg
, IDC_RESIZE_CURSIZE
, s
, sizeof(s
) / sizeof(WCHAR
));
838 format_size(dev_info
.size
, u
, sizeof(u
) / sizeof(WCHAR
), TRUE
);
839 StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), s
, u
);
840 SetDlgItemTextW(hwndDlg
, IDC_RESIZE_CURSIZE
, t
);
842 new_size
= dev_info
.size
;
844 GetDlgItemTextW(hwndDlg
, IDC_RESIZE_NEWSIZE
, new_size_text
, sizeof(new_size_text
) / sizeof(WCHAR
));
845 StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), new_size_text
, u
);
846 SetDlgItemTextW(hwndDlg
, IDC_RESIZE_NEWSIZE
, t
);
848 slider
= GetDlgItem(hwndDlg
, IDC_RESIZE_SLIDER
);
849 SendMessageW(slider
, TBM_SETRANGEMIN
, FALSE
, 0);
850 SendMessageW(slider
, TBM_SETRANGEMAX
, FALSE
, dev_info
.max_size
/ 1048576);
851 SendMessageW(slider
, TBM_SETPOS
, TRUE
, new_size
/ 1048576);
859 switch (HIWORD(wParam
)) {
861 switch (LOWORD(wParam
)) {
867 EndDialog(hwndDlg
, 0);
876 WCHAR t
[255], u
[255];
878 new_size
= UInt32x32To64(SendMessageW(GetDlgItem(hwndDlg
, IDC_RESIZE_SLIDER
), TBM_GETPOS
, 0, 0), 1048576);
880 format_size(new_size
, u
, sizeof(u
) / sizeof(WCHAR
), TRUE
);
881 StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), new_size_text
, u
);
882 SetDlgItemTextW(hwndDlg
, IDC_RESIZE_NEWSIZE
, t
);
884 EnableWindow(GetDlgItem(hwndDlg
, IDOK
), new_size
> 0 ? TRUE
: FALSE
);
893 static INT_PTR CALLBACK
stub_DeviceResizeDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
894 BtrfsDeviceResize
* bdr
;
896 if (uMsg
== WM_INITDIALOG
) {
897 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
898 bdr
= (BtrfsDeviceResize
*)lParam
;
900 bdr
= (BtrfsDeviceResize
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
903 return bdr
->DeviceResizeDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
908 void BtrfsDeviceResize::ShowDialog(HWND hwnd
, WCHAR
* fn
, UINT64 dev_id
) {
909 this->dev_id
= dev_id
;
910 wcscpy(this->fn
, fn
);
912 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_RESIZE
), hwnd
, stub_DeviceResizeDlgProc
, (LPARAM
)this);
919 void CALLBACK
AddDeviceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
927 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
)) {
928 ShowError(hwnd
, GetLastError());
932 if (!LookupPrivilegeValueW(NULL
, L
"SeManageVolumePrivilege", &luid
)) {
933 ShowError(hwnd
, GetLastError());
937 tp
.PrivilegeCount
= 1;
938 tp
.Privileges
[0].Luid
= luid
;
939 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
941 if (!AdjustTokenPrivileges(token
, FALSE
, &tp
, sizeof(TOKEN_PRIVILEGES
), NULL
, NULL
)) {
942 ShowError(hwnd
, GetLastError());
946 bda
= new BtrfsDeviceAdd(hinst
, hwnd
, lpszCmdLine
);
954 void CALLBACK
RemoveDeviceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
955 WCHAR
*s
, *vol
, *dev
;
961 IO_STATUS_BLOCK iosb
;
966 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
)) {
967 ShowError(hwnd
, GetLastError());
971 if (!LookupPrivilegeValueW(NULL
, L
"SeManageVolumePrivilege", &luid
)) {
972 ShowError(hwnd
, GetLastError());
976 tp
.PrivilegeCount
= 1;
977 tp
.Privileges
[0].Luid
= luid
;
978 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
980 if (!AdjustTokenPrivileges(token
, FALSE
, &tp
, sizeof(TOKEN_PRIVILEGES
), NULL
, NULL
)) {
981 ShowError(hwnd
, GetLastError());
985 s
= wcsstr(lpszCmdLine
, L
"|");
998 h
= CreateFileW(vol
, FILE_TRAVERSE
| FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, NULL
,
999 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, NULL
);
1001 if (h
== INVALID_HANDLE_VALUE
) {
1002 ShowError(hwnd
, GetLastError());
1006 Status
= NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_REMOVE_DEVICE
, &devid
, sizeof(UINT64
), NULL
, 0);
1007 if (!NT_SUCCESS(Status
)) {
1008 if (Status
== STATUS_CANNOT_DELETE
)
1009 ShowStringError(hwnd
, IDS_CANNOT_REMOVE_RAID
);
1011 ShowNtStatusError(hwnd
, Status
);
1019 bb
= new BtrfsBalance(vol
, TRUE
);
1021 bb
->ShowBalance(hwnd
);
1029 void CALLBACK
ResizeDeviceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
1030 WCHAR
*s
, *vol
, *dev
;
1033 TOKEN_PRIVILEGES tp
;
1035 BtrfsDeviceResize
* bdr
;
1039 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
)) {
1040 ShowError(hwnd
, GetLastError());
1044 if (!LookupPrivilegeValueW(NULL
, L
"SeManageVolumePrivilege", &luid
)) {
1045 ShowError(hwnd
, GetLastError());
1049 tp
.PrivilegeCount
= 1;
1050 tp
.Privileges
[0].Luid
= luid
;
1051 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
1053 if (!AdjustTokenPrivileges(token
, FALSE
, &tp
, sizeof(TOKEN_PRIVILEGES
), NULL
, NULL
)) {
1054 ShowError(hwnd
, GetLastError());
1058 s
= wcsstr(lpszCmdLine
, L
"|");
1071 bdr
= new BtrfsDeviceResize
;
1072 bdr
->ShowDialog(hwnd
, vol
, devid
);