Something went wrong. Try again.
Reactos
Something went wrong. Try again.
35 kB · 983 lines
C++
at listview
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984/* Copyright (c) Mark Harmstone 2016-17 * * This file is part of WinBtrfs. * * WinBtrfs is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public Licence as published by * the Free Software Foundation, either version 3 of the Licence, or * (at your option) any later version. * * WinBtrfs is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public Licence for more details. * * You should have received a copy of the GNU Lesser General Public Licence * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
#define ISOLATION_AWARE_ENABLED 1#define STRSAFE_NO_DEPRECATE
#include "shellext.h"#include "devices.h"#include "resource.h"#include "balance.h"#include <stddef.h>#include <uxtheme.h>#include <setupapi.h>#include <strsafe.h>#include <mountmgr.h>#ifndef __REACTOS__#include <algorithm>#include "../btrfs.h"#include "mountmgr.h"#else#include <ntddstor.h>#include <ndk/rtlfuncs.h>#include <ndk/obfuncs.h>#include "btrfs.h"#include "mountmgr_local.h"#endif
DEFINE_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME, 0x7f108a28L, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62);
static wstring get_mountdev_name(const nt_handle& h ) { NTSTATUS Status; IO_STATUS_BLOCK iosb; MOUNTDEV_NAME mdn, *mdn2; wstring name;
Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, nullptr, 0, &mdn, sizeof(MOUNTDEV_NAME)); if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) return L"";
size_t mdnsize = offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength;
mdn2 = (MOUNTDEV_NAME*)malloc(mdnsize);
Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, nullptr, 0, mdn2, (ULONG)mdnsize); if (!NT_SUCCESS(Status)) { free(mdn2); return L""; }
name = wstring(mdn2->Name, mdn2->NameLength / sizeof(WCHAR));
free(mdn2);
return name;}
static void find_devices(HWND hwnd, const GUID* guid, const mountmgr& mm, vector<device>& device_list) { HDEVINFO h;
static const wstring dosdevices = L"\\DosDevices\\";
h = SetupDiGetClassDevsW(guid, nullptr, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (h != INVALID_HANDLE_VALUE) { DWORD index = 0; SP_DEVICE_INTERFACE_DATA did;
did.cbSize = sizeof(did);
if (!SetupDiEnumDeviceInterfaces(h, nullptr, guid, index, &did)) return;
do { SP_DEVINFO_DATA dd; SP_DEVICE_INTERFACE_DETAIL_DATA_W* detail; DWORD size;
dd.cbSize = sizeof(dd);
SetupDiGetDeviceInterfaceDetailW(h, &did, nullptr, 0, &size, nullptr);
detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_W*)malloc(size); memset(detail, 0, size);
detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
if (SetupDiGetDeviceInterfaceDetailW(h, &did, detail, size, &size, &dd)) { NTSTATUS Status; nt_handle file; device dev; STORAGE_DEVICE_NUMBER sdn; IO_STATUS_BLOCK iosb; UNICODE_STRING path; OBJECT_ATTRIBUTES attr; GET_LENGTH_INFORMATION gli; ULONG i; uint8_t sb[4096];
path.Buffer = detail->DevicePath; path.Length = path.MaximumLength = (uint16_t)(wcslen(detail->DevicePath) * sizeof(WCHAR));
if (path.Length > 4 * sizeof(WCHAR) && path.Buffer[0] == '\\' && path.Buffer[1] == '\\' && path.Buffer[2] == '?' && path.Buffer[3] == '\\') path.Buffer[1] = '?';
InitializeObjectAttributes(&attr, &path, 0, nullptr, nullptr);
Status = NtOpenFile(&file, FILE_GENERIC_READ, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(Status)) { free(detail); index++; continue; }
dev.pnp_name = detail->DevicePath;
Status = NtDeviceIoControlFile(file, nullptr, nullptr, nullptr, &iosb, IOCTL_DISK_GET_LENGTH_INFO, nullptr, 0, &gli, sizeof(GET_LENGTH_INFORMATION)); if (!NT_SUCCESS(Status)) { free(detail); index++; continue; }
dev.size = gli.Length.QuadPart;
Status = NtDeviceIoControlFile(file, nullptr, nullptr, nullptr, &iosb, IOCTL_STORAGE_GET_DEVICE_NUMBER, nullptr, 0, &sdn, sizeof(STORAGE_DEVICE_NUMBER)); if (!NT_SUCCESS(Status)) { dev.disk_num = 0xffffffff; dev.part_num = 0xffffffff; } else { dev.disk_num = sdn.DeviceNumber; dev.part_num = sdn.PartitionNumber; }
dev.friendly_name = L""; dev.drive = L""; dev.fstype = L""; dev.has_parts = false; dev.ignore = false; dev.multi_device = false;
dev.is_disk = RtlCompareMemory(guid, &GUID_DEVINTERFACE_DISK, sizeof(GUID)) == sizeof(GUID);
if (dev.is_disk) { STORAGE_PROPERTY_QUERY spq; STORAGE_DEVICE_DESCRIPTOR sdd, *sdd2; ULONG dlisize; DRIVE_LAYOUT_INFORMATION_EX* dli;
spq.PropertyId = StorageDeviceProperty; spq.QueryType = PropertyStandardQuery; spq.AdditionalParameters[0] = 0;
Status = NtDeviceIoControlFile(file, nullptr, nullptr, nullptr, &iosb, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(STORAGE_PROPERTY_QUERY), &sdd, sizeof(STORAGE_DEVICE_DESCRIPTOR));
if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW) { sdd2 = (STORAGE_DEVICE_DESCRIPTOR*)malloc(sdd.Size);
Status = NtDeviceIoControlFile(file, nullptr, nullptr, nullptr, &iosb, IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(STORAGE_PROPERTY_QUERY), sdd2, sdd.Size); if (NT_SUCCESS(Status)) { string desc2;
desc2 = "";
if (sdd2->VendorIdOffset != 0) { desc2 += (char*)((uint8_t*)sdd2 + sdd2->VendorIdOffset);
while (desc2.length() > 0 && desc2[desc2.length() - 1] == ' ') desc2 = desc2.substr(0, desc2.length() - 1); }
if (sdd2->ProductIdOffset != 0) { if (sdd2->VendorIdOffset != 0 && desc2.length() != 0 && desc2[desc2.length() - 1] != ' ') desc2 += " ";
desc2 += (char*)((uint8_t*)sdd2 + sdd2->ProductIdOffset);
while (desc2.length() > 0 && desc2[desc2.length() - 1] == ' ') desc2 = desc2.substr(0, desc2.length() - 1); }
if (sdd2->VendorIdOffset != 0 || sdd2->ProductIdOffset != 0) { ULONG ss;
ss = MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, desc2.c_str(), -1, nullptr, 0);
if (ss > 0) { WCHAR* desc3 = (WCHAR*)malloc(ss * sizeof(WCHAR));
if (MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, desc2.c_str(), -1, desc3, ss)) dev.friendly_name = desc3;
free(desc3); } } }
free(sdd2); }
dlisize = 0; dli = nullptr;
do { dlisize += 1024;
if (dli) free(dli);
dli = (DRIVE_LAYOUT_INFORMATION_EX*)malloc(dlisize);
Status = NtDeviceIoControlFile(file, nullptr, nullptr, nullptr, &iosb, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, nullptr, 0, dli, dlisize); } while (Status == STATUS_BUFFER_TOO_SMALL);
if (NT_SUCCESS(Status) && dli->PartitionCount > 0) dev.has_parts = true;
free(dli); } else { try { auto v = mm.query_points(L"", L"", wstring_view(path.Buffer, path.Length / sizeof(WCHAR)));
#ifndef __REACTOS__ for (const auto& p : v) { if (p.symlink.length() == 14 && p.symlink.substr(0, dosdevices.length()) == dosdevices && p.symlink[13] == ':') {#else for(auto p = v.begin(); p != v.end(); ++p) { if ((*p).symlink.length() == 14 && (*p).symlink.substr(0, dosdevices.length()) == dosdevices && (*p).symlink[13] == ':') {#endif WCHAR dr[3];
#ifndef __REACTOS__ dr[0] = p.symlink[12];#else dr[0] = (*p).symlink[12];#endif dr[1] = ':'; dr[2] = 0;
dev.drive = dr; break; } } } catch (...) { // don't fail entirely if mountmgr refuses to co-operate } }
if (!dev.is_disk || !dev.has_parts) { i = 0; while (fs_ident[i].name) { if (i == 0 || fs_ident[i].kboff != fs_ident[i-1].kboff) { LARGE_INTEGER off;
off.QuadPart = fs_ident[i].kboff * 1024; Status = NtReadFile(file, nullptr, nullptr, nullptr, &iosb, sb, sizeof(sb), &off, nullptr); }
if (NT_SUCCESS(Status)) { if (RtlCompareMemory(sb + fs_ident[i].sboff, fs_ident[i].magic, fs_ident[i].magiclen) == fs_ident[i].magiclen) { dev.fstype = fs_ident[i].name;
if (dev.fstype == L"Btrfs") { superblock* bsb = (superblock*)sb;
RtlCopyMemory(&dev.fs_uuid, &bsb->uuid, sizeof(BTRFS_UUID)); RtlCopyMemory(&dev.dev_uuid, &bsb->dev_item.device_uuid, sizeof(BTRFS_UUID)); }
break; } }
i++; }
if (dev.fstype == L"Btrfs" && RtlCompareMemory(guid, &GUID_DEVINTERFACE_DISK, sizeof(GUID)) != sizeof(GUID)) { wstring name; wstring pref = L"\\Device\\Btrfs{";
name = get_mountdev_name(file);
if (name.length() > pref.length() && RtlCompareMemory(name.c_str(), pref.c_str(), pref.length() * sizeof(WCHAR)) == pref.length() * sizeof(WCHAR)) dev.ignore = true; } }
device_list.push_back(dev); }
free(detail);
index++; } while (SetupDiEnumDeviceInterfaces(h, nullptr, guid, index, &did));
SetupDiDestroyDeviceInfoList(h); } else throw last_error(GetLastError());}
#ifndef __REACTOS__ // Disabled because building with our <algorithm> seems complex right now...static bool sort_devices(device i, device j) { if (i.disk_num < j.disk_num) return true;
if (i.disk_num == j.disk_num && i.part_num < j.part_num) return true;
return false;}#endif
void BtrfsDeviceAdd::populate_device_tree(HWND tree) { HWND hwnd = GetParent(tree); unsigned int i; ULONG last_disk_num = 0xffffffff; HTREEITEM diskitem; NTSTATUS Status; OBJECT_ATTRIBUTES attr; UNICODE_STRING us; IO_STATUS_BLOCK iosb; btrfs_filesystem* bfs = nullptr;
static WCHAR btrfs[] = L"\\Btrfs";
device_list.clear();
{ mountmgr mm;
{ nt_handle btrfsh;
us.Length = us.MaximumLength = (uint16_t)(wcslen(btrfs) * sizeof(WCHAR)); us.Buffer = btrfs;
InitializeObjectAttributes(&attr, &us, 0, nullptr, nullptr);
Status = NtOpenFile(&btrfsh, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &attr, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT); if (NT_SUCCESS(Status)) { ULONG bfssize = 0;
do { bfssize += 1024;
if (bfs) free(bfs); bfs = (btrfs_filesystem*)malloc(bfssize);
Status = NtDeviceIoControlFile(btrfsh, nullptr, nullptr, nullptr, &iosb, IOCTL_BTRFS_QUERY_FILESYSTEMS, nullptr, 0, bfs, bfssize); if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { free(bfs); bfs = nullptr; break; } } while (Status == STATUS_BUFFER_OVERFLOW);
if (bfs && bfs->num_devices == 0) { // no mounted filesystems found free(bfs); bfs = nullptr; } } }
find_devices(hwnd, &GUID_DEVINTERFACE_DISK, mm, device_list); find_devices(hwnd, &GUID_DEVINTERFACE_VOLUME, mm, device_list); find_devices(hwnd, &GUID_DEVINTERFACE_HIDDEN_VOLUME, mm, device_list); }
#ifndef __REACTOS__ // Disabled because building with our <algorithm> seems complex right now... sort(device_list.begin(), device_list.end(), sort_devices);#endif
for (i = 0; i < device_list.size(); i++) { if (!device_list[i].ignore) { TVINSERTSTRUCTW tis; HTREEITEM item; wstring name, size;
if (device_list[i].disk_num != 0xffffffff && device_list[i].disk_num == last_disk_num) tis.hParent = diskitem; else tis.hParent = TVI_ROOT;
tis.hInsertAfter = TVI_LAST; tis.itemex.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM; tis.itemex.state = TVIS_EXPANDED; tis.itemex.stateMask = TVIS_EXPANDED;
if (device_list[i].disk_num != 0xffffffff) { wstring t;
if (!load_string(module, device_list[i].part_num != 0 ? IDS_PARTITION : IDS_DISK_NUM, t)) throw last_error(GetLastError());
wstring_sprintf(name, t, device_list[i].part_num != 0 ? device_list[i].part_num : device_list[i].disk_num); } else name = device_list[i].pnp_name;
// match child Btrfs devices to their parent if (bfs && device_list[i].drive == L"" && device_list[i].fstype == L"Btrfs") { btrfs_filesystem* bfs2 = bfs;
while (true) { if (RtlCompareMemory(&bfs2->uuid, &device_list[i].fs_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { ULONG j, k; btrfs_filesystem_device* dev;
for (j = 0; j < bfs2->num_devices; j++) { if (j == 0) dev = &bfs2->device; else dev = (btrfs_filesystem_device*)((uint8_t*)dev + offsetof(btrfs_filesystem_device, name[0]) + dev->name_length);
if (RtlCompareMemory(&device_list[i].dev_uuid, &device_list[i].dev_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { for (k = 0; k < device_list.size(); k++) { if (k != i && device_list[k].fstype == L"Btrfs" && device_list[k].drive != L"" && RtlCompareMemory(&device_list[k].fs_uuid, &device_list[i].fs_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { device_list[i].drive = device_list[k].drive; break; } }
device_list[i].multi_device = bfs2->num_devices > 1;
break; } }
break; }
if (bfs2->next_entry != 0) bfs2 = (btrfs_filesystem*)((uint8_t*)bfs2 + bfs2->next_entry); else break; } }
name += L" (";
if (device_list[i].friendly_name != L"") { name += device_list[i].friendly_name; name += L", "; }
if (device_list[i].drive != L"") { name += device_list[i].drive; name += L", "; }
if (device_list[i].fstype != L"") { name += device_list[i].fstype; name += L", "; }
format_size(device_list[i].size, size, false); name += size;
name += L")";
tis.itemex.pszText = (WCHAR*)name.c_str(); tis.itemex.cchTextMax = (int)name.length(); tis.itemex.lParam = (LPARAM)&device_list[i];
item = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tis); if (!item) throw string_error(IDS_TVM_INSERTITEM_FAILED);
if (device_list[i].part_num == 0) { diskitem = item; last_disk_num = device_list[i].disk_num; } } }}
void BtrfsDeviceAdd::AddDevice(HWND hwndDlg) { wstring mess, title; NTSTATUS Status; UNICODE_STRING vn; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK iosb;
if (!sel) { EndDialog(hwndDlg, 0); return; }
if (sel->fstype != L"") { wstring s;
if (!load_string(module, IDS_ADD_DEVICE_CONFIRMATION_FS, s)) throw last_error(GetLastError());
wstring_sprintf(mess, s, sel->fstype.c_str()); } else { if (!load_string(module, IDS_ADD_DEVICE_CONFIRMATION, mess)) throw last_error(GetLastError()); }
if (!load_string(module, IDS_CONFIRMATION_TITLE, title)) throw last_error(GetLastError());
if (MessageBoxW(hwndDlg, mess.c_str(), title.c_str(), MB_YESNO) != IDYES) return;
win_handle h = CreateFileW(cmdline, FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
if (h == INVALID_HANDLE_VALUE) throw last_error(GetLastError());
{ nt_handle h2;
vn.Length = vn.MaximumLength = (uint16_t)(sel->pnp_name.length() * sizeof(WCHAR)); vn.Buffer = (WCHAR*)sel->pnp_name.c_str();
InitializeObjectAttributes(&attr, &vn, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, nullptr, nullptr);
Status = NtOpenFile(&h2, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) throw ntstatus_error(Status);
if (!sel->is_disk) { Status = NtFsControlFile(h2, nullptr, nullptr, nullptr, &iosb, FSCTL_LOCK_VOLUME, nullptr, 0, nullptr, 0); if (!NT_SUCCESS(Status)) throw string_error(IDS_LOCK_FAILED, Status); }
Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_ADD_DEVICE, &h2, sizeof(HANDLE), nullptr, 0); if (!NT_SUCCESS(Status)) throw ntstatus_error(Status);
if (!sel->is_disk) { Status = NtFsControlFile(h2, nullptr, nullptr, nullptr, &iosb, FSCTL_DISMOUNT_VOLUME, nullptr, 0, nullptr, 0); if (!NT_SUCCESS(Status)) throw ntstatus_error(Status);
Status = NtFsControlFile(h2, nullptr, nullptr, nullptr, &iosb, FSCTL_UNLOCK_VOLUME, nullptr, 0, nullptr, 0); if (!NT_SUCCESS(Status)) throw ntstatus_error(Status); } }
EndDialog(hwndDlg, 0);}
INT_PTR CALLBACK BtrfsDeviceAdd::DeviceAddDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { try { switch (uMsg) { case WM_INITDIALOG: { EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB); populate_device_tree(GetDlgItem(hwndDlg, IDC_DEVICE_TREE)); EnableWindow(GetDlgItem(hwndDlg, IDOK), false); break; }
case WM_COMMAND: switch (HIWORD(wParam)) { case BN_CLICKED: switch (LOWORD(wParam)) { case IDOK: AddDevice(hwndDlg); return true;
case IDCANCEL: EndDialog(hwndDlg, 0); return true; } break; } break;
case WM_NOTIFY: switch (((LPNMHDR)lParam)->code) { case TVN_SELCHANGEDW: { NMTREEVIEWW* nmtv = (NMTREEVIEWW*)lParam; TVITEMW tvi; bool enable = false;
RtlZeroMemory(&tvi, sizeof(TVITEMW)); tvi.hItem = nmtv->itemNew.hItem; tvi.mask = TVIF_PARAM | TVIF_HANDLE;
if (SendMessageW(GetDlgItem(hwndDlg, IDC_DEVICE_TREE), TVM_GETITEMW, 0, (LPARAM)&tvi)) sel = tvi.lParam == 0 ? nullptr : (device*)tvi.lParam; else sel = nullptr;
if (sel) enable = (!sel->is_disk || !sel->has_parts) && !sel->multi_device;
EnableWindow(GetDlgItem(hwndDlg, IDOK), enable); break; } } break; } } catch (const exception& e) { error_message(hwndDlg, e.what()); }
return false;}
static INT_PTR CALLBACK stub_DeviceAddDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { BtrfsDeviceAdd* bda;
if (uMsg == WM_INITDIALOG) { SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); bda = (BtrfsDeviceAdd*)lParam; } else { bda = (BtrfsDeviceAdd*)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA); }
if (bda) return bda->DeviceAddDlgProc(hwndDlg, uMsg, wParam, lParam); else return false;}
void BtrfsDeviceAdd::ShowDialog() { DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_DEVICE_ADD), hwnd, stub_DeviceAddDlgProc, (LPARAM)this);}
BtrfsDeviceAdd::BtrfsDeviceAdd(HINSTANCE hinst, HWND hwnd, WCHAR* cmdline) { this->hinst = hinst; this->hwnd = hwnd; this->cmdline = cmdline;
sel = nullptr;}
void BtrfsDeviceResize::do_resize(HWND hwndDlg) { NTSTATUS Status; IO_STATUS_BLOCK iosb; btrfs_resize br;
{ win_handle h = CreateFileW(fn.c_str(), FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
if (h == INVALID_HANDLE_VALUE) throw last_error(GetLastError());
br.device = dev_id; br.size = new_size;
Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESIZE, &br, sizeof(btrfs_resize), nullptr, 0);
if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status)) throw ntstatus_error(Status); }
if (Status != STATUS_MORE_PROCESSING_REQUIRED) { wstring s, t, u;
load_string(module, IDS_RESIZE_SUCCESSFUL, s); format_size(new_size, u, true); wstring_sprintf(t, s, dev_id, u.c_str()); MessageBoxW(hwndDlg, t.c_str(), L"", MB_OK);
EndDialog(hwndDlg, 0); } else { HWND par;
par = GetParent(hwndDlg); EndDialog(hwndDlg, 0);
BtrfsBalance bb(fn, false, true); bb.ShowBalance(par); }}
INT_PTR CALLBACK BtrfsDeviceResize::DeviceResizeDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { try { switch (uMsg) { case WM_INITDIALOG: { win_handle h; WCHAR s[255]; wstring t, u;
EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
GetDlgItemTextW(hwndDlg, IDC_RESIZE_DEVICE_ID, s, sizeof(s) / sizeof(WCHAR)); wstring_sprintf(t, s, dev_id); SetDlgItemTextW(hwndDlg, IDC_RESIZE_DEVICE_ID, t.c_str());
h = CreateFileW(fn.c_str(), FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
if (h != INVALID_HANDLE_VALUE) { NTSTATUS Status; IO_STATUS_BLOCK iosb; btrfs_device *devices, *bd; ULONG devsize; bool found = false; HWND slider;
devsize = 1024; devices = (btrfs_device*)malloc(devsize);
while (true) { Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_DEVICES, nullptr, 0, devices, devsize); if (Status == STATUS_BUFFER_OVERFLOW) { devsize += 1024;
free(devices); devices = (btrfs_device*)malloc(devsize); } else break; }
if (!NT_SUCCESS(Status)) { free(devices); return false; }
bd = devices;
while (true) { if (bd->dev_id == dev_id) { memcpy(&dev_info, bd, sizeof(btrfs_device)); found = true; break; }
if (bd->next_entry > 0) bd = (btrfs_device*)((uint8_t*)bd + bd->next_entry); else break; }
if (!found) { free(devices); return false; }
free(devices);
GetDlgItemTextW(hwndDlg, IDC_RESIZE_CURSIZE, s, sizeof(s) / sizeof(WCHAR)); format_size(dev_info.size, u, true); wstring_sprintf(t, s, u.c_str()); SetDlgItemTextW(hwndDlg, IDC_RESIZE_CURSIZE, t.c_str());
new_size = dev_info.size;
GetDlgItemTextW(hwndDlg, IDC_RESIZE_NEWSIZE, new_size_text, sizeof(new_size_text) / sizeof(WCHAR)); wstring_sprintf(t, new_size_text, u.c_str()); SetDlgItemTextW(hwndDlg, IDC_RESIZE_NEWSIZE, t.c_str());
slider = GetDlgItem(hwndDlg, IDC_RESIZE_SLIDER); SendMessageW(slider, TBM_SETRANGEMIN, false, 0); SendMessageW(slider, TBM_SETRANGEMAX, false, (LPARAM)(dev_info.max_size / 1048576)); SendMessageW(slider, TBM_SETPOS, true, (LPARAM)(new_size / 1048576)); } else return false;
break; }
case WM_COMMAND: switch (HIWORD(wParam)) { case BN_CLICKED: switch (LOWORD(wParam)) { case IDOK: do_resize(hwndDlg); return true;
case IDCANCEL: EndDialog(hwndDlg, 0); return true; } break; } break;
case WM_HSCROLL: { wstring t, u;
new_size = UInt32x32To64(SendMessageW(GetDlgItem(hwndDlg, IDC_RESIZE_SLIDER), TBM_GETPOS, 0, 0), 1048576);
format_size(new_size, u, true); wstring_sprintf(t, new_size_text, u.c_str()); SetDlgItemTextW(hwndDlg, IDC_RESIZE_NEWSIZE, t.c_str());
EnableWindow(GetDlgItem(hwndDlg, IDOK), new_size > 0 ? true : false);
break; } } } catch (const exception& e) { error_message(hwndDlg, e.what()); }
return false;}
static INT_PTR CALLBACK stub_DeviceResizeDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { BtrfsDeviceResize* bdr;
if (uMsg == WM_INITDIALOG) { SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); bdr = (BtrfsDeviceResize*)lParam; } else bdr = (BtrfsDeviceResize*)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
if (bdr) return bdr->DeviceResizeDlgProc(hwndDlg, uMsg, wParam, lParam); else return false;}
void BtrfsDeviceResize::ShowDialog(HWND hwnd, const wstring& fn, uint64_t dev_id) { this->dev_id = dev_id; this->fn = fn;
DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_RESIZE), hwnd, stub_DeviceResizeDlgProc, (LPARAM)this);}
#ifdef __cplusplusextern "C" {#endif
void CALLBACK AddDeviceW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { try { win_handle token; TOKEN_PRIVILEGES tp; LUID luid;
set_dpi_aware();
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) throw last_error(GetLastError());
if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) throw last_error(GetLastError());
tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) throw last_error(GetLastError());
BtrfsDeviceAdd bda(hinst, hwnd, lpszCmdLine); bda.ShowDialog(); } catch (const exception& e) { error_message(hwnd, e.what()); }}
void CALLBACK RemoveDeviceW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { try { WCHAR *s, *vol, *dev; uint64_t devid; win_handle h, token; TOKEN_PRIVILEGES tp; LUID luid; NTSTATUS Status; IO_STATUS_BLOCK iosb;
set_dpi_aware();
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) throw last_error(GetLastError());
if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) throw last_error(GetLastError());
tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) throw last_error(GetLastError());
s = wcsstr(lpszCmdLine, L"|"); if (!s) return;
s[0] = 0;
vol = lpszCmdLine; dev = &s[1];
devid = _wtoi(dev); if (devid == 0) return;
h = CreateFileW(vol, FILE_TRAVERSE | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr);
if (h == INVALID_HANDLE_VALUE) throw last_error(GetLastError());
Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_REMOVE_DEVICE, &devid, sizeof(uint64_t), nullptr, 0); if (!NT_SUCCESS(Status)) { if (Status == STATUS_CANNOT_DELETE) throw string_error(IDS_CANNOT_REMOVE_RAID); else throw ntstatus_error(Status);
return; }
BtrfsBalance bb(vol, true); bb.ShowBalance(hwnd); } catch (const exception& e) { error_message(hwnd, e.what()); }}
void CALLBACK ResizeDeviceW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { try { WCHAR *s, *vol, *dev; uint64_t devid; win_handle token; TOKEN_PRIVILEGES tp; LUID luid;
set_dpi_aware();
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) throw last_error(GetLastError());
if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) throw last_error(GetLastError());
tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(token, false, &tp, sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) throw last_error(GetLastError());
s = wcsstr(lpszCmdLine, L"|"); if (!s) return;
s[0] = 0;
vol = lpszCmdLine; dev = &s[1];
devid = _wtoi(dev); if (devid == 0) return;
BtrfsDeviceResize bdr; bdr.ShowDialog(hwnd, vol, devid); } catch (const exception& e) { error_message(hwnd, e.what()); }}
#ifdef __cplusplus}#endif