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
36 #include <ndk/rtlfuncs.h>
37 #include <ndk/obfuncs.h>
39 #include "mountmgr_local.h"
42 DEFINE_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME
, 0x7f108a28L
, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62);
44 static wstring
get_mountdev_name(const nt_handle
& h
) {
47 MOUNTDEV_NAME mdn
, *mdn2
;
50 Status
= NtDeviceIoControlFile(h
, nullptr, nullptr, nullptr, &iosb
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
51 nullptr, 0, &mdn
, sizeof(MOUNTDEV_NAME
));
52 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
)
55 size_t mdnsize
= offsetof(MOUNTDEV_NAME
, Name
[0]) + mdn
.NameLength
;
57 mdn2
= (MOUNTDEV_NAME
*)malloc(mdnsize
);
59 Status
= NtDeviceIoControlFile(h
, nullptr, nullptr, nullptr, &iosb
, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
,
60 nullptr, 0, mdn2
, (ULONG
)mdnsize
);
61 if (!NT_SUCCESS(Status
)) {
66 name
= wstring(mdn2
->Name
, mdn2
->NameLength
/ sizeof(WCHAR
));
73 static void find_devices(HWND hwnd
, const GUID
* guid
, const mountmgr
& mm
, vector
<device
>& device_list
) {
76 static const wstring dosdevices
= L
"\\DosDevices\\";
78 h
= SetupDiGetClassDevsW(guid
, nullptr, 0, DIGCF_DEVICEINTERFACE
| DIGCF_PRESENT
);
80 if (h
!= INVALID_HANDLE_VALUE
) {
82 SP_DEVICE_INTERFACE_DATA did
;
84 did
.cbSize
= sizeof(did
);
86 if (!SetupDiEnumDeviceInterfaces(h
, nullptr, guid
, index
, &did
))
91 SP_DEVICE_INTERFACE_DETAIL_DATA_W
* detail
;
94 dd
.cbSize
= sizeof(dd
);
96 SetupDiGetDeviceInterfaceDetailW(h
, &did
, nullptr, 0, &size
, nullptr);
98 detail
= (SP_DEVICE_INTERFACE_DETAIL_DATA_W
*)malloc(size
);
99 memset(detail
, 0, size
);
101 detail
->cbSize
= sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W
);
103 if (SetupDiGetDeviceInterfaceDetailW(h
, &did
, detail
, size
, &size
, &dd
)) {
107 STORAGE_DEVICE_NUMBER sdn
;
108 IO_STATUS_BLOCK iosb
;
110 OBJECT_ATTRIBUTES attr
;
111 GET_LENGTH_INFORMATION gli
;
115 path
.Buffer
= detail
->DevicePath
;
116 path
.Length
= path
.MaximumLength
= (uint16_t)(wcslen(detail
->DevicePath
) * sizeof(WCHAR
));
118 if (path
.Length
> 4 * sizeof(WCHAR
) && path
.Buffer
[0] == '\\' && path
.Buffer
[1] == '\\' && path
.Buffer
[2] == '?' && path
.Buffer
[3] == '\\')
119 path
.Buffer
[1] = '?';
121 InitializeObjectAttributes(&attr
, &path
, 0, nullptr, nullptr);
123 Status
= NtOpenFile(&file
, FILE_GENERIC_READ
, &attr
, &iosb
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, FILE_SYNCHRONOUS_IO_ALERT
);
125 if (!NT_SUCCESS(Status
)) {
131 dev
.pnp_name
= detail
->DevicePath
;
133 Status
= NtDeviceIoControlFile(file
, nullptr, nullptr, nullptr, &iosb
, IOCTL_DISK_GET_LENGTH_INFO
, nullptr, 0, &gli
, sizeof(GET_LENGTH_INFORMATION
));
134 if (!NT_SUCCESS(Status
)) {
140 dev
.size
= gli
.Length
.QuadPart
;
142 Status
= NtDeviceIoControlFile(file
, nullptr, nullptr, nullptr, &iosb
, IOCTL_STORAGE_GET_DEVICE_NUMBER
, nullptr, 0, &sdn
, sizeof(STORAGE_DEVICE_NUMBER
));
143 if (!NT_SUCCESS(Status
)) {
144 dev
.disk_num
= 0xffffffff;
145 dev
.part_num
= 0xffffffff;
147 dev
.disk_num
= sdn
.DeviceNumber
;
148 dev
.part_num
= sdn
.PartitionNumber
;
151 dev
.friendly_name
= L
"";
154 dev
.has_parts
= false;
156 dev
.multi_device
= false;
158 dev
.is_disk
= RtlCompareMemory(guid
, &GUID_DEVINTERFACE_DISK
, sizeof(GUID
)) == sizeof(GUID
);
161 STORAGE_PROPERTY_QUERY spq
;
162 STORAGE_DEVICE_DESCRIPTOR sdd
, *sdd2
;
164 DRIVE_LAYOUT_INFORMATION_EX
* dli
;
166 spq
.PropertyId
= StorageDeviceProperty
;
167 spq
.QueryType
= PropertyStandardQuery
;
168 spq
.AdditionalParameters
[0] = 0;
170 Status
= NtDeviceIoControlFile(file
, nullptr, nullptr, nullptr, &iosb
, IOCTL_STORAGE_QUERY_PROPERTY
,
171 &spq
, sizeof(STORAGE_PROPERTY_QUERY
), &sdd
, sizeof(STORAGE_DEVICE_DESCRIPTOR
));
173 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_OVERFLOW
) {
174 sdd2
= (STORAGE_DEVICE_DESCRIPTOR
*)malloc(sdd
.Size
);
176 Status
= NtDeviceIoControlFile(file
, nullptr, nullptr, nullptr, &iosb
, IOCTL_STORAGE_QUERY_PROPERTY
,
177 &spq
, sizeof(STORAGE_PROPERTY_QUERY
), sdd2
, sdd
.Size
);
178 if (NT_SUCCESS(Status
)) {
183 if (sdd2
->VendorIdOffset
!= 0) {
184 desc2
+= (char*)((uint8_t*)sdd2
+ sdd2
->VendorIdOffset
);
186 while (desc2
.length() > 0 && desc2
[desc2
.length() - 1] == ' ')
187 desc2
= desc2
.substr(0, desc2
.length() - 1);
190 if (sdd2
->ProductIdOffset
!= 0) {
191 if (sdd2
->VendorIdOffset
!= 0 && desc2
.length() != 0 && desc2
[desc2
.length() - 1] != ' ')
194 desc2
+= (char*)((uint8_t*)sdd2
+ sdd2
->ProductIdOffset
);
196 while (desc2
.length() > 0 && desc2
[desc2
.length() - 1] == ' ')
197 desc2
= desc2
.substr(0, desc2
.length() - 1);
200 if (sdd2
->VendorIdOffset
!= 0 || sdd2
->ProductIdOffset
!= 0) {
203 ss
= MultiByteToWideChar(CP_OEMCP
, MB_PRECOMPOSED
, desc2
.c_str(), -1, nullptr, 0);
206 WCHAR
* desc3
= (WCHAR
*)malloc(ss
* sizeof(WCHAR
));
208 if (MultiByteToWideChar(CP_OEMCP
, MB_PRECOMPOSED
, desc2
.c_str(), -1, desc3
, ss
))
209 dev
.friendly_name
= desc3
;
228 dli
= (DRIVE_LAYOUT_INFORMATION_EX
*)malloc(dlisize
);
230 Status
= NtDeviceIoControlFile(file
, nullptr, nullptr, nullptr, &iosb
, IOCTL_DISK_GET_DRIVE_LAYOUT_EX
,
231 nullptr, 0, dli
, dlisize
);
232 } while (Status
== STATUS_BUFFER_TOO_SMALL
);
234 if (NT_SUCCESS(Status
) && dli
->PartitionCount
> 0)
235 dev
.has_parts
= true;
240 auto v
= mm
.query_points(L
"", L
"", wstring_view(path
.Buffer
, path
.Length
/ sizeof(WCHAR
)));
243 for (const auto& p
: v
) {
244 if (p
.symlink
.length() == 14 && p
.symlink
.substr(0, dosdevices
.length()) == dosdevices
&& p
.symlink
[13] == ':') {
246 for(auto p
= v
.begin(); p
!= v
.end(); ++p
) {
247 if ((*p
).symlink
.length() == 14 && (*p
).symlink
.substr(0, dosdevices
.length()) == dosdevices
&& (*p
).symlink
[13] == ':') {
252 dr
[0] = p
.symlink
[12];
254 dr
[0] = (*p
).symlink
[12];
263 } catch (...) { // don't fail entirely if mountmgr refuses to co-operate
267 if (!dev
.is_disk
|| !dev
.has_parts
) {
269 while (fs_ident
[i
].name
) {
270 if (i
== 0 || fs_ident
[i
].kboff
!= fs_ident
[i
-1].kboff
) {
273 off
.QuadPart
= fs_ident
[i
].kboff
* 1024;
274 Status
= NtReadFile(file
, nullptr, nullptr, nullptr, &iosb
, sb
, sizeof(sb
), &off
, nullptr);
277 if (NT_SUCCESS(Status
)) {
278 if (RtlCompareMemory(sb
+ fs_ident
[i
].sboff
, fs_ident
[i
].magic
, fs_ident
[i
].magiclen
) == fs_ident
[i
].magiclen
) {
279 dev
.fstype
= fs_ident
[i
].name
;
281 if (dev
.fstype
== L
"Btrfs") {
282 superblock
* bsb
= (superblock
*)sb
;
284 RtlCopyMemory(&dev
.fs_uuid
, &bsb
->uuid
, sizeof(BTRFS_UUID
));
285 RtlCopyMemory(&dev
.dev_uuid
, &bsb
->dev_item
.device_uuid
, sizeof(BTRFS_UUID
));
295 if (dev
.fstype
== L
"Btrfs" && RtlCompareMemory(guid
, &GUID_DEVINTERFACE_DISK
, sizeof(GUID
)) != sizeof(GUID
)) {
297 wstring pref
= L
"\\Device\\Btrfs{";
299 name
= get_mountdev_name(file
);
301 if (name
.length() > pref
.length() && RtlCompareMemory(name
.c_str(), pref
.c_str(), pref
.length() * sizeof(WCHAR
)) == pref
.length() * sizeof(WCHAR
))
306 device_list
.push_back(dev
);
312 } while (SetupDiEnumDeviceInterfaces(h
, nullptr, guid
, index
, &did
));
314 SetupDiDestroyDeviceInfoList(h
);
316 throw last_error(GetLastError());
319 #ifndef __REACTOS__ // Disabled because building with our <algorithm> seems complex right now...
320 static bool sort_devices(device i
, device j
) {
321 if (i
.disk_num
< j
.disk_num
)
324 if (i
.disk_num
== j
.disk_num
&& i
.part_num
< j
.part_num
)
331 void BtrfsDeviceAdd::populate_device_tree(HWND tree
) {
332 HWND hwnd
= GetParent(tree
);
334 ULONG last_disk_num
= 0xffffffff;
337 OBJECT_ATTRIBUTES attr
;
339 IO_STATUS_BLOCK iosb
;
340 btrfs_filesystem
* bfs
= nullptr;
342 static WCHAR btrfs
[] = L
"\\Btrfs";
352 us
.Length
= us
.MaximumLength
= (uint16_t)(wcslen(btrfs
) * sizeof(WCHAR
));
355 InitializeObjectAttributes(&attr
, &us
, 0, nullptr, nullptr);
357 Status
= NtOpenFile(&btrfsh
, SYNCHRONIZE
| FILE_READ_ATTRIBUTES
, &attr
, &iosb
,
358 FILE_SHARE_READ
| FILE_SHARE_WRITE
, FILE_SYNCHRONOUS_IO_ALERT
);
359 if (NT_SUCCESS(Status
)) {
366 bfs
= (btrfs_filesystem
*)malloc(bfssize
);
368 Status
= NtDeviceIoControlFile(btrfsh
, nullptr, nullptr, nullptr, &iosb
, IOCTL_BTRFS_QUERY_FILESYSTEMS
, nullptr, 0, bfs
, bfssize
);
369 if (!NT_SUCCESS(Status
) && Status
!= STATUS_BUFFER_OVERFLOW
) {
374 } while (Status
== STATUS_BUFFER_OVERFLOW
);
376 if (bfs
&& bfs
->num_devices
== 0) { // no mounted filesystems found
383 find_devices(hwnd
, &GUID_DEVINTERFACE_DISK
, mm
, device_list
);
384 find_devices(hwnd
, &GUID_DEVINTERFACE_VOLUME
, mm
, device_list
);
385 find_devices(hwnd
, &GUID_DEVINTERFACE_HIDDEN_VOLUME
, mm
, device_list
);
388 #ifndef __REACTOS__ // Disabled because building with our <algorithm> seems complex right now...
389 sort(device_list
.begin(), device_list
.end(), sort_devices
);
392 for (i
= 0; i
< device_list
.size(); i
++) {
393 if (!device_list
[i
].ignore
) {
398 if (device_list
[i
].disk_num
!= 0xffffffff && device_list
[i
].disk_num
== last_disk_num
)
399 tis
.hParent
= diskitem
;
401 tis
.hParent
= TVI_ROOT
;
403 tis
.hInsertAfter
= TVI_LAST
;
404 tis
.itemex
.mask
= TVIF_TEXT
| TVIF_STATE
| TVIF_PARAM
;
405 tis
.itemex
.state
= TVIS_EXPANDED
;
406 tis
.itemex
.stateMask
= TVIS_EXPANDED
;
408 if (device_list
[i
].disk_num
!= 0xffffffff) {
411 if (!load_string(module
, device_list
[i
].part_num
!= 0 ? IDS_PARTITION
: IDS_DISK_NUM
, t
))
412 throw last_error(GetLastError());
414 wstring_sprintf(name
, t
, device_list
[i
].part_num
!= 0 ? device_list
[i
].part_num
: device_list
[i
].disk_num
);
416 name
= device_list
[i
].pnp_name
;
418 // match child Btrfs devices to their parent
419 if (bfs
&& device_list
[i
].drive
== L
"" && device_list
[i
].fstype
== L
"Btrfs") {
420 btrfs_filesystem
* bfs2
= bfs
;
423 if (RtlCompareMemory(&bfs2
->uuid
, &device_list
[i
].fs_uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
425 btrfs_filesystem_device
* dev
;
427 for (j
= 0; j
< bfs2
->num_devices
; j
++) {
431 dev
= (btrfs_filesystem_device
*)((uint8_t*)dev
+ offsetof(btrfs_filesystem_device
, name
[0]) + dev
->name_length
);
433 if (RtlCompareMemory(&device_list
[i
].dev_uuid
, &device_list
[i
].dev_uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
434 for (k
= 0; k
< device_list
.size(); k
++) {
435 if (k
!= i
&& device_list
[k
].fstype
== L
"Btrfs" && device_list
[k
].drive
!= L
"" &&
436 RtlCompareMemory(&device_list
[k
].fs_uuid
, &device_list
[i
].fs_uuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
437 device_list
[i
].drive
= device_list
[k
].drive
;
442 device_list
[i
].multi_device
= bfs2
->num_devices
> 1;
451 if (bfs2
->next_entry
!= 0)
452 bfs2
= (btrfs_filesystem
*)((uint8_t*)bfs2
+ bfs2
->next_entry
);
460 if (device_list
[i
].friendly_name
!= L
"") {
461 name
+= device_list
[i
].friendly_name
;
465 if (device_list
[i
].drive
!= L
"") {
466 name
+= device_list
[i
].drive
;
470 if (device_list
[i
].fstype
!= L
"") {
471 name
+= device_list
[i
].fstype
;
475 format_size(device_list
[i
].size
, size
, false);
480 tis
.itemex
.pszText
= (WCHAR
*)name
.c_str();
481 tis
.itemex
.cchTextMax
= (int)name
.length();
482 tis
.itemex
.lParam
= (LPARAM
)&device_list
[i
];
484 item
= (HTREEITEM
)SendMessageW(tree
, TVM_INSERTITEMW
, 0, (LPARAM
)&tis
);
486 throw string_error(IDS_TVM_INSERTITEM_FAILED
);
488 if (device_list
[i
].part_num
== 0) {
490 last_disk_num
= device_list
[i
].disk_num
;
496 void BtrfsDeviceAdd::AddDevice(HWND hwndDlg
) {
500 OBJECT_ATTRIBUTES attr
;
501 IO_STATUS_BLOCK iosb
;
504 EndDialog(hwndDlg
, 0);
508 if (sel
->fstype
!= L
"") {
511 if (!load_string(module
, IDS_ADD_DEVICE_CONFIRMATION_FS
, s
))
512 throw last_error(GetLastError());
514 wstring_sprintf(mess
, s
, sel
->fstype
.c_str());
516 if (!load_string(module
, IDS_ADD_DEVICE_CONFIRMATION
, mess
))
517 throw last_error(GetLastError());
520 if (!load_string(module
, IDS_CONFIRMATION_TITLE
, title
))
521 throw last_error(GetLastError());
523 if (MessageBoxW(hwndDlg
, mess
.c_str(), title
.c_str(), MB_YESNO
) != IDYES
)
526 win_handle h
= CreateFileW(cmdline
, FILE_TRAVERSE
| FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr,
527 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, nullptr);
529 if (h
== INVALID_HANDLE_VALUE
)
530 throw last_error(GetLastError());
535 vn
.Length
= vn
.MaximumLength
= (uint16_t)(sel
->pnp_name
.length() * sizeof(WCHAR
));
536 vn
.Buffer
= (WCHAR
*)sel
->pnp_name
.c_str();
538 InitializeObjectAttributes(&attr
, &vn
, OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
, nullptr, nullptr);
540 Status
= NtOpenFile(&h2
, FILE_GENERIC_READ
| FILE_GENERIC_WRITE
, &attr
, &iosb
, FILE_SHARE_READ
, FILE_SYNCHRONOUS_IO_ALERT
);
541 if (!NT_SUCCESS(Status
))
542 throw ntstatus_error(Status
);
545 Status
= NtFsControlFile(h2
, nullptr, nullptr, nullptr, &iosb
, FSCTL_LOCK_VOLUME
, nullptr, 0, nullptr, 0);
546 if (!NT_SUCCESS(Status
))
547 throw string_error(IDS_LOCK_FAILED
, Status
);
550 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_ADD_DEVICE
, &h2
, sizeof(HANDLE
), nullptr, 0);
551 if (!NT_SUCCESS(Status
))
552 throw ntstatus_error(Status
);
555 Status
= NtFsControlFile(h2
, nullptr, nullptr, nullptr, &iosb
, FSCTL_DISMOUNT_VOLUME
, nullptr, 0, nullptr, 0);
556 if (!NT_SUCCESS(Status
))
557 throw ntstatus_error(Status
);
559 Status
= NtFsControlFile(h2
, nullptr, nullptr, nullptr, &iosb
, FSCTL_UNLOCK_VOLUME
, nullptr, 0, nullptr, 0);
560 if (!NT_SUCCESS(Status
))
561 throw ntstatus_error(Status
);
565 EndDialog(hwndDlg
, 0);
568 INT_PTR CALLBACK
BtrfsDeviceAdd::DeviceAddDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
573 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
574 populate_device_tree(GetDlgItem(hwndDlg
, IDC_DEVICE_TREE
));
575 EnableWindow(GetDlgItem(hwndDlg
, IDOK
), false);
580 switch (HIWORD(wParam
)) {
582 switch (LOWORD(wParam
)) {
588 EndDialog(hwndDlg
, 0);
596 switch (((LPNMHDR
)lParam
)->code
) {
597 case TVN_SELCHANGEDW
:
599 NMTREEVIEWW
* nmtv
= (NMTREEVIEWW
*)lParam
;
603 RtlZeroMemory(&tvi
, sizeof(TVITEMW
));
604 tvi
.hItem
= nmtv
->itemNew
.hItem
;
605 tvi
.mask
= TVIF_PARAM
| TVIF_HANDLE
;
607 if (SendMessageW(GetDlgItem(hwndDlg
, IDC_DEVICE_TREE
), TVM_GETITEMW
, 0, (LPARAM
)&tvi
))
608 sel
= tvi
.lParam
== 0 ? nullptr : (device
*)tvi
.lParam
;
613 enable
= (!sel
->is_disk
|| !sel
->has_parts
) && !sel
->multi_device
;
615 EnableWindow(GetDlgItem(hwndDlg
, IDOK
), enable
);
621 } catch (const exception
& e
) {
622 error_message(hwndDlg
, e
.what());
628 static INT_PTR CALLBACK
stub_DeviceAddDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
631 if (uMsg
== WM_INITDIALOG
) {
632 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
633 bda
= (BtrfsDeviceAdd
*)lParam
;
635 bda
= (BtrfsDeviceAdd
*)GetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
);
639 return bda
->DeviceAddDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
644 void BtrfsDeviceAdd::ShowDialog() {
645 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_DEVICE_ADD
), hwnd
, stub_DeviceAddDlgProc
, (LPARAM
)this);
648 BtrfsDeviceAdd::BtrfsDeviceAdd(HINSTANCE hinst
, HWND hwnd
, WCHAR
* cmdline
) {
651 this->cmdline
= cmdline
;
656 void BtrfsDeviceResize::do_resize(HWND hwndDlg
) {
658 IO_STATUS_BLOCK iosb
;
662 win_handle h
= CreateFileW(fn
.c_str(), FILE_TRAVERSE
| FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr,
663 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, nullptr);
665 if (h
== INVALID_HANDLE_VALUE
)
666 throw last_error(GetLastError());
671 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_RESIZE
, &br
, sizeof(btrfs_resize
), nullptr, 0);
673 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
&& !NT_SUCCESS(Status
))
674 throw ntstatus_error(Status
);
677 if (Status
!= STATUS_MORE_PROCESSING_REQUIRED
) {
680 load_string(module
, IDS_RESIZE_SUCCESSFUL
, s
);
681 format_size(new_size
, u
, true);
682 wstring_sprintf(t
, s
, dev_id
, u
.c_str());
683 MessageBoxW(hwndDlg
, t
.c_str(), L
"", MB_OK
);
685 EndDialog(hwndDlg
, 0);
689 par
= GetParent(hwndDlg
);
690 EndDialog(hwndDlg
, 0);
692 BtrfsBalance
bb(fn
, false, true);
697 INT_PTR CALLBACK
BtrfsDeviceResize::DeviceResizeDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
706 EnableThemeDialogTexture(hwndDlg
, ETDT_ENABLETAB
);
708 GetDlgItemTextW(hwndDlg
, IDC_RESIZE_DEVICE_ID
, s
, sizeof(s
) / sizeof(WCHAR
));
709 wstring_sprintf(t
, s
, dev_id
);
710 SetDlgItemTextW(hwndDlg
, IDC_RESIZE_DEVICE_ID
, t
.c_str());
712 h
= CreateFileW(fn
.c_str(), FILE_TRAVERSE
| FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr,
713 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, nullptr);
715 if (h
!= INVALID_HANDLE_VALUE
) {
717 IO_STATUS_BLOCK iosb
;
718 btrfs_device
*devices
, *bd
;
724 devices
= (btrfs_device
*)malloc(devsize
);
727 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_GET_DEVICES
, nullptr, 0, devices
, devsize
);
728 if (Status
== STATUS_BUFFER_OVERFLOW
) {
732 devices
= (btrfs_device
*)malloc(devsize
);
737 if (!NT_SUCCESS(Status
)) {
745 if (bd
->dev_id
== dev_id
) {
746 memcpy(&dev_info
, bd
, sizeof(btrfs_device
));
751 if (bd
->next_entry
> 0)
752 bd
= (btrfs_device
*)((uint8_t*)bd
+ bd
->next_entry
);
764 GetDlgItemTextW(hwndDlg
, IDC_RESIZE_CURSIZE
, s
, sizeof(s
) / sizeof(WCHAR
));
765 format_size(dev_info
.size
, u
, true);
766 wstring_sprintf(t
, s
, u
.c_str());
767 SetDlgItemTextW(hwndDlg
, IDC_RESIZE_CURSIZE
, t
.c_str());
769 new_size
= dev_info
.size
;
771 GetDlgItemTextW(hwndDlg
, IDC_RESIZE_NEWSIZE
, new_size_text
, sizeof(new_size_text
) / sizeof(WCHAR
));
772 wstring_sprintf(t
, new_size_text
, u
.c_str());
773 SetDlgItemTextW(hwndDlg
, IDC_RESIZE_NEWSIZE
, t
.c_str());
775 slider
= GetDlgItem(hwndDlg
, IDC_RESIZE_SLIDER
);
776 SendMessageW(slider
, TBM_SETRANGEMIN
, false, 0);
777 SendMessageW(slider
, TBM_SETRANGEMAX
, false, (LPARAM
)(dev_info
.max_size
/ 1048576));
778 SendMessageW(slider
, TBM_SETPOS
, true, (LPARAM
)(new_size
/ 1048576));
786 switch (HIWORD(wParam
)) {
788 switch (LOWORD(wParam
)) {
794 EndDialog(hwndDlg
, 0);
805 new_size
= UInt32x32To64(SendMessageW(GetDlgItem(hwndDlg
, IDC_RESIZE_SLIDER
), TBM_GETPOS
, 0, 0), 1048576);
807 format_size(new_size
, u
, true);
808 wstring_sprintf(t
, new_size_text
, u
.c_str());
809 SetDlgItemTextW(hwndDlg
, IDC_RESIZE_NEWSIZE
, t
.c_str());
811 EnableWindow(GetDlgItem(hwndDlg
, IDOK
), new_size
> 0 ? true : false);
816 } catch (const exception
& e
) {
817 error_message(hwndDlg
, e
.what());
823 static INT_PTR CALLBACK
stub_DeviceResizeDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
824 BtrfsDeviceResize
* bdr
;
826 if (uMsg
== WM_INITDIALOG
) {
827 SetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
828 bdr
= (BtrfsDeviceResize
*)lParam
;
830 bdr
= (BtrfsDeviceResize
*)GetWindowLongPtrW(hwndDlg
, GWLP_USERDATA
);
833 return bdr
->DeviceResizeDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
838 void BtrfsDeviceResize::ShowDialog(HWND hwnd
, const wstring
& fn
, uint64_t dev_id
) {
839 this->dev_id
= dev_id
;
842 DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_RESIZE
), hwnd
, stub_DeviceResizeDlgProc
, (LPARAM
)this);
849 void CALLBACK
AddDeviceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
857 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
))
858 throw last_error(GetLastError());
860 if (!LookupPrivilegeValueW(nullptr, L
"SeManageVolumePrivilege", &luid
))
861 throw last_error(GetLastError());
863 tp
.PrivilegeCount
= 1;
864 tp
.Privileges
[0].Luid
= luid
;
865 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
867 if (!AdjustTokenPrivileges(token
, false, &tp
, sizeof(TOKEN_PRIVILEGES
), nullptr, nullptr))
868 throw last_error(GetLastError());
870 BtrfsDeviceAdd
bda(hinst
, hwnd
, lpszCmdLine
);
872 } catch (const exception
& e
) {
873 error_message(hwnd
, e
.what());
877 void CALLBACK
RemoveDeviceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
879 WCHAR
*s
, *vol
, *dev
;
885 IO_STATUS_BLOCK iosb
;
889 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
))
890 throw last_error(GetLastError());
892 if (!LookupPrivilegeValueW(nullptr, L
"SeManageVolumePrivilege", &luid
))
893 throw last_error(GetLastError());
895 tp
.PrivilegeCount
= 1;
896 tp
.Privileges
[0].Luid
= luid
;
897 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
899 if (!AdjustTokenPrivileges(token
, false, &tp
, sizeof(TOKEN_PRIVILEGES
), nullptr, nullptr))
900 throw last_error(GetLastError());
902 s
= wcsstr(lpszCmdLine
, L
"|");
915 h
= CreateFileW(vol
, FILE_TRAVERSE
| FILE_READ_ATTRIBUTES
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, nullptr,
916 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT
, nullptr);
918 if (h
== INVALID_HANDLE_VALUE
)
919 throw last_error(GetLastError());
921 Status
= NtFsControlFile(h
, nullptr, nullptr, nullptr, &iosb
, FSCTL_BTRFS_REMOVE_DEVICE
, &devid
, sizeof(uint64_t), nullptr, 0);
922 if (!NT_SUCCESS(Status
)) {
923 if (Status
== STATUS_CANNOT_DELETE
)
924 throw string_error(IDS_CANNOT_REMOVE_RAID
);
926 throw ntstatus_error(Status
);
931 BtrfsBalance
bb(vol
, true);
932 bb
.ShowBalance(hwnd
);
933 } catch (const exception
& e
) {
934 error_message(hwnd
, e
.what());
938 void CALLBACK
ResizeDeviceW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
940 WCHAR
*s
, *vol
, *dev
;
948 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
))
949 throw last_error(GetLastError());
951 if (!LookupPrivilegeValueW(nullptr, L
"SeManageVolumePrivilege", &luid
))
952 throw last_error(GetLastError());
954 tp
.PrivilegeCount
= 1;
955 tp
.Privileges
[0].Luid
= luid
;
956 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
958 if (!AdjustTokenPrivileges(token
, false, &tp
, sizeof(TOKEN_PRIVILEGES
), nullptr, nullptr))
959 throw last_error(GetLastError());
961 s
= wcsstr(lpszCmdLine
, L
"|");
974 BtrfsDeviceResize bdr
;
975 bdr
.ShowDialog(hwnd
, vol
, devid
);
976 } catch (const exception
& e
) {
977 error_message(hwnd
, e
.what());