[SHELLBTRFS] Upgrade to 1.5

CORE-16494
This commit is contained in:
Pierre Schweitzer 2019-11-12 21:45:49 +01:00
parent 86ee9b0cc2
commit aed50d7e21
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
18 changed files with 1001 additions and 537 deletions

View file

@ -18,6 +18,7 @@ list(APPEND SOURCE
factory.cpp factory.cpp
iconoverlay.cpp iconoverlay.cpp
main.cpp main.cpp
mountmgr_local.cpp
propsheet.cpp propsheet.cpp
reactos.cpp reactos.cpp
recv.cpp recv.cpp

View file

@ -386,11 +386,9 @@ void BtrfsBalance::SaveBalanceOpts(HWND hwndDlg) {
} }
if (IsDlgButtonChecked(hwndDlg, IDC_DEVID) == BST_CHECKED) { if (IsDlgButtonChecked(hwndDlg, IDC_DEVID) == BST_CHECKED) {
int sel;
opts->flags |= BTRFS_BALANCE_OPTS_DEVID; opts->flags |= BTRFS_BALANCE_OPTS_DEVID;
sel = SendMessageW(GetDlgItem(hwndDlg, IDC_DEVID_COMBO), CB_GETCURSEL, 0, 0); auto sel = SendMessageW(GetDlgItem(hwndDlg, IDC_DEVID_COMBO), CB_GETCURSEL, 0, 0);
if (sel == CB_ERR) if (sel == CB_ERR)
opts->flags &= ~BTRFS_BALANCE_OPTS_DEVID; opts->flags &= ~BTRFS_BALANCE_OPTS_DEVID;
@ -493,11 +491,9 @@ void BtrfsBalance::SaveBalanceOpts(HWND hwndDlg) {
} }
if (IsDlgButtonChecked(hwndDlg, IDC_CONVERT) == BST_CHECKED) { if (IsDlgButtonChecked(hwndDlg, IDC_CONVERT) == BST_CHECKED) {
int sel;
opts->flags |= BTRFS_BALANCE_OPTS_CONVERT; opts->flags |= BTRFS_BALANCE_OPTS_CONVERT;
sel = SendMessageW(GetDlgItem(hwndDlg, IDC_CONVERT_COMBO), CB_GETCURSEL, 0, 0); auto sel = SendMessageW(GetDlgItem(hwndDlg, IDC_CONVERT_COMBO), CB_GETCURSEL, 0, 0);
if (sel == CB_ERR || (unsigned int)sel >= sizeof(convtypes2) / sizeof(convtypes2[0])) if (sel == CB_ERR || (unsigned int)sel >= sizeof(convtypes2) / sizeof(convtypes2[0]))
opts->flags &= ~BTRFS_BALANCE_OPTS_CONVERT; opts->flags &= ~BTRFS_BALANCE_OPTS_CONVERT;

169
dll/shellext/shellbtrfs/contextmenu.cpp Normal file → Executable file
View file

@ -323,7 +323,7 @@ void BtrfsContextMenu::get_uac_icon() {
hr = Create32BitHBITMAP(nullptr, &sz, (void**)&buf, &uacicon); hr = Create32BitHBITMAP(nullptr, &sz, (void**)&buf, &uacicon);
if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) {
UINT stride = cx * sizeof(DWORD); UINT stride = (UINT)(cx * sizeof(DWORD));
UINT buflen = cy * stride; UINT buflen = cy * stride;
bitmap->CopyPixels(nullptr, stride, buflen, buf); bitmap->CopyPixels(nullptr, stride, buflen, buf);
} }
@ -462,8 +462,6 @@ static void create_snapshot(HWND hwnd, const wstring& fn) {
if (NT_SUCCESS(Status) && bgfi.inode == 0x100 && !bgfi.top) { if (NT_SUCCESS(Status) && bgfi.inode == 0x100 && !bgfi.top) {
wstring subvolname, parpath, searchpath, temp1, name, nameorig; wstring subvolname, parpath, searchpath, temp1, name, nameorig;
win_handle h2; win_handle h2;
btrfs_create_snapshot* bcs;
ULONG namelen;
WIN32_FIND_DATAW wfd; WIN32_FIND_DATAW wfd;
SYSTEMTIME time; SYSTEMTIME time;
@ -511,16 +509,17 @@ static void create_snapshot(HWND hwnd, const wstring& fn) {
} while (fff != INVALID_HANDLE_VALUE); } while (fff != INVALID_HANDLE_VALUE);
} }
namelen = name.length() * sizeof(WCHAR); size_t namelen = name.length() * sizeof(WCHAR);
bcs = (btrfs_create_snapshot*)malloc(sizeof(btrfs_create_snapshot) - 1 + namelen); auto bcs = (btrfs_create_snapshot*)malloc(sizeof(btrfs_create_snapshot) - 1 + namelen);
bcs->readonly = false; bcs->readonly = false;
bcs->posix = false; bcs->posix = false;
bcs->subvol = h; bcs->subvol = h;
bcs->namelen = (uint16_t)namelen; bcs->namelen = (uint16_t)namelen;
memcpy(bcs->name, name.c_str(), namelen); memcpy(bcs->name, name.c_str(), namelen);
Status = NtFsControlFile(h2, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, sizeof(btrfs_create_snapshot) - 1 + namelen, nullptr, 0); Status = NtFsControlFile(h2, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs,
(ULONG)(sizeof(btrfs_create_snapshot) - 1 + namelen), nullptr, 0);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
throw ntstatus_error(Status); throw ntstatus_error(Status);
@ -619,7 +618,8 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
bcs->namelen = (uint16_t)(destname.length() * sizeof(WCHAR)); bcs->namelen = (uint16_t)(destname.length() * sizeof(WCHAR));
memcpy(bcs->name, destname.c_str(), destname.length() * sizeof(WCHAR)); memcpy(bcs->name, destname.c_str(), destname.length() * sizeof(WCHAR));
Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, sizeof(btrfs_create_snapshot) - sizeof(WCHAR) + bcs->namelen, nullptr, 0); Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs,
(ULONG)(sizeof(btrfs_create_snapshot) - sizeof(WCHAR) + bcs->namelen), nullptr, 0);
free(bcs); free(bcs);
@ -629,19 +629,19 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
return; return;
} }
if (!GetFileInformationByHandleEx(source, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO))) Status = NtQueryInformationFile(source, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation);
throw last_error(GetLastError()); if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
if (bii.type == BTRFS_TYPE_CHARDEV || bii.type == BTRFS_TYPE_BLOCKDEV || bii.type == BTRFS_TYPE_FIFO || bii.type == BTRFS_TYPE_SOCKET) { if (bii.type == BTRFS_TYPE_CHARDEV || bii.type == BTRFS_TYPE_BLOCKDEV || bii.type == BTRFS_TYPE_FIFO || bii.type == BTRFS_TYPE_SOCKET) {
win_handle dirh; win_handle dirh;
ULONG bmnsize;
btrfs_mknod* bmn; btrfs_mknod* bmn;
dirh = CreateFileW(dir, FILE_ADD_FILE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); dirh = CreateFileW(dir, FILE_ADD_FILE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (dirh == INVALID_HANDLE_VALUE) if (dirh == INVALID_HANDLE_VALUE)
throw last_error(GetLastError()); throw last_error(GetLastError());
bmnsize = offsetof(btrfs_mknod, name[0]) + (wcslen(name) * sizeof(WCHAR)); size_t bmnsize = offsetof(btrfs_mknod, name[0]) + (wcslen(name) * sizeof(WCHAR));
bmn = (btrfs_mknod*)malloc(bmnsize); bmn = (btrfs_mknod*)malloc(bmnsize);
bmn->inode = 0; bmn->inode = 0;
@ -650,7 +650,7 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
bmn->namelen = (uint16_t)(wcslen(name) * sizeof(WCHAR)); bmn->namelen = (uint16_t)(wcslen(name) * sizeof(WCHAR));
memcpy(bmn->name, name, bmn->namelen); memcpy(bmn->name, name, bmn->namelen);
Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, bmnsize, nullptr, 0); Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, (ULONG)bmnsize, nullptr, 0);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
free(bmn); free(bmn);
throw ntstatus_error(Status); throw ntstatus_error(Status);
@ -759,11 +759,8 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
// CreateDirectoryExW also copies streams, no need to do it here // CreateDirectoryExW also copies streams, no need to do it here
} else { } else {
WIN32_FIND_STREAM_DATA fsd;
if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
reparse_header rh; reparse_header rh;
ULONG rplen;
uint8_t* rp; uint8_t* rp;
if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, &rh, sizeof(reparse_header), &bytesret, nullptr)) { if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, &rh, sizeof(reparse_header), &bytesret, nullptr)) {
@ -771,13 +768,13 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
throw last_error(GetLastError()); throw last_error(GetLastError());
} }
rplen = sizeof(reparse_header) + rh.ReparseDataLength; size_t rplen = sizeof(reparse_header) + rh.ReparseDataLength;
rp = (uint8_t*)malloc(rplen); rp = (uint8_t*)malloc(rplen);
if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, rp, rplen, &bytesret, nullptr)) if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, rp, (ULONG)rplen, &bytesret, nullptr))
throw last_error(GetLastError()); throw last_error(GetLastError());
if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, rplen, nullptr, 0, &bytesret, nullptr)) if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, (ULONG)rplen, nullptr, 0, &bytesret, nullptr))
throw last_error(GetLastError()); throw last_error(GetLastError());
free(rp); free(rp);
@ -790,8 +787,9 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
uint64_t offset, alloc_size; uint64_t offset, alloc_size;
ULONG maxdup; ULONG maxdup;
if (!GetFileInformationByHandleEx(source, FileStandardInfo, &fsi, sizeof(FILE_STANDARD_INFO))) Status = NtQueryInformationFile(source, &iosb, &fsi, sizeof(FILE_STANDARD_INFO), FileStandardInformation);
throw last_error(GetLastError()); if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
if (!DeviceIoControl(source, FSCTL_GET_INTEGRITY_INFORMATION, nullptr, 0, &fgiib, sizeof(FSCTL_GET_INTEGRITY_INFORMATION_BUFFER), &bytesret, nullptr)) if (!DeviceIoControl(source, FSCTL_GET_INTEGRITY_INFORMATION, nullptr, 0, &fgiib, sizeof(FSCTL_GET_INTEGRITY_INFORMATION_BUFFER), &bytesret, nullptr))
throw last_error(GetLastError()); throw last_error(GetLastError());
@ -808,8 +806,9 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
throw last_error(GetLastError()); throw last_error(GetLastError());
feofi.EndOfFile = fsi.EndOfFile; feofi.EndOfFile = fsi.EndOfFile;
if (!SetFileInformationByHandle(dest, FileEndOfFileInfo, &feofi, sizeof(FILE_END_OF_FILE_INFO))) Status = NtSetInformationFile(dest, &iosb, &feofi, sizeof(FILE_END_OF_FILE_INFO), FileEndOfFileInformation);
throw last_error(GetLastError()); if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
ded.FileHandle = source; ded.FileHandle = source;
maxdup = 0xffffffff - fgiib.ClusterSizeInBytes + 1; maxdup = 0xffffffff - fgiib.ClusterSizeInBytes + 1;
@ -827,19 +826,34 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
} }
} }
fff_handle h = FindFirstStreamW(fn, FindStreamInfoStandard, &fsd, 0); ULONG streambufsize = 0;
if (h != INVALID_HANDLE_VALUE) { vector<char> streambuf;
do {
wstring sn;
sn = fsd.cStreamName; do {
streambufsize += 0x1000;
streambuf.resize(streambufsize);
memset(streambuf.data(), 0, streambufsize);
Status = NtQueryInformationFile(source, &iosb, streambuf.data(), streambufsize, FileStreamInformation);
} while (Status == STATUS_BUFFER_OVERFLOW);
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
auto fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(streambuf.data());
while (true) {
if (fsi->StreamNameLength > 0) {
wstring sn = wstring(fsi->StreamName, fsi->StreamNameLength / sizeof(WCHAR));
if (sn != L"::$DATA" && sn.length() > 6 && sn.substr(sn.length() - 6, 6) == L":$DATA") { if (sn != L"::$DATA" && sn.length() > 6 && sn.substr(sn.length() - 6, 6) == L":$DATA") {
win_handle stream; win_handle stream;
uint8_t* data = nullptr; uint8_t* data = nullptr;
uint16_t stream_size = (uint16_t)fsd.StreamSize.QuadPart; auto stream_size = (uint16_t)fsi->StreamSize.QuadPart;
if (fsd.StreamSize.QuadPart > 0) {
if (stream_size > 0) {
wstring fn2; wstring fn2;
fn2 = fn; fn2 = fn;
@ -876,7 +890,12 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
free(data); free(data);
} }
} }
} while (FindNextStreamW(h, &fsd)); }
if (fsi->NextEntryOffset == 0)
break;
fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(reinterpret_cast<char*>(fsi) + fsi->NextEntryOffset);
} }
} }
@ -909,7 +928,7 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
xa2 = xa; xa2 = xa;
while (xa2->valuelen > 0) { while (xa2->valuelen > 0) {
Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, xa2, Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, xa2,
offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen, nullptr, 0); (ULONG)(offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen), nullptr, 0);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
free(xa); free(xa);
throw ntstatus_error(Status); throw ntstatus_error(Status);
@ -924,8 +943,9 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
FILE_DISPOSITION_INFO fdi; FILE_DISPOSITION_INFO fdi;
fdi.DeleteFile = true; fdi.DeleteFile = true;
if (!SetFileInformationByHandle(dest, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO))) Status = NtSetInformationFile(dest, &iosb, &fdi, sizeof(FILE_DISPOSITION_INFO), FileDispositionInformation);
throw last_error(GetLastError()); if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
throw; throw;
} }
@ -1007,7 +1027,6 @@ HRESULT __stdcall BtrfsContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO picia) {
win_handle h; win_handle h;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
NTSTATUS Status; NTSTATUS Status;
ULONG bcslen;
wstring name, nameorig, searchpath; wstring name, nameorig, searchpath;
btrfs_create_subvol* bcs; btrfs_create_subvol* bcs;
WIN32_FIND_DATAW wfd; WIN32_FIND_DATAW wfd;
@ -1048,7 +1067,7 @@ HRESULT __stdcall BtrfsContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO picia) {
} }
} }
bcslen = offsetof(btrfs_create_subvol, name[0]) + (name.length() * sizeof(WCHAR)); size_t bcslen = offsetof(btrfs_create_subvol, name[0]) + (name.length() * sizeof(WCHAR));
bcs = (btrfs_create_subvol*)malloc(bcslen); bcs = (btrfs_create_subvol*)malloc(bcslen);
bcs->readonly = false; bcs->readonly = false;
@ -1056,7 +1075,7 @@ HRESULT __stdcall BtrfsContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO picia) {
bcs->namelen = (uint16_t)(name.length() * sizeof(WCHAR)); bcs->namelen = (uint16_t)(name.length() * sizeof(WCHAR));
memcpy(bcs->name, name.c_str(), name.length() * sizeof(WCHAR)); memcpy(bcs->name, name.c_str(), name.length() * sizeof(WCHAR));
Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, bcslen, nullptr, 0); Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, (ULONG)bcslen, nullptr, 0);
free(bcs); free(bcs);
@ -1319,7 +1338,6 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
// if subvol, do snapshot instead // if subvol, do snapshot instead
if (bii.inode == SUBVOL_ROOT_INODE) { if (bii.inode == SUBVOL_ROOT_INODE) {
ULONG bcslen;
btrfs_create_snapshot* bcs; btrfs_create_snapshot* bcs;
win_handle dirh; win_handle dirh;
@ -1327,13 +1345,13 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
if (dirh == INVALID_HANDLE_VALUE) if (dirh == INVALID_HANDLE_VALUE)
throw last_error(GetLastError()); throw last_error(GetLastError());
bcslen = offsetof(btrfs_create_snapshot, name[0]) + (destname.length() * sizeof(WCHAR)); size_t bcslen = offsetof(btrfs_create_snapshot, name[0]) + (destname.length() * sizeof(WCHAR));
bcs = (btrfs_create_snapshot*)malloc(bcslen); bcs = (btrfs_create_snapshot*)malloc(bcslen);
bcs->subvol = source; bcs->subvol = source;
bcs->namelen = (uint16_t)(destname.length() * sizeof(WCHAR)); bcs->namelen = (uint16_t)(destname.length() * sizeof(WCHAR));
memcpy(bcs->name, destname.c_str(), destname.length() * sizeof(WCHAR)); memcpy(bcs->name, destname.c_str(), destname.length() * sizeof(WCHAR));
Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, bcslen, nullptr, 0); Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, (ULONG)bcslen, nullptr, 0);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
free(bcs); free(bcs);
throw ntstatus_error(Status); throw ntstatus_error(Status);
@ -1344,19 +1362,19 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
return; return;
} }
if (!GetFileInformationByHandleEx(source, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO))) Status = NtQueryInformationFile(source, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation);
throw last_error(GetLastError()); if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
if (bii.type == BTRFS_TYPE_CHARDEV || bii.type == BTRFS_TYPE_BLOCKDEV || bii.type == BTRFS_TYPE_FIFO || bii.type == BTRFS_TYPE_SOCKET) { if (bii.type == BTRFS_TYPE_CHARDEV || bii.type == BTRFS_TYPE_BLOCKDEV || bii.type == BTRFS_TYPE_FIFO || bii.type == BTRFS_TYPE_SOCKET) {
win_handle dirh; win_handle dirh;
ULONG bmnsize;
btrfs_mknod* bmn; btrfs_mknod* bmn;
dirh = CreateFileW(destdir.c_str(), FILE_ADD_FILE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); dirh = CreateFileW(destdir.c_str(), FILE_ADD_FILE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (dirh == INVALID_HANDLE_VALUE) if (dirh == INVALID_HANDLE_VALUE)
throw last_error(GetLastError()); throw last_error(GetLastError());
bmnsize = offsetof(btrfs_mknod, name[0]) + (destname.length() * sizeof(WCHAR)); size_t bmnsize = offsetof(btrfs_mknod, name[0]) + (destname.length() * sizeof(WCHAR));
bmn = (btrfs_mknod*)malloc(bmnsize); bmn = (btrfs_mknod*)malloc(bmnsize);
bmn->inode = 0; bmn->inode = 0;
@ -1365,7 +1383,7 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
bmn->namelen = (uint16_t)(destname.length() * sizeof(WCHAR)); bmn->namelen = (uint16_t)(destname.length() * sizeof(WCHAR));
memcpy(bmn->name, destname.c_str(), bmn->namelen); memcpy(bmn->name, destname.c_str(), bmn->namelen);
Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, bmnsize, nullptr, 0); Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, (ULONG)bmnsize, nullptr, 0);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
free(bmn); free(bmn);
throw ntstatus_error(Status); throw ntstatus_error(Status);
@ -1428,11 +1446,8 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
// CreateDirectoryExW also copies streams, no need to do it here // CreateDirectoryExW also copies streams, no need to do it here
} else { } else {
WIN32_FIND_STREAM_DATA fsd;
if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
reparse_header rh; reparse_header rh;
ULONG rplen;
uint8_t* rp; uint8_t* rp;
if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, &rh, sizeof(reparse_header), &bytesret, nullptr)) { if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, &rh, sizeof(reparse_header), &bytesret, nullptr)) {
@ -1440,14 +1455,14 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
throw last_error(GetLastError()); throw last_error(GetLastError());
} }
rplen = sizeof(reparse_header) + rh.ReparseDataLength; size_t rplen = sizeof(reparse_header) + rh.ReparseDataLength;
rp = (uint8_t*)malloc(rplen); rp = (uint8_t*)malloc(rplen);
try { try {
if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, rp, rplen, &bytesret, nullptr)) if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, rp, (DWORD)rplen, &bytesret, nullptr))
throw last_error(GetLastError()); throw last_error(GetLastError());
if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, rplen, nullptr, 0, &bytesret, nullptr)) if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, (DWORD)rplen, nullptr, 0, &bytesret, nullptr))
throw last_error(GetLastError()); throw last_error(GetLastError());
} catch (...) { } catch (...) {
free(rp); free(rp);
@ -1464,8 +1479,9 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
uint64_t offset, alloc_size; uint64_t offset, alloc_size;
ULONG maxdup; ULONG maxdup;
if (!GetFileInformationByHandleEx(source, FileStandardInfo, &fsi, sizeof(FILE_STANDARD_INFO))) Status = NtQueryInformationFile(source, &iosb, &fsi, sizeof(FILE_STANDARD_INFO), FileStandardInformation);
throw last_error(GetLastError()); if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
if (!DeviceIoControl(source, FSCTL_GET_INTEGRITY_INFORMATION, nullptr, 0, &fgiib, sizeof(FSCTL_GET_INTEGRITY_INFORMATION_BUFFER), &bytesret, nullptr)) if (!DeviceIoControl(source, FSCTL_GET_INTEGRITY_INFORMATION, nullptr, 0, &fgiib, sizeof(FSCTL_GET_INTEGRITY_INFORMATION_BUFFER), &bytesret, nullptr))
throw last_error(GetLastError()); throw last_error(GetLastError());
@ -1482,8 +1498,9 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
throw last_error(GetLastError()); throw last_error(GetLastError());
feofi.EndOfFile = fsi.EndOfFile; feofi.EndOfFile = fsi.EndOfFile;
if (!SetFileInformationByHandle(dest, FileEndOfFileInfo, &feofi, sizeof(FILE_END_OF_FILE_INFO))) Status = NtSetInformationFile(dest, &iosb, &feofi, sizeof(FILE_END_OF_FILE_INFO), FileEndOfFileInformation);
throw last_error(GetLastError()); if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
ded.FileHandle = source; ded.FileHandle = source;
maxdup = 0xffffffff - fgiib.ClusterSizeInBytes + 1; maxdup = 0xffffffff - fgiib.ClusterSizeInBytes + 1;
@ -1501,20 +1518,34 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
} }
} }
fff_handle h = FindFirstStreamW(srcfn.c_str(), FindStreamInfoStandard, &fsd, 0); ULONG streambufsize = 0;
if (h != INVALID_HANDLE_VALUE) { vector<char> streambuf;
do {
wstring sn;
sn = fsd.cStreamName; do {
streambufsize += 0x1000;
streambuf.resize(streambufsize);
memset(streambuf.data(), 0, streambufsize);
Status = NtQueryInformationFile(source, &iosb, streambuf.data(), streambufsize, FileStreamInformation);
} while (Status == STATUS_BUFFER_OVERFLOW);
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
auto fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(streambuf.data());
while (true) {
if (fsi->StreamNameLength > 0) {
wstring sn = wstring(fsi->StreamName, fsi->StreamNameLength / sizeof(WCHAR));
if (sn != L"::$DATA" && sn.length() > 6 && sn.substr(sn.length() - 6, 6) == L":$DATA") { if (sn != L"::$DATA" && sn.length() > 6 && sn.substr(sn.length() - 6, 6) == L":$DATA") {
win_handle stream; win_handle stream;
uint8_t* data = nullptr; uint8_t* data = nullptr;
auto stream_size = (uint16_t)fsi->StreamSize.QuadPart;
if (fsd.StreamSize.QuadPart > 0) { if (stream_size > 0) {
wstring fn2; wstring fn2;
uint16_t stream_size = (uint16_t)fsd.StreamSize.QuadPart;
fn2 = srcfn; fn2 = srcfn;
fn2 += sn; fn2 += sn;
@ -1542,7 +1573,7 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
} }
if (data) { if (data) {
if (!WriteFile(stream, data, (uint32_t)fsd.StreamSize.QuadPart, &bytesret, nullptr)) { if (!WriteFile(stream, data, stream_size, &bytesret, nullptr)) {
free(data); free(data);
throw last_error(GetLastError()); throw last_error(GetLastError());
} }
@ -1550,7 +1581,13 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
free(data); free(data);
} }
} }
} while (FindNextStreamW(h, &fsd));
}
if (fsi->NextEntryOffset == 0)
break;
fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(reinterpret_cast<char*>(fsi) + fsi->NextEntryOffset);
} }
} }
@ -1583,7 +1620,7 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
xa2 = xa; xa2 = xa;
while (xa2->valuelen > 0) { while (xa2->valuelen > 0) {
Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, xa2, Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, xa2,
offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen, nullptr, 0); (ULONG)(offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen), nullptr, 0);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
free(xa); free(xa);
throw ntstatus_error(Status); throw ntstatus_error(Status);
@ -1598,7 +1635,9 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
FILE_DISPOSITION_INFO fdi; FILE_DISPOSITION_INFO fdi;
fdi.DeleteFile = true; fdi.DeleteFile = true;
SetFileInformationByHandle(dest, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO)); Status = NtSetInformationFile(dest, &iosb, &fdi, sizeof(FILE_DISPOSITION_INFO), FileDispositionInformation);
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
throw; throw;
} }

84
dll/shellext/shellbtrfs/devices.cpp Normal file → Executable file
View file

@ -30,11 +30,13 @@
#ifndef __REACTOS__ #ifndef __REACTOS__
#include <algorithm> #include <algorithm>
#include "../btrfs.h" #include "../btrfs.h"
#include "mountmgr.h"
#else #else
#include <ntddstor.h> #include <ntddstor.h>
#include <ndk/rtlfuncs.h> #include <ndk/rtlfuncs.h>
#include <ndk/obfuncs.h> #include <ndk/obfuncs.h>
#include "btrfs.h" #include "btrfs.h"
#include "mountmgr_local.h"
#endif #endif
DEFINE_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME, 0x7f108a28L, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62); DEFINE_GUID(GUID_DEVINTERFACE_HIDDEN_VOLUME, 0x7f108a28L, 0x9833, 0x4b3b, 0xb7, 0x80, 0x2c, 0x6b, 0x5f, 0xa5, 0xc0, 0x62);
@ -43,7 +45,6 @@ static wstring get_mountdev_name(const nt_handle& h ) {
NTSTATUS Status; NTSTATUS Status;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
MOUNTDEV_NAME mdn, *mdn2; MOUNTDEV_NAME mdn, *mdn2;
ULONG mdnsize;
wstring name; wstring name;
Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
@ -51,12 +52,12 @@ static wstring get_mountdev_name(const nt_handle& h ) {
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
return L""; return L"";
mdnsize = offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength; size_t mdnsize = offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength;
mdn2 = (MOUNTDEV_NAME*)malloc(mdnsize); mdn2 = (MOUNTDEV_NAME*)malloc(mdnsize);
Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
nullptr, 0, mdn2, mdnsize); nullptr, 0, mdn2, (ULONG)mdnsize);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
free(mdn2); free(mdn2);
return L""; return L"";
@ -69,10 +70,10 @@ static wstring get_mountdev_name(const nt_handle& h ) {
return name; return name;
} }
static void find_devices(HWND hwnd, const GUID* guid, const nt_handle& mountmgr, vector<device>& device_list) { static void find_devices(HWND hwnd, const GUID* guid, const mountmgr& mm, vector<device>& device_list) {
HDEVINFO h; HDEVINFO h;
static WCHAR dosdevices[] = L"\\DosDevices\\"; static const wstring dosdevices = L"\\DosDevices\\";
h = SetupDiGetClassDevs(guid, nullptr, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); h = SetupDiGetClassDevs(guid, nullptr, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
@ -204,7 +205,7 @@ static void find_devices(HWND hwnd, const GUID* guid, const nt_handle& mountmgr,
if (ss > 0) { if (ss > 0) {
WCHAR* desc3 = (WCHAR*)malloc(ss * sizeof(WCHAR)); WCHAR* desc3 = (WCHAR*)malloc(ss * sizeof(WCHAR));
if (MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, desc2.c_str(), -1, desc3, ss * sizeof(WCHAR))) if (MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, desc2.c_str(), -1, desc3, (int)(ss * sizeof(WCHAR))))
dev.friendly_name = desc3; dev.friendly_name = desc3;
free(desc3); free(desc3);
@ -235,53 +236,23 @@ static void find_devices(HWND hwnd, const GUID* guid, const nt_handle& mountmgr,
free(dli); free(dli);
} else { } else {
ULONG mmpsize; try {
MOUNTMGR_MOUNT_POINT* mmp; auto v = mm.query_points(L"", L"", wstring_view(path.Buffer, path.Length / sizeof(WCHAR)));
MOUNTMGR_MOUNT_POINTS mmps;
mmpsize = sizeof(MOUNTMGR_MOUNT_POINT) + path.Length; for (const auto& p : v) {
if (p.symlink.length() == 14 && p.symlink.substr(0, dosdevices.length()) == dosdevices && p.symlink[13] == ':') {
WCHAR dr[3];
mmp = (MOUNTMGR_MOUNT_POINT*)malloc(mmpsize); dr[0] = p.symlink[12];
dr[1] = ':';
dr[2] = 0;
RtlZeroMemory(mmp, sizeof(MOUNTMGR_MOUNT_POINT)); dev.drive = dr;
mmp->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); break;
mmp->DeviceNameLength = path.Length;
RtlCopyMemory(&mmp[1], path.Buffer, path.Length);
Status = NtDeviceIoControlFile(mountmgr, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_QUERY_POINTS,
mmp, mmpsize, &mmps, sizeof(MOUNTMGR_MOUNT_POINTS));
if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW) {
MOUNTMGR_MOUNT_POINTS* mmps2;
mmps2 = (MOUNTMGR_MOUNT_POINTS*)malloc(mmps.Size);
Status = NtDeviceIoControlFile(mountmgr, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_QUERY_POINTS,
mmp, mmpsize, mmps2, mmps.Size);
if (NT_SUCCESS(Status)) {
ULONG i;
for (i = 0; i < mmps2->NumberOfMountPoints; i++) {
WCHAR* symlink = (WCHAR*)((uint8_t*)mmps2 + mmps2->MountPoints[i].SymbolicLinkNameOffset);
if (mmps2->MountPoints[i].SymbolicLinkNameLength == 0x1c &&
RtlCompareMemory(symlink, dosdevices, wcslen(dosdevices) * sizeof(WCHAR)) == wcslen(dosdevices) * sizeof(WCHAR) &&
symlink[13] == ':'
) {
WCHAR dr[3];
dr[0] = symlink[12];
dr[1] = ':';
dr[2] = 0;
dev.drive = dr;
break;
}
} }
} }
} catch (...) { // don't fail entirely if mountmgr refuses to co-operate
} }
free(mmp);
} }
if (!dev.is_disk || !dev.has_parts) { if (!dev.is_disk || !dev.has_parts) {
@ -364,16 +335,7 @@ void BtrfsDeviceAdd::populate_device_tree(HWND tree) {
device_list.clear(); device_list.clear();
{ {
nt_handle mountmgr; mountmgr mm;
RtlInitUnicodeString(&us, MOUNTMGR_DEVICE_NAME);
InitializeObjectAttributes(&attr, &us, 0, nullptr, nullptr);
Status = NtOpenFile(&mountmgr, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb,
FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(Status))
throw string_error(IDS_CANT_OPEN_MOUNTMGR);
{ {
nt_handle btrfsh; nt_handle btrfsh;
@ -409,9 +371,9 @@ void BtrfsDeviceAdd::populate_device_tree(HWND tree) {
} }
} }
find_devices(hwnd, &GUID_DEVINTERFACE_DISK, mountmgr, device_list); find_devices(hwnd, &GUID_DEVINTERFACE_DISK, mm, device_list);
find_devices(hwnd, &GUID_DEVINTERFACE_VOLUME, mountmgr, device_list); find_devices(hwnd, &GUID_DEVINTERFACE_VOLUME, mm, device_list);
find_devices(hwnd, &GUID_DEVINTERFACE_HIDDEN_VOLUME, mountmgr, device_list); find_devices(hwnd, &GUID_DEVINTERFACE_HIDDEN_VOLUME, mm, device_list);
} }
#ifndef __REACTOS__ // Disabled because building with our <algorithm> seems complex right now... #ifndef __REACTOS__ // Disabled because building with our <algorithm> seems complex right now...
@ -507,7 +469,7 @@ void BtrfsDeviceAdd::populate_device_tree(HWND tree) {
name += L")"; name += L")";
tis.itemex.pszText = (WCHAR*)name.c_str(); tis.itemex.pszText = (WCHAR*)name.c_str();
tis.itemex.cchTextMax = name.length(); tis.itemex.cchTextMax = (int)name.length();
tis.itemex.lParam = (LPARAM)&device_list[i]; tis.itemex.lParam = (LPARAM)&device_list[i];
item = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tis); item = (HTREEITEM)SendMessageW(tree, TVM_INSERTITEMW, 0, (LPARAM)&tis);

312
dll/shellext/shellbtrfs/main.cpp Normal file → Executable file
View file

@ -298,7 +298,7 @@ static void write_reg_key(HKEY root, const wstring& keyname, const WCHAR* val, c
if (l != ERROR_SUCCESS) if (l != ERROR_SUCCESS)
throw string_error(IDS_REGCREATEKEY_FAILED, l); throw string_error(IDS_REGCREATEKEY_FAILED, l);
l = RegSetValueExW(hk, val, 0, REG_SZ, (const BYTE*)data.c_str(), (data.length() + 1) * sizeof(WCHAR)); l = RegSetValueExW(hk, val, 0, REG_SZ, (const BYTE*)data.c_str(), (DWORD)((data.length() + 1) * sizeof(WCHAR)));
if (l != ERROR_SUCCESS) if (l != ERROR_SUCCESS)
throw string_error(IDS_REGSETVALUEEX_FAILED, l); throw string_error(IDS_REGSETVALUEEX_FAILED, l);
@ -340,20 +340,71 @@ static void register_clsid(const GUID clsid, const WCHAR* description) {
CoTaskMemFree(clsidstring); CoTaskMemFree(clsidstring);
} }
// implementation of RegDeleteTreeW, only available from Vista on
static void reg_delete_tree(HKEY hkey, const wstring& keyname) {
HKEY k;
LSTATUS ret;
ret = RegOpenKeyExW(hkey, keyname.c_str(), 0, KEY_READ, &k);
if (ret != ERROR_SUCCESS)
throw last_error(ret);
try {
WCHAR* buf;
ULONG bufsize;
ret = RegQueryInfoKeyW(k, nullptr, nullptr, nullptr, nullptr, &bufsize, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr);
if (ret != ERROR_SUCCESS)
throw last_error(ret);
bufsize++;
buf = new WCHAR[bufsize];
try {
do {
ULONG size = bufsize;
ret = RegEnumKeyExW(k, 0, buf, &size, nullptr, nullptr, nullptr, nullptr);
if (ret == ERROR_NO_MORE_ITEMS)
break;
else if (ret != ERROR_SUCCESS)
throw last_error(ret);
reg_delete_tree(k, buf);
} while (true);
ret = RegDeleteKeyW(hkey, keyname.c_str());
if (ret != ERROR_SUCCESS)
throw last_error(ret);
} catch (...) {
delete[] buf;
throw;
}
delete[] buf;
} catch (...) {
RegCloseKey(k);
throw;
}
RegCloseKey(k);
}
static void unregister_clsid(const GUID clsid) { static void unregister_clsid(const GUID clsid) {
WCHAR* clsidstring; WCHAR* clsidstring;
StringFromCLSID(clsid, &clsidstring); StringFromCLSID(clsid, &clsidstring);
try { try {
WCHAR clsidkeyname[MAX_PATH]; #ifndef __REACTOS__
reg_delete_tree(HKEY_CLASSES_ROOT, L"CLSID\\"s + clsidstring);
wsprintfW(clsidkeyname, L"CLSID\\%s", clsidstring); #else
wstring path = wstring(L"CLSID\\") + clsidstring;
LONG l = RegDeleteTreeW(HKEY_CLASSES_ROOT, clsidkeyname); reg_delete_tree(HKEY_CLASSES_ROOT, path);
#endif
if (l != ERROR_SUCCESS)
throw string_error(IDS_REGDELETETREE_FAILED, l);
} catch (...) { } catch (...) {
CoTaskMemFree(clsidstring); CoTaskMemFree(clsidstring);
throw; throw;
@ -385,15 +436,11 @@ static void reg_icon_overlay(const GUID clsid, const wstring& name) {
static void unreg_icon_overlay(const wstring& name) { static void unreg_icon_overlay(const wstring& name) {
#ifndef __REACTOS__ #ifndef __REACTOS__
wstring path = L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\"s + name; reg_delete_tree(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\"s + name);
#else #else
wstring path = wstring(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\") + name; wstring path = wstring(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ShellIconOverlayIdentifiers\\") + name;
reg_delete_tree(HKEY_LOCAL_MACHINE, path);
#endif #endif
LONG l = RegDeleteTreeW(HKEY_LOCAL_MACHINE, path.c_str());
if (l != ERROR_SUCCESS)
throw string_error(IDS_REGDELETETREE_FAILED, l);
} }
static void reg_context_menu_handler(const GUID clsid, const wstring& filetype, const wstring& name) { static void reg_context_menu_handler(const GUID clsid, const wstring& filetype, const wstring& name) {
@ -417,15 +464,11 @@ static void reg_context_menu_handler(const GUID clsid, const wstring& filetype,
static void unreg_context_menu_handler(const wstring& filetype, const wstring& name) { static void unreg_context_menu_handler(const wstring& filetype, const wstring& name) {
#ifndef __REACTOS__ #ifndef __REACTOS__
wstring path = filetype + L"\\ShellEx\\ContextMenuHandlers\\"s + name; reg_delete_tree(HKEY_CLASSES_ROOT, filetype + L"\\ShellEx\\ContextMenuHandlers\\"s + name);
#else #else
wstring path = filetype + wstring(L"\\ShellEx\\ContextMenuHandlers\\") + name; wstring path = filetype + wstring(L"\\ShellEx\\ContextMenuHandlers\\") + name;
reg_delete_tree(HKEY_CLASSES_ROOT, path);
#endif #endif
LONG l = RegDeleteTreeW(HKEY_CLASSES_ROOT, path.c_str());
if (l != ERROR_SUCCESS)
throw string_error(IDS_REGDELETETREE_FAILED, l);
} }
static void reg_prop_sheet_handler(const GUID clsid, const wstring& filetype, const wstring& name) { static void reg_prop_sheet_handler(const GUID clsid, const wstring& filetype, const wstring& name) {
@ -449,15 +492,11 @@ static void reg_prop_sheet_handler(const GUID clsid, const wstring& filetype, co
static void unreg_prop_sheet_handler(const wstring& filetype, const wstring& name) { static void unreg_prop_sheet_handler(const wstring& filetype, const wstring& name) {
#ifndef __REACTOS__ #ifndef __REACTOS__
wstring path = filetype + L"\\ShellEx\\PropertySheetHandlers\\"s + name; reg_delete_tree(HKEY_CLASSES_ROOT, filetype + L"\\ShellEx\\PropertySheetHandlers\\"s + name);
#else #else
wstring path = filetype + wstring(L"\\ShellEx\\PropertySheetHandlers\\") + name; wstring path = filetype + wstring(L"\\ShellEx\\PropertySheetHandlers\\") + name;
reg_delete_tree(HKEY_CLASSES_ROOT, path);
#endif #endif
LONG l = RegDeleteTreeW(HKEY_CLASSES_ROOT, path.c_str());
if (l != ERROR_SUCCESS)
throw string_error(IDS_REGDELETETREE_FAILED, l);
} }
extern "C" STDAPI DllRegisterServer(void) { extern "C" STDAPI DllRegisterServer(void) {
@ -522,7 +561,6 @@ static void create_subvol(const wstring& fn) {
size_t found = fn.rfind(L"\\"); size_t found = fn.rfind(L"\\");
wstring path, file; wstring path, file;
win_handle h; win_handle h;
ULONG bcslen;
btrfs_create_subvol* bcs; btrfs_create_subvol* bcs;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
@ -540,7 +578,7 @@ static void create_subvol(const wstring& fn) {
if (h == INVALID_HANDLE_VALUE) if (h == INVALID_HANDLE_VALUE)
return; return;
bcslen = offsetof(btrfs_create_subvol, name[0]) + (file.length() * sizeof(WCHAR)); size_t bcslen = offsetof(btrfs_create_subvol, name[0]) + (file.length() * sizeof(WCHAR));
bcs = (btrfs_create_subvol*)malloc(bcslen); bcs = (btrfs_create_subvol*)malloc(bcslen);
bcs->readonly = false; bcs->readonly = false;
@ -548,7 +586,7 @@ static void create_subvol(const wstring& fn) {
bcs->namelen = (uint16_t)(file.length() * sizeof(WCHAR)); bcs->namelen = (uint16_t)(file.length() * sizeof(WCHAR));
memcpy(bcs->name, file.c_str(), bcs->namelen); memcpy(bcs->name, file.c_str(), bcs->namelen);
NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, bcslen, nullptr, 0); NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, (ULONG)bcslen, nullptr, 0);
} }
extern "C" void CALLBACK CreateSubvolW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { extern "C" void CALLBACK CreateSubvolW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
@ -564,7 +602,6 @@ static void create_snapshot2(const wstring& source, const wstring& fn) {
size_t found = fn.rfind(L"\\"); size_t found = fn.rfind(L"\\");
wstring path, file; wstring path, file;
win_handle h, src; win_handle h, src;
ULONG bcslen;
btrfs_create_snapshot* bcs; btrfs_create_snapshot* bcs;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
@ -586,7 +623,7 @@ static void create_snapshot2(const wstring& source, const wstring& fn) {
if (h == INVALID_HANDLE_VALUE) if (h == INVALID_HANDLE_VALUE)
return; return;
bcslen = offsetof(btrfs_create_snapshot, name[0]) + (file.length() * sizeof(WCHAR)); size_t bcslen = offsetof(btrfs_create_snapshot, name[0]) + (file.length() * sizeof(WCHAR));
bcs = (btrfs_create_snapshot*)malloc(bcslen); bcs = (btrfs_create_snapshot*)malloc(bcslen);
bcs->readonly = false; bcs->readonly = false;
@ -595,7 +632,7 @@ static void create_snapshot2(const wstring& source, const wstring& fn) {
memcpy(bcs->name, file.c_str(), bcs->namelen); memcpy(bcs->name, file.c_str(), bcs->namelen);
bcs->subvol = src; bcs->subvol = src;
NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, bcslen, nullptr, 0); NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, (ULONG)bcslen, nullptr, 0);
} }
extern "C" void CALLBACK CreateSnapshotW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { extern "C" void CALLBACK CreateSnapshotW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
@ -607,7 +644,7 @@ extern "C" void CALLBACK CreateSnapshotW(HWND hwnd, HINSTANCE hinst, LPWSTR lpsz
create_snapshot2(args[0], args[1]); create_snapshot2(args[0], args[1]);
} }
void command_line_to_args(LPWSTR cmdline, vector<wstring> args) { void command_line_to_args(LPWSTR cmdline, vector<wstring>& args) {
LPWSTR* l; LPWSTR* l;
int num_args; int num_args;
@ -632,6 +669,38 @@ void command_line_to_args(LPWSTR cmdline, vector<wstring> args) {
LocalFree(l); LocalFree(l);
} }
static string utf16_to_utf8(const wstring_view& utf16) {
string utf8;
char* buf;
if (utf16.empty())
return "";
auto utf8len = WideCharToMultiByte(CP_UTF8, 0, utf16.data(), static_cast<int>(utf16.length()), nullptr, 0, nullptr, nullptr);
if (utf8len == 0)
throw last_error(GetLastError());
buf = (char*)malloc(utf8len + sizeof(char));
if (!buf)
throw string_error(IDS_OUT_OF_MEMORY);
if (WideCharToMultiByte(CP_UTF8, 0, utf16.data(), static_cast<int>(utf16.length()), buf, utf8len, nullptr, nullptr) == 0) {
auto le = GetLastError();
free(buf);
throw last_error(le);
}
buf[utf8len] = 0;
utf8 = buf;
free(buf);
return utf8;
}
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4996) #pragma warning(disable: 4996)
@ -657,65 +726,43 @@ string_error::string_error(int resno, ...) {
va_end(args); va_end(args);
utf16_to_utf8(s, msg); msg = utf16_to_utf8(s);
} }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#endif #endif
void utf8_to_utf16(const string& utf8, wstring& utf16) { wstring utf8_to_utf16(const string_view& utf8) {
NTSTATUS Status; wstring ret;
ULONG utf16len;
WCHAR* buf; WCHAR* buf;
Status = RtlUTF8ToUnicodeN(nullptr, 0, &utf16len, utf8.c_str(), utf8.length()); if (utf8.empty())
if (!NT_SUCCESS(Status)) return L"";
throw string_error(IDS_RECV_RTLUTF8TOUNICODEN_FAILED, Status, format_ntstatus(Status).c_str());
buf = (WCHAR*)malloc(utf16len + sizeof(WCHAR)); auto utf16len = MultiByteToWideChar(CP_UTF8, 0, utf8.data(), (int)utf8.length(), nullptr, 0);
if (utf16len == 0)
throw last_error(GetLastError());
buf = (WCHAR*)malloc((utf16len + 1) * sizeof(WCHAR));
if (!buf) if (!buf)
throw string_error(IDS_OUT_OF_MEMORY); throw string_error(IDS_OUT_OF_MEMORY);
Status = RtlUTF8ToUnicodeN(buf, utf16len, &utf16len, utf8.c_str(), utf8.length()); if (MultiByteToWideChar(CP_UTF8, 0, utf8.data(), (int)utf8.length(), buf, utf16len) == 0) {
if (!NT_SUCCESS(Status)) { auto le = GetLastError();
free(buf); free(buf);
throw string_error(IDS_RECV_RTLUTF8TOUNICODEN_FAILED, Status, format_ntstatus(Status).c_str()); throw last_error(le);
} }
buf[utf16len / sizeof(WCHAR)] = 0; buf[utf16len] = 0;
utf16 = buf; ret = buf;
free(buf); free(buf);
}
void utf16_to_utf8(const wstring& utf16, string& utf8) { return ret;
NTSTATUS Status;
ULONG utf8len;
char* buf;
Status = RtlUnicodeToUTF8N(nullptr, 0, &utf8len, utf16.c_str(), utf16.length() * sizeof(WCHAR));
if (!NT_SUCCESS(Status))
throw string_error(IDS_RECV_RTLUNICODETOUTF8N_FAILED, Status, format_ntstatus(Status).c_str());
buf = (char*)malloc(utf8len + sizeof(char));
if (!buf)
throw string_error(IDS_OUT_OF_MEMORY);
Status = RtlUnicodeToUTF8N(buf, utf8len, &utf8len, utf16.c_str(), utf16.length() * sizeof(WCHAR));
if (!NT_SUCCESS(Status)) {
free(buf);
throw string_error(IDS_RECV_RTLUNICODETOUTF8N_FAILED, Status, format_ntstatus(Status).c_str());
}
buf[utf8len] = 0;
utf8 = buf;
free(buf);
} }
last_error::last_error(DWORD errnum) { last_error::last_error(DWORD errnum) {
@ -726,7 +773,7 @@ last_error::last_error(DWORD errnum) {
throw runtime_error("FormatMessage failed"); throw runtime_error("FormatMessage failed");
try { try {
utf16_to_utf8(buf, msg); msg = utf16_to_utf8(buf);
} catch (...) { } catch (...) {
LocalFree(buf); LocalFree(buf);
throw; throw;
@ -736,16 +783,16 @@ last_error::last_error(DWORD errnum) {
} }
void error_message(HWND hwnd, const char* msg) { void error_message(HWND hwnd, const char* msg) {
wstring title, wmsg; wstring title;
load_string(module, IDS_ERROR, title); load_string(module, IDS_ERROR, title);
utf8_to_utf16(msg, wmsg); auto wmsg = utf8_to_utf16(msg);
MessageBoxW(hwnd, wmsg.c_str(), title.c_str(), MB_ICONERROR); MessageBoxW(hwnd, wmsg.c_str(), title.c_str(), MB_ICONERROR);
} }
ntstatus_error::ntstatus_error(NTSTATUS Status) { ntstatus_error::ntstatus_error(NTSTATUS Status) : Status(Status) {
_RtlNtStatusToDosError RtlNtStatusToDosError; _RtlNtStatusToDosError RtlNtStatusToDosError;
HMODULE ntdll = LoadLibraryW(L"ntdll.dll"); HMODULE ntdll = LoadLibraryW(L"ntdll.dll");
WCHAR* buf; WCHAR* buf;
@ -764,7 +811,7 @@ ntstatus_error::ntstatus_error(NTSTATUS Status) {
throw runtime_error("FormatMessage failed"); throw runtime_error("FormatMessage failed");
try { try {
utf16_to_utf8(buf, msg); msg = utf16_to_utf8(buf);
} catch (...) { } catch (...) {
LocalFree(buf); LocalFree(buf);
throw; throw;
@ -778,112 +825,3 @@ ntstatus_error::ntstatus_error(NTSTATUS Status) {
FreeLibrary(ntdll); FreeLibrary(ntdll);
} }
#ifdef __REACTOS__
NTSTATUS NTAPI RtlUnicodeToUTF8N(CHAR *utf8_dest, ULONG utf8_bytes_max,
ULONG *utf8_bytes_written,
const WCHAR *uni_src, ULONG uni_bytes)
{
NTSTATUS status;
ULONG i;
ULONG written;
ULONG ch;
BYTE utf8_ch[4];
ULONG utf8_ch_len;
if (!uni_src)
return STATUS_INVALID_PARAMETER_4;
if (!utf8_bytes_written)
return STATUS_INVALID_PARAMETER;
if (utf8_dest && uni_bytes % sizeof(WCHAR))
return STATUS_INVALID_PARAMETER_5;
written = 0;
status = STATUS_SUCCESS;
for (i = 0; i < uni_bytes / sizeof(WCHAR); i++)
{
/* decode UTF-16 into ch */
ch = uni_src[i];
if (ch >= 0xdc00 && ch <= 0xdfff)
{
ch = 0xfffd;
status = STATUS_SOME_NOT_MAPPED;
}
else if (ch >= 0xd800 && ch <= 0xdbff)
{
if (i + 1 < uni_bytes / sizeof(WCHAR))
{
ch -= 0xd800;
ch <<= 10;
if (uni_src[i + 1] >= 0xdc00 && uni_src[i + 1] <= 0xdfff)
{
ch |= uni_src[i + 1] - 0xdc00;
ch += 0x010000;
i++;
}
else
{
ch = 0xfffd;
status = STATUS_SOME_NOT_MAPPED;
}
}
else
{
ch = 0xfffd;
status = STATUS_SOME_NOT_MAPPED;
}
}
/* encode ch as UTF-8 */
if (ch < 0x80)
{
utf8_ch[0] = ch & 0x7f;
utf8_ch_len = 1;
}
else if (ch < 0x800)
{
utf8_ch[0] = 0xc0 | (ch >> 6 & 0x1f);
utf8_ch[1] = 0x80 | (ch >> 0 & 0x3f);
utf8_ch_len = 2;
}
else if (ch < 0x10000)
{
utf8_ch[0] = 0xe0 | (ch >> 12 & 0x0f);
utf8_ch[1] = 0x80 | (ch >> 6 & 0x3f);
utf8_ch[2] = 0x80 | (ch >> 0 & 0x3f);
utf8_ch_len = 3;
}
else if (ch < 0x200000)
{
utf8_ch[0] = 0xf0 | (ch >> 18 & 0x07);
utf8_ch[1] = 0x80 | (ch >> 12 & 0x3f);
utf8_ch[2] = 0x80 | (ch >> 6 & 0x3f);
utf8_ch[3] = 0x80 | (ch >> 0 & 0x3f);
utf8_ch_len = 4;
}
if (!utf8_dest)
{
written += utf8_ch_len;
continue;
}
if (utf8_bytes_max >= utf8_ch_len)
{
memcpy(utf8_dest, utf8_ch, utf8_ch_len);
utf8_dest += utf8_ch_len;
utf8_bytes_max -= utf8_ch_len;
written += utf8_ch_len;
}
else
{
utf8_bytes_max = 0;
status = STATUS_BUFFER_TOO_SMALL;
}
}
*utf8_bytes_written = written;
return status;
}
#endif

View file

@ -0,0 +1,180 @@
#include "shellext.h"
#ifndef __REACTOS__
#include "mountmgr.h"
#else
#include "mountmgr_local.h"
#endif
#include <mountmgr.h>
using namespace std;
mountmgr::mountmgr() {
UNICODE_STRING us;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK iosb;
NTSTATUS Status;
RtlInitUnicodeString(&us, MOUNTMGR_DEVICE_NAME);
InitializeObjectAttributes(&attr, &us, 0, nullptr, nullptr);
Status = NtOpenFile(&h, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb,
FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
}
mountmgr::~mountmgr() {
NtClose(h);
}
void mountmgr::create_point(const wstring_view& symlink, const wstring_view& device) const {
NTSTATUS Status;
IO_STATUS_BLOCK iosb;
vector<uint8_t> buf(sizeof(MOUNTMGR_CREATE_POINT_INPUT) + ((symlink.length() + device.length()) * sizeof(WCHAR)));
auto mcpi = reinterpret_cast<MOUNTMGR_CREATE_POINT_INPUT*>(buf.data());
mcpi->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
mcpi->SymbolicLinkNameLength = (USHORT)(symlink.length() * sizeof(WCHAR));
mcpi->DeviceNameOffset = (USHORT)(mcpi->SymbolicLinkNameOffset + mcpi->SymbolicLinkNameLength);
mcpi->DeviceNameLength = (USHORT)(device.length() * sizeof(WCHAR));
memcpy((uint8_t*)mcpi + mcpi->SymbolicLinkNameOffset, symlink.data(), symlink.length() * sizeof(WCHAR));
memcpy((uint8_t*)mcpi + mcpi->DeviceNameOffset, device.data(), device.length() * sizeof(WCHAR));
Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_CREATE_POINT,
buf.data(), (ULONG)buf.size(), nullptr, 0);
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
}
void mountmgr::delete_points(const wstring_view& symlink, const wstring_view& unique_id, const wstring_view& device_name) const {
NTSTATUS Status;
IO_STATUS_BLOCK iosb;
vector<uint8_t> buf(sizeof(MOUNTMGR_MOUNT_POINT) + ((symlink.length() + unique_id.length() + device_name.length()) * sizeof(WCHAR)));
auto mmp = reinterpret_cast<MOUNTMGR_MOUNT_POINT*>(buf.data());
memset(mmp, 0, sizeof(MOUNTMGR_MOUNT_POINT));
if (symlink.length() > 0) {
mmp->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
mmp->SymbolicLinkNameLength = (USHORT)(symlink.length() * sizeof(WCHAR));
memcpy((uint8_t*)mmp + mmp->SymbolicLinkNameOffset, symlink.data(), symlink.length() * sizeof(WCHAR));
}
if (unique_id.length() > 0) {
if (mmp->SymbolicLinkNameLength == 0)
mmp->UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINT);
else
mmp->UniqueIdOffset = mmp->SymbolicLinkNameOffset + mmp->SymbolicLinkNameLength;
mmp->UniqueIdLength = (USHORT)(unique_id.length() * sizeof(WCHAR));
memcpy((uint8_t*)mmp + mmp->UniqueIdOffset, unique_id.data(), unique_id.length() * sizeof(WCHAR));
}
if (device_name.length() > 0) {
if (mmp->SymbolicLinkNameLength == 0 && mmp->UniqueIdOffset == 0)
mmp->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
else if (mmp->SymbolicLinkNameLength != 0)
mmp->DeviceNameOffset = mmp->SymbolicLinkNameOffset + mmp->SymbolicLinkNameLength;
else
mmp->DeviceNameOffset = mmp->UniqueIdOffset + mmp->UniqueIdLength;
mmp->DeviceNameLength = (USHORT)(device_name.length() * sizeof(WCHAR));
memcpy((uint8_t*)mmp + mmp->DeviceNameOffset, device_name.data(), device_name.length() * sizeof(WCHAR));
}
vector<uint8_t> buf2(sizeof(MOUNTMGR_MOUNT_POINTS));
auto mmps = reinterpret_cast<MOUNTMGR_MOUNT_POINTS*>(buf2.data());
Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_DELETE_POINTS,
buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size());
if (Status == STATUS_BUFFER_OVERFLOW) {
buf2.resize(mmps->Size);
Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_DELETE_POINTS,
buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size());
}
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
}
vector<mountmgr_point> mountmgr::query_points(const wstring_view& symlink, const wstring_view& unique_id, const wstring_view& device_name) const {
NTSTATUS Status;
IO_STATUS_BLOCK iosb;
vector<mountmgr_point> v;
vector<uint8_t> buf(sizeof(MOUNTMGR_MOUNT_POINT) + ((symlink.length() + unique_id.length() + device_name.length()) * sizeof(WCHAR)));
auto mmp = reinterpret_cast<MOUNTMGR_MOUNT_POINT*>(buf.data());
memset(mmp, 0, sizeof(MOUNTMGR_MOUNT_POINT));
if (symlink.length() > 0) {
mmp->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
mmp->SymbolicLinkNameLength = (USHORT)(symlink.length() * sizeof(WCHAR));
memcpy((uint8_t*)mmp + mmp->SymbolicLinkNameOffset, symlink.data(), symlink.length() * sizeof(WCHAR));
}
if (unique_id.length() > 0) {
if (mmp->SymbolicLinkNameLength == 0)
mmp->UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINT);
else
mmp->UniqueIdOffset = mmp->SymbolicLinkNameOffset + mmp->SymbolicLinkNameLength;
mmp->UniqueIdLength = (USHORT)(unique_id.length() * sizeof(WCHAR));
memcpy((uint8_t*)mmp + mmp->UniqueIdOffset, unique_id.data(), unique_id.length() * sizeof(WCHAR));
}
if (device_name.length() > 0) {
if (mmp->SymbolicLinkNameLength == 0 && mmp->UniqueIdOffset == 0)
mmp->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
else if (mmp->SymbolicLinkNameLength != 0)
mmp->DeviceNameOffset = mmp->SymbolicLinkNameOffset + mmp->SymbolicLinkNameLength;
else
mmp->DeviceNameOffset = mmp->UniqueIdOffset + mmp->UniqueIdLength;
mmp->DeviceNameLength = (USHORT)(device_name.length() * sizeof(WCHAR));
memcpy((uint8_t*)mmp + mmp->DeviceNameOffset, device_name.data(), device_name.length() * sizeof(WCHAR));
}
vector<uint8_t> buf2(sizeof(MOUNTMGR_MOUNT_POINTS));
auto mmps = reinterpret_cast<MOUNTMGR_MOUNT_POINTS*>(buf2.data());
Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_QUERY_POINTS,
buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size());
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
throw ntstatus_error(Status);
buf2.resize(mmps->Size);
mmps = reinterpret_cast<MOUNTMGR_MOUNT_POINTS*>(buf2.data());
Status = NtDeviceIoControlFile(h, nullptr, nullptr, nullptr, &iosb, IOCTL_MOUNTMGR_QUERY_POINTS,
buf.data(), (ULONG)buf.size(), buf2.data(), (ULONG)buf2.size());
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
for (ULONG i = 0; i < mmps->NumberOfMountPoints; i++) {
wstring_view mpsl, mpdn;
string_view mpuid;
if (mmps->MountPoints[i].SymbolicLinkNameLength)
mpsl = wstring_view((WCHAR*)((uint8_t*)mmps + mmps->MountPoints[i].SymbolicLinkNameOffset), mmps->MountPoints[i].SymbolicLinkNameLength / sizeof(WCHAR));
if (mmps->MountPoints[i].UniqueIdLength)
mpuid = string_view((char*)((uint8_t*)mmps + mmps->MountPoints[i].UniqueIdOffset), mmps->MountPoints[i].UniqueIdLength);
if (mmps->MountPoints[i].DeviceNameLength)
mpdn = wstring_view((WCHAR*)((uint8_t*)mmps + mmps->MountPoints[i].DeviceNameOffset), mmps->MountPoints[i].DeviceNameLength / sizeof(WCHAR));
v.emplace_back(mpsl, mpuid, mpdn);
}
return v;
}

View file

@ -0,0 +1,34 @@
#pragma once
#include <vector>
#include <string>
#include <sstream>
#ifndef __REACTOS__
#include <string_view>
#else
#define string_view string
#define wstring_view wstring
#endif
#include <iostream>
#include <iomanip>
class mountmgr_point {
public:
mountmgr_point(const std::wstring_view& symlink, const std::string_view& unique_id, const std::wstring_view& device_name) : symlink(symlink), device_name(device_name), unique_id(unique_id) {
}
std::wstring symlink, device_name;
std::string unique_id;
};
class mountmgr {
public:
mountmgr();
~mountmgr();
void create_point(const std::wstring_view& symlink, const std::wstring_view& device) const;
void delete_points(const std::wstring_view& symlink, const std::wstring_view& unique_id = L"", const std::wstring_view& device_name = L"") const;
std::vector<mountmgr_point> query_points(const std::wstring_view& symlink = L"", const std::wstring_view& unique_id = L"", const std::wstring_view& device_name = L"") const;
private:
HANDLE h;
};

48
dll/shellext/shellbtrfs/propsheet.cpp Normal file → Executable file
View file

@ -60,6 +60,13 @@ typedef struct _FILE_STANDARD_INFORMATION {
#define FileStandardInformation (FILE_INFORMATION_CLASS)5 #define FileStandardInformation (FILE_INFORMATION_CLASS)5
typedef struct _FILE_FS_SIZE_INFORMATION {
LARGE_INTEGER TotalAllocationUnits;
LARGE_INTEGER AvailableAllocationUnits;
ULONG SectorsPerAllocationUnit;
ULONG BytesPerSector;
} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;
#endif #endif
#endif #endif
@ -125,6 +132,7 @@ void BtrfsPropSheet::do_search(const wstring& fn) {
sizes[4] += bii2.disk_size_zstd; sizes[4] += bii2.disk_size_zstd;
totalsize += bii2.inline_length + bii2.disk_size_uncompressed + bii2.disk_size_zlib + bii2.disk_size_lzo + bii2.disk_size_zstd; totalsize += bii2.inline_length + bii2.disk_size_uncompressed + bii2.disk_size_zlib + bii2.disk_size_lzo + bii2.disk_size_zstd;
sparsesize += bii2.sparse_size; sparsesize += bii2.sparse_size;
num_extents += bii2.num_extents == 0 ? 0 : (bii2.num_extents - 1);
} }
FILE_STANDARD_INFORMATION fsi; FILE_STANDARD_INFORMATION fsi;
@ -247,6 +255,7 @@ HRESULT BtrfsPropSheet::check_file(const wstring& fn, UINT i, UINT num_files, UI
} }
sparsesize += bii2.sparse_size; sparsesize += bii2.sparse_size;
num_extents += bii2.num_extents == 0 ? 0 : (bii2.num_extents - 1);
FILE_STANDARD_INFORMATION fsi; FILE_STANDARD_INFORMATION fsi;
@ -288,6 +297,18 @@ HRESULT BtrfsPropSheet::check_file(const wstring& fn, UINT i, UINT num_files, UI
if (filesize.QuadPart != 0) if (filesize.QuadPart != 0)
can_change_nocow = false; can_change_nocow = false;
} }
{
FILE_FS_SIZE_INFORMATION ffsi;
Status = NtQueryVolumeInformationFile(h, &iosb, &ffsi, sizeof(ffsi), FileFsSizeInformation);
if (NT_SUCCESS(Status))
sector_size = ffsi.BytesPerSector;
if (sector_size == 0)
sector_size = 4096;
}
} else } else
return E_FAIL; return E_FAIL;
@ -623,8 +644,9 @@ void BtrfsPropSheet::apply_changes_file(HWND hDlg, const wstring& fn) {
else else
fbi.FileAttributes &= ~FILE_ATTRIBUTE_READONLY; fbi.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
if (!SetFileInformationByHandle(h, FileBasicInfo, &fbi, sizeof(fbi))) Status = NtSetInformationFile(h, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation);
throw last_error(GetLastError()); if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
} }
if (flags_changed || perms_changed || uid_changed || gid_changed || compress_type_changed) { if (flags_changed || perms_changed || uid_changed || gid_changed || compress_type_changed) {
@ -693,7 +715,7 @@ void BtrfsPropSheet::apply_changes(HWND hDlg) {
} }
void BtrfsPropSheet::set_size_on_disk(HWND hwndDlg) { void BtrfsPropSheet::set_size_on_disk(HWND hwndDlg) {
wstring s, size_on_disk, cr; wstring s, size_on_disk, cr, frag;
WCHAR old_text[1024]; WCHAR old_text[1024];
float ratio; float ratio;
@ -717,6 +739,21 @@ void BtrfsPropSheet::set_size_on_disk(HWND hwndDlg) {
if (cr != old_text) if (cr != old_text)
SetDlgItemTextW(hwndDlg, IDC_COMPRESSION_RATIO, cr.c_str()); SetDlgItemTextW(hwndDlg, IDC_COMPRESSION_RATIO, cr.c_str());
uint64_t extent_size = (allocsize - sparsesize - sizes[0]) / sector_size;
if (num_extents == 0 || extent_size <= 1)
ratio = 0.0f;
else
ratio = 100.0f * ((float)num_extents / (float)(extent_size - 1));
wstring_sprintf(frag, frag_format, ratio);
GetDlgItemTextW(hwndDlg, IDC_FRAGMENTATION, old_text, sizeof(old_text) / sizeof(WCHAR));
if (frag != old_text)
SetDlgItemTextW(hwndDlg, IDC_FRAGMENTATION, frag.c_str());
} }
void BtrfsPropSheet::change_perm_flag(HWND hDlg, ULONG flag, UINT state) { void BtrfsPropSheet::change_perm_flag(HWND hDlg, ULONG flag, UINT state) {
@ -945,6 +982,9 @@ void BtrfsPropSheet::init_propsheet(HWND hwndDlg) {
if (cr_format[0] == 0) if (cr_format[0] == 0)
GetDlgItemTextW(hwndDlg, IDC_COMPRESSION_RATIO, cr_format, sizeof(cr_format) / sizeof(WCHAR)); GetDlgItemTextW(hwndDlg, IDC_COMPRESSION_RATIO, cr_format, sizeof(cr_format) / sizeof(WCHAR));
if (frag_format[0] == 0)
GetDlgItemTextW(hwndDlg, IDC_FRAGMENTATION, frag_format, sizeof(frag_format) / sizeof(WCHAR));
set_size_on_disk(hwndDlg); set_size_on_disk(hwndDlg);
if (thread) if (thread)
@ -1180,7 +1220,7 @@ static INT_PTR CALLBACK PropSheetDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
case CBN_SELCHANGE: { case CBN_SELCHANGE: {
switch (LOWORD(wParam)) { switch (LOWORD(wParam)) {
case IDC_COMPRESS_TYPE: { case IDC_COMPRESS_TYPE: {
int sel = SendMessageW(GetDlgItem(hwndDlg, LOWORD(wParam)), CB_GETCURSEL, 0, 0); auto sel = SendMessageW(GetDlgItem(hwndDlg, LOWORD(wParam)), CB_GETCURSEL, 0, 0);
if (bps->min_compression_type != bps->max_compression_type) { if (bps->min_compression_type != bps->max_compression_type) {
if (sel == 0) if (sel == 0)

View file

@ -111,8 +111,11 @@ public:
sizes[0] = sizes[1] = sizes[2] = sizes[3] = sizes[4] = 0; sizes[0] = sizes[1] = sizes[2] = sizes[3] = sizes[4] = 0;
totalsize = allocsize = sparsesize = 0; totalsize = allocsize = sparsesize = 0;
num_extents = 0;
sector_size = 0;
size_format[0] = 0; size_format[0] = 0;
cr_format[0] = 0; cr_format[0] = 0;
frag_format[0] = 0;
InterlockedIncrement(&objs_loaded); InterlockedIncrement(&objs_loaded);
} }
@ -168,7 +171,7 @@ public:
bool readonly; bool readonly;
bool can_change_perms; bool can_change_perms;
bool can_change_nocow; bool can_change_nocow;
WCHAR size_format[255], cr_format[255]; WCHAR size_format[255], cr_format[255], frag_format[255];
HANDLE thread; HANDLE thread;
uint32_t min_mode, max_mode, mode, mode_set; uint32_t min_mode, max_mode, mode, mode_set;
uint64_t min_flags, max_flags, flags, flags_set; uint64_t min_flags, max_flags, flags, flags_set;
@ -184,9 +187,10 @@ private:
STGMEDIUM stgm; STGMEDIUM stgm;
bool stgm_set; bool stgm_set;
bool flags_changed, perms_changed, uid_changed, gid_changed; bool flags_changed, perms_changed, uid_changed, gid_changed;
uint64_t sizes[5], totalsize, allocsize, sparsesize; uint64_t sizes[5], totalsize, allocsize, sparsesize, num_extents;
deque<wstring> search_list; deque<wstring> search_list;
wstring filename; wstring filename;
uint32_t sector_size;
void apply_changes_file(HWND hDlg, const wstring& fn); void apply_changes_file(HWND hDlg, const wstring& fn);
HRESULT check_file(const wstring& fn, UINT i, UINT num_files, UINT* sv); HRESULT check_file(const wstring& fn, UINT i, UINT num_files, UINT* sv);

View file

@ -84,8 +84,8 @@ static const uint32_t crctable[] = {
#define ALIGN_MASK (ALIGN_SIZE - 1) #define ALIGN_MASK (ALIGN_SIZE - 1)
#define CALC_CRC(op, crc, type, buf, len) \ #define CALC_CRC(op, crc, type, buf, len) \
do { \ do { \
for (; (len) >= sizeof (type); (len) -= sizeof(type), buf += sizeof (type)) { \ for (; (len) >= sizeof (type); (len) -= (ULONG)sizeof(type), buf += sizeof (type)) { \
(crc) = op((crc), *(type *) (buf)); \ (crc) = (uint32_t)op((crc), *(type *) (buf)); \
} \ } \
} while(0) } while(0)
@ -153,7 +153,7 @@ static uint32_t calc_crc32c(uint32_t seed, uint8_t* msg, ULONG msglen) {
} }
bool BtrfsRecv::find_tlv(uint8_t* data, ULONG datalen, uint16_t type, void** value, ULONG* len) { bool BtrfsRecv::find_tlv(uint8_t* data, ULONG datalen, uint16_t type, void** value, ULONG* len) {
ULONG off = 0; size_t off = 0;
while (off < datalen) { while (off < datalen) {
btrfs_send_tlv* tlv = (btrfs_send_tlv*)(data + off); btrfs_send_tlv* tlv = (btrfs_send_tlv*)(data + off);
@ -178,11 +178,10 @@ void BtrfsRecv::cmd_subvol(HWND hwnd, btrfs_send_command* cmd, uint8_t* data, co
string name; string name;
BTRFS_UUID* uuid; BTRFS_UUID* uuid;
uint64_t* gen; uint64_t* gen;
ULONG uuidlen, genlen, bcslen; ULONG uuidlen, genlen;
btrfs_create_subvol* bcs; btrfs_create_subvol* bcs;
NTSTATUS Status; NTSTATUS Status;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
wstring nameu;
{ {
char* namebuf; char* namebuf;
@ -209,9 +208,9 @@ void BtrfsRecv::cmd_subvol(HWND hwnd, btrfs_send_command* cmd, uint8_t* data, co
this->subvol_uuid = *uuid; this->subvol_uuid = *uuid;
this->stransid = *gen; this->stransid = *gen;
utf8_to_utf16(name, nameu); auto nameu = utf8_to_utf16(name);
bcslen = offsetof(btrfs_create_subvol, name[0]) + (nameu.length() * sizeof(WCHAR)); size_t bcslen = offsetof(btrfs_create_subvol, name[0]) + (nameu.length() * sizeof(WCHAR));
bcs = (btrfs_create_subvol*)malloc(bcslen); bcs = (btrfs_create_subvol*)malloc(bcslen);
bcs->readonly = true; bcs->readonly = true;
@ -219,7 +218,7 @@ void BtrfsRecv::cmd_subvol(HWND hwnd, btrfs_send_command* cmd, uint8_t* data, co
bcs->namelen = (uint16_t)(nameu.length() * sizeof(WCHAR)); bcs->namelen = (uint16_t)(nameu.length() * sizeof(WCHAR));
memcpy(bcs->name, nameu.c_str(), bcs->namelen); memcpy(bcs->name, nameu.c_str(), bcs->namelen);
Status = NtFsControlFile(parent, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, bcslen, nullptr, 0); Status = NtFsControlFile(parent, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, (ULONG)bcslen, nullptr, 0);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
throw string_error(IDS_RECV_CREATE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str()); throw string_error(IDS_RECV_CREATE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str());
@ -238,7 +237,7 @@ void BtrfsRecv::cmd_subvol(HWND hwnd, btrfs_send_command* cmd, uint8_t* data, co
if (master == INVALID_HANDLE_VALUE) if (master == INVALID_HANDLE_VALUE)
throw string_error(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str()); throw string_error(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str());
Status = NtFsControlFile(master, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESERVE_SUBVOL, bcs, bcslen, nullptr, 0); Status = NtFsControlFile(master, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESERVE_SUBVOL, bcs, (ULONG)bcslen, nullptr, 0);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
throw string_error(IDS_RECV_RESERVE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str()); throw string_error(IDS_RECV_RESERVE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str());
@ -269,13 +268,14 @@ void BtrfsRecv::cmd_snapshot(HWND hwnd, btrfs_send_command* cmd, uint8_t* data,
string name; string name;
BTRFS_UUID *uuid, *parent_uuid; BTRFS_UUID *uuid, *parent_uuid;
uint64_t *gen, *parent_transid; uint64_t *gen, *parent_transid;
ULONG uuidlen, genlen, paruuidlen, partransidlen, bcslen; ULONG uuidlen, genlen, paruuidlen, partransidlen;
btrfs_create_snapshot* bcs; btrfs_create_snapshot* bcs;
NTSTATUS Status; NTSTATUS Status;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
wstring nameu, parpath; wstring parpath;
btrfs_find_subvol bfs; btrfs_find_subvol bfs;
WCHAR parpathw[MAX_PATH], volpathw[MAX_PATH]; WCHAR parpathw[MAX_PATH], volpathw[MAX_PATH];
size_t bcslen;
{ {
char* namebuf; char* namebuf;
@ -314,7 +314,7 @@ void BtrfsRecv::cmd_snapshot(HWND hwnd, btrfs_send_command* cmd, uint8_t* data,
this->subvol_uuid = *uuid; this->subvol_uuid = *uuid;
this->stransid = *gen; this->stransid = *gen;
utf8_to_utf16(name, nameu); auto nameu = utf8_to_utf16(name);
bfs.uuid = *parent_uuid; bfs.uuid = *parent_uuid;
bfs.ctransid = *parent_transid; bfs.ctransid = *parent_transid;
@ -350,7 +350,7 @@ void BtrfsRecv::cmd_snapshot(HWND hwnd, btrfs_send_command* cmd, uint8_t* data,
bcs->namelen = (uint16_t)(nameu.length() * sizeof(WCHAR)); bcs->namelen = (uint16_t)(nameu.length() * sizeof(WCHAR));
memcpy(bcs->name, nameu.c_str(), bcs->namelen); memcpy(bcs->name, nameu.c_str(), bcs->namelen);
Status = NtFsControlFile(parent, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, bcslen, nullptr, 0); Status = NtFsControlFile(parent, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, (ULONG)bcslen, nullptr, 0);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
throw string_error(IDS_RECV_CREATE_SNAPSHOT_FAILED, Status, format_ntstatus(Status).c_str()); throw string_error(IDS_RECV_CREATE_SNAPSHOT_FAILED, Status, format_ntstatus(Status).c_str());
} }
@ -370,7 +370,7 @@ void BtrfsRecv::cmd_snapshot(HWND hwnd, btrfs_send_command* cmd, uint8_t* data,
if (master == INVALID_HANDLE_VALUE) if (master == INVALID_HANDLE_VALUE)
throw string_error(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str()); throw string_error(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str());
Status = NtFsControlFile(master, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESERVE_SUBVOL, bcs, bcslen, nullptr, 0); Status = NtFsControlFile(master, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESERVE_SUBVOL, bcs, (ULONG)bcslen, nullptr, 0);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
throw string_error(IDS_RECV_RESERVE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str()); throw string_error(IDS_RECV_RESERVE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str());
@ -389,7 +389,7 @@ void BtrfsRecv::cmd_snapshot(HWND hwnd, btrfs_send_command* cmd, uint8_t* data,
void BtrfsRecv::cmd_mkfile(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { void BtrfsRecv::cmd_mkfile(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
uint64_t *inode, *rdev = nullptr, *mode = nullptr; uint64_t *inode, *rdev = nullptr, *mode = nullptr;
ULONG inodelen, bmnsize; ULONG inodelen;
NTSTATUS Status; NTSTATUS Status;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
btrfs_mknod* bmn; btrfs_mknod* bmn;
@ -402,7 +402,7 @@ void BtrfsRecv::cmd_mkfile(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&name, &namelen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&name, &namelen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(name, namelen), nameu); nameu = utf8_to_utf16(string(name, namelen));
} }
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_INODE, (void**)&inode, &inodelen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_INODE, (void**)&inode, &inodelen))
@ -432,10 +432,10 @@ void BtrfsRecv::cmd_mkfile(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_LINK, (void**)&pathlink, &pathlinklen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_LINK, (void**)&pathlink, &pathlinklen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path_link"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path_link");
utf8_to_utf16(string(pathlink, pathlinklen), pathlinku); pathlinku = utf8_to_utf16(string(pathlink, pathlinklen));
} }
bmnsize = sizeof(btrfs_mknod) - sizeof(WCHAR) + (nameu.length() * sizeof(WCHAR)); size_t bmnsize = sizeof(btrfs_mknod) - sizeof(WCHAR) + (nameu.length() * sizeof(WCHAR));
bmn = (btrfs_mknod*)malloc(bmnsize); bmn = (btrfs_mknod*)malloc(bmnsize);
bmn->inode = *inode; bmn->inode = *inode;
@ -455,7 +455,7 @@ void BtrfsRecv::cmd_mkfile(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
bmn->namelen = (uint16_t)(nameu.length() * sizeof(WCHAR)); bmn->namelen = (uint16_t)(nameu.length() * sizeof(WCHAR));
memcpy(bmn->name, nameu.c_str(), bmn->namelen); memcpy(bmn->name, nameu.c_str(), bmn->namelen);
Status = NtFsControlFile(dir, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, bmnsize, nullptr, 0); Status = NtFsControlFile(dir, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, (ULONG)bmnsize, nullptr, 0);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
free(bmn); free(bmn);
throw string_error(IDS_RECV_MKNOD_FAILED, Status, format_ntstatus(Status).c_str()); throw string_error(IDS_RECV_MKNOD_FAILED, Status, format_ntstatus(Status).c_str());
@ -465,10 +465,9 @@ void BtrfsRecv::cmd_mkfile(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (cmd->cmd == BTRFS_SEND_CMD_SYMLINK) { if (cmd->cmd == BTRFS_SEND_CMD_SYMLINK) {
REPARSE_DATA_BUFFER* rdb; REPARSE_DATA_BUFFER* rdb;
ULONG rdblen;
btrfs_set_inode_info bsii; btrfs_set_inode_info bsii;
rdblen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]) + (2 * pathlinku.length() * sizeof(WCHAR)); size_t rdblen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]) + (2 * pathlinku.length() * sizeof(WCHAR));
if (rdblen >= 0x10000) if (rdblen >= 0x10000)
throw string_error(IDS_RECV_PATH_TOO_LONG, funcname); throw string_error(IDS_RECV_PATH_TOO_LONG, funcname);
@ -495,7 +494,7 @@ void BtrfsRecv::cmd_mkfile(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, nameu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, nameu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
} }
Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_SET_REPARSE_POINT, rdb, rdblen, nullptr, 0); Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_SET_REPARSE_POINT, rdb, (ULONG)rdblen, nullptr, 0);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
free(rdb); free(rdb);
throw string_error(IDS_RECV_SET_REPARSE_POINT_FAILED, Status, format_ntstatus(Status).c_str()); throw string_error(IDS_RECV_SET_REPARSE_POINT_FAILED, Status, format_ntstatus(Status).c_str());
@ -548,7 +547,7 @@ void BtrfsRecv::cmd_rename(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &path_len)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &path_len))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, path_len), pathu); pathu = utf8_to_utf16(string(path, path_len));
} }
{ {
@ -558,7 +557,7 @@ void BtrfsRecv::cmd_rename(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_TO, (void**)&path_to, &path_to_len)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_TO, (void**)&path_to, &path_to_len))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path_to"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path_to");
utf8_to_utf16(string(path_to, path_to_len), path_tou); path_tou = utf8_to_utf16(string(path_to, path_to_len));
} }
if (!MoveFileW((subvolpath + pathu).c_str(), (subvolpath + path_tou).c_str())) if (!MoveFileW((subvolpath + pathu).c_str(), (subvolpath + path_tou).c_str()))
@ -575,7 +574,7 @@ void BtrfsRecv::cmd_link(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &path_len)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &path_len))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, path_len), pathu); pathu = utf8_to_utf16(string(path, path_len));
} }
{ {
@ -585,7 +584,7 @@ void BtrfsRecv::cmd_link(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_LINK, (void**)&path_link, &path_link_len)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_LINK, (void**)&path_link, &path_link_len))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path_link"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path_link");
utf8_to_utf16(string(path_link, path_link_len), path_linku); path_linku = utf8_to_utf16(string(path_link, path_link_len));
} }
if (!CreateHardLinkW((subvolpath + pathu).c_str(), (subvolpath + path_linku).c_str(), nullptr)) if (!CreateHardLinkW((subvolpath + pathu).c_str(), (subvolpath + path_linku).c_str(), nullptr))
@ -603,7 +602,7 @@ void BtrfsRecv::cmd_unlink(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, pathlen), pathu); pathu = utf8_to_utf16(string(path, pathlen));
} }
att = GetFileAttributesW((subvolpath + pathu).c_str()); att = GetFileAttributesW((subvolpath + pathu).c_str());
@ -630,7 +629,7 @@ void BtrfsRecv::cmd_rmdir(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, pathlen), pathu); pathu = utf8_to_utf16(string(path, pathlen));
} }
att = GetFileAttributesW((subvolpath + pathu).c_str()); att = GetFileAttributesW((subvolpath + pathu).c_str());
@ -659,7 +658,7 @@ void BtrfsRecv::cmd_setxattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* data)
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, pathlen), pathu); pathu = utf8_to_utf16(string(path, pathlen));
} }
{ {
@ -677,10 +676,9 @@ void BtrfsRecv::cmd_setxattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* data)
if (xattrname.length() > XATTR_USER.length() && xattrname.substr(0, XATTR_USER.length()) == XATTR_USER && if (xattrname.length() > XATTR_USER.length() && xattrname.substr(0, XATTR_USER.length()) == XATTR_USER &&
xattrname != EA_DOSATTRIB && xattrname != EA_EA && xattrname != EA_REPARSE) { xattrname != EA_DOSATTRIB && xattrname != EA_EA && xattrname != EA_REPARSE) {
wstring streamname;
ULONG att; ULONG att;
utf8_to_utf16(xattrname, streamname); auto streamname = utf8_to_utf16(xattrname);
att = GetFileAttributesW((subvolpath + pathu).c_str()); att = GetFileAttributesW((subvolpath + pathu).c_str());
if (att == INVALID_FILE_ATTRIBUTES) if (att == INVALID_FILE_ATTRIBUTES)
@ -710,7 +708,7 @@ void BtrfsRecv::cmd_setxattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* data)
} else { } else {
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
NTSTATUS Status; NTSTATUS Status;
ULONG bsxalen, perms = FILE_WRITE_ATTRIBUTES; ULONG perms = FILE_WRITE_ATTRIBUTES;
btrfs_set_xattr* bsxa; btrfs_set_xattr* bsxa;
if (xattrname == EA_NTACL) if (xattrname == EA_NTACL)
@ -723,7 +721,7 @@ void BtrfsRecv::cmd_setxattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* data)
if (h == INVALID_HANDLE_VALUE) if (h == INVALID_HANDLE_VALUE)
throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
bsxalen = offsetof(btrfs_set_xattr, data[0]) + xattrname.length() + xattrdatalen; size_t bsxalen = offsetof(btrfs_set_xattr, data[0]) + xattrname.length() + xattrdatalen;
bsxa = (btrfs_set_xattr*)malloc(bsxalen); bsxa = (btrfs_set_xattr*)malloc(bsxalen);
if (!bsxa) if (!bsxa)
throw string_error(IDS_OUT_OF_MEMORY); throw string_error(IDS_OUT_OF_MEMORY);
@ -733,7 +731,7 @@ void BtrfsRecv::cmd_setxattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* data)
memcpy(bsxa->data, xattrname.c_str(), xattrname.length()); memcpy(bsxa->data, xattrname.c_str(), xattrname.length());
memcpy(&bsxa->data[xattrname.length()], xattrdata, xattrdatalen); memcpy(&bsxa->data[xattrname.length()], xattrdata, xattrdatalen);
Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, bsxa, bsxalen, nullptr, 0); Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, bsxa, (ULONG)bsxalen, nullptr, 0);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
free(bsxa); free(bsxa);
throw string_error(IDS_RECV_SETXATTR_FAILED, Status, format_ntstatus(Status).c_str()); throw string_error(IDS_RECV_SETXATTR_FAILED, Status, format_ntstatus(Status).c_str());
@ -754,7 +752,7 @@ void BtrfsRecv::cmd_removexattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* dat
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, pathlen), pathu); pathu = utf8_to_utf16(string(path, pathlen));
} }
{ {
@ -769,9 +767,8 @@ void BtrfsRecv::cmd_removexattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* dat
if (xattrname.length() > XATTR_USER.length() && xattrname.substr(0, XATTR_USER.length()) == XATTR_USER && xattrname != EA_DOSATTRIB && xattrname != EA_EA) { // deleting stream if (xattrname.length() > XATTR_USER.length() && xattrname.substr(0, XATTR_USER.length()) == XATTR_USER && xattrname != EA_DOSATTRIB && xattrname != EA_EA) { // deleting stream
ULONG att; ULONG att;
wstring streamname;
utf8_to_utf16(xattrname, streamname); auto streamname = utf8_to_utf16(xattrname);
streamname = streamname.substr(XATTR_USER.length()); streamname = streamname.substr(XATTR_USER.length());
@ -794,7 +791,7 @@ void BtrfsRecv::cmd_removexattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* dat
} else { } else {
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
NTSTATUS Status; NTSTATUS Status;
ULONG bsxalen, perms = FILE_WRITE_ATTRIBUTES; ULONG perms = FILE_WRITE_ATTRIBUTES;
btrfs_set_xattr* bsxa; btrfs_set_xattr* bsxa;
if (xattrname == EA_NTACL) if (xattrname == EA_NTACL)
@ -807,7 +804,7 @@ void BtrfsRecv::cmd_removexattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* dat
if (h == INVALID_HANDLE_VALUE) if (h == INVALID_HANDLE_VALUE)
throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
bsxalen = offsetof(btrfs_set_xattr, data[0]) + xattrname.length(); size_t bsxalen = offsetof(btrfs_set_xattr, data[0]) + xattrname.length();
bsxa = (btrfs_set_xattr*)malloc(bsxalen); bsxa = (btrfs_set_xattr*)malloc(bsxalen);
if (!bsxa) if (!bsxa)
throw string_error(IDS_OUT_OF_MEMORY); throw string_error(IDS_OUT_OF_MEMORY);
@ -816,7 +813,7 @@ void BtrfsRecv::cmd_removexattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* dat
bsxa->valuelen = 0; bsxa->valuelen = 0;
memcpy(bsxa->data, xattrname.c_str(), xattrname.length()); memcpy(bsxa->data, xattrname.c_str(), xattrname.length());
Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, bsxa, bsxalen, nullptr, 0); Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, bsxa, (ULONG)bsxalen, nullptr, 0);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
free(bsxa); free(bsxa);
throw string_error(IDS_RECV_SETXATTR_FAILED, Status, format_ntstatus(Status).c_str()); throw string_error(IDS_RECV_SETXATTR_FAILED, Status, format_ntstatus(Status).c_str());
@ -833,6 +830,8 @@ void BtrfsRecv::cmd_write(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
wstring pathu; wstring pathu;
HANDLE h; HANDLE h;
LARGE_INTEGER offli; LARGE_INTEGER offli;
NTSTATUS Status;
IO_STATUS_BLOCK iosb;
{ {
char* path; char* path;
@ -841,7 +840,7 @@ void BtrfsRecv::cmd_write(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, pathlen), pathu); pathu = utf8_to_utf16(string(path, pathlen));
} }
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_OFFSET, (void**)&offset, &offsetlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_OFFSET, (void**)&offset, &offsetlen))
@ -884,8 +883,9 @@ void BtrfsRecv::cmd_write(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
fbi.LastWriteTime.QuadPart = -1; fbi.LastWriteTime.QuadPart = -1;
if (!SetFileInformationByHandle(h, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO))) Status = NtSetInformationFile(h, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation);
throw string_error(IDS_RECV_SETFILEINFO_FAILED, GetLastError(), format_message(GetLastError()).c_str()); if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
} else } else
h = lastwritefile; h = lastwritefile;
@ -930,7 +930,7 @@ void BtrfsRecv::cmd_clone(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, pathlen), pathu); pathu = utf8_to_utf16(string(path, pathlen));
} }
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_UUID, (void**)&cloneuuid, &cloneuuidlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_UUID, (void**)&cloneuuid, &cloneuuidlen))
@ -952,7 +952,7 @@ void BtrfsRecv::cmd_clone(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_PATH, (void**)&clonepath, &clonepathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_PATH, (void**)&clonepath, &clonepathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"clone_path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"clone_path");
utf8_to_utf16(string(clonepath, clonepathlen), clonepathu); clonepathu = utf8_to_utf16(string(clonepath, clonepathlen));
} }
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_OFFSET, (void**)&cloneoffset, &cloneoffsetlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_OFFSET, (void**)&cloneoffset, &cloneoffsetlen))
@ -1047,7 +1047,7 @@ void BtrfsRecv::cmd_truncate(HWND hwnd, btrfs_send_command* cmd, uint8_t* data)
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, pathlen), pathu); pathu = utf8_to_utf16(string(path, pathlen));
} }
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_SIZE, (void**)&size, &sizelen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_SIZE, (void**)&size, &sizelen))
@ -1103,7 +1103,7 @@ void BtrfsRecv::cmd_chmod(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, pathlen), pathu); pathu = utf8_to_utf16(string(path, pathlen));
} }
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_MODE, (void**)&mode, &modelen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_MODE, (void**)&mode, &modelen))
@ -1141,7 +1141,7 @@ void BtrfsRecv::cmd_chown(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, pathlen), pathu); pathu = utf8_to_utf16(string(path, pathlen));
} }
h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_ATTRIBUTES | WRITE_OWNER | WRITE_DAC, 0, nullptr, OPEN_EXISTING, h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_ATTRIBUTES | WRITE_OWNER | WRITE_DAC, 0, nullptr, OPEN_EXISTING,
@ -1187,6 +1187,8 @@ void BtrfsRecv::cmd_utimes(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
FILE_BASIC_INFO fbi; FILE_BASIC_INFO fbi;
BTRFS_TIME* time; BTRFS_TIME* time;
ULONG timelen; ULONG timelen;
IO_STATUS_BLOCK iosb;
NTSTATUS Status;
{ {
char* path; char* path;
@ -1195,7 +1197,7 @@ void BtrfsRecv::cmd_utimes(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen))
throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path");
utf8_to_utf16(string(path, pathlen), pathu); pathu = utf8_to_utf16(string(path, pathlen));
} }
h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_ATTRIBUTES, 0, nullptr, OPEN_EXISTING, h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_ATTRIBUTES, 0, nullptr, OPEN_EXISTING,
@ -1217,8 +1219,9 @@ void BtrfsRecv::cmd_utimes(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) {
if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_CTIME, (void**)&time, &timelen) && timelen >= sizeof(BTRFS_TIME)) if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_CTIME, (void**)&time, &timelen) && timelen >= sizeof(BTRFS_TIME))
fbi.ChangeTime.QuadPart = unix_time_to_win(time); fbi.ChangeTime.QuadPart = unix_time_to_win(time);
if (!SetFileInformationByHandle(h, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO))) Status = NtSetInformationFile(h, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation);
throw string_error(IDS_RECV_SETFILEINFO_FAILED, GetLastError(), format_message(GetLastError()).c_str()); if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
} }
static void delete_directory(const wstring& dir) { static void delete_directory(const wstring& dir) {
@ -1496,9 +1499,7 @@ DWORD BtrfsRecv::recv_thread() {
} while (pos < (uint64_t)size.QuadPart); } while (pos < (uint64_t)size.QuadPart);
} }
} catch (const exception& e) { } catch (const exception& e) {
wstring msg; auto msg = utf8_to_utf16(e.what());
utf8_to_utf16(e.what(), msg);
SetDlgItemTextW(hwnd, IDC_RECV_MSG, msg.c_str()); SetDlgItemTextW(hwnd, IDC_RECV_MSG, msg.c_str());
@ -1552,9 +1553,7 @@ INT_PTR CALLBACK BtrfsRecv::RecvProgressDlgProc(HWND hwndDlg, UINT uMsg, WPARAM
if (!thread) if (!thread)
throw string_error(IDS_RECV_CREATETHREAD_FAILED, GetLastError(), format_message(GetLastError()).c_str()); throw string_error(IDS_RECV_CREATETHREAD_FAILED, GetLastError(), format_message(GetLastError()).c_str());
} catch (const exception& e) { } catch (const exception& e) {
wstring msg; auto msg = utf8_to_utf16(e.what());
utf8_to_utf16(e.what(), msg);
SetDlgItemTextW(hwnd, IDC_RECV_MSG, msg.c_str()); SetDlgItemTextW(hwnd, IDC_RECV_MSG, msg.c_str());

14
dll/shellext/shellbtrfs/resource.h Normal file → Executable file
View file

@ -1,4 +1,4 @@
//{{NO_DEPENDENCIES}} //{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file. // Microsoft Visual C++ generated include file.
// Used by shellbtrfs.rc // Used by shellbtrfs.rc
// //
@ -92,6 +92,7 @@
#define IDS_PARTITION 174 #define IDS_PARTITION 174
#define IDS_WHOLE_DISK 175 #define IDS_WHOLE_DISK 175
#define IDS_CANNOT_REMOVE_RAID 176 #define IDS_CANNOT_REMOVE_RAID 176
#define IDD_DRIVE_LETTER 176
#define IDS_REMOVE_DEVICE_CONFIRMATION 177 #define IDS_REMOVE_DEVICE_CONFIRMATION 177
#define IDS_CONFIRMATION_TITLE 178 #define IDS_CONFIRMATION_TITLE 178
#define IDS_ADD_DEVICE_CONFIRMATION 179 #define IDS_ADD_DEVICE_CONFIRMATION 179
@ -133,7 +134,6 @@
#define IDS_OUT_OF_MEMORY 215 #define IDS_OUT_OF_MEMORY 215
#define IDS_RECV_UNKNOWN_COMMAND 216 #define IDS_RECV_UNKNOWN_COMMAND 216
#define IDS_RECV_CANT_OPEN_PATH 217 #define IDS_RECV_CANT_OPEN_PATH 217
#define IDS_RECV_RTLUTF8TOUNICODEN_FAILED 218
#define IDS_RECV_CREATE_SUBVOL_FAILED 219 #define IDS_RECV_CREATE_SUBVOL_FAILED 219
#define IDS_RECV_MISSING_PARAM 220 #define IDS_RECV_MISSING_PARAM 220
#define IDS_RECV_SHORT_PARAM 221 #define IDS_RECV_SHORT_PARAM 221
@ -145,7 +145,6 @@
#define IDS_RECV_CREATEHARDLINK_FAILED 227 #define IDS_RECV_CREATEHARDLINK_FAILED 227
#define IDS_RECV_SETENDOFFILE_FAILED 228 #define IDS_RECV_SETENDOFFILE_FAILED 228
#define IDS_RECV_CANT_CREATE_FILE 229 #define IDS_RECV_CANT_CREATE_FILE 229
#define IDS_RECV_SETFILEINFO_FAILED 230
#define IDS_RECV_SETINODEINFO_FAILED 231 #define IDS_RECV_SETINODEINFO_FAILED 231
#define IDS_RECV_SUCCESS 232 #define IDS_RECV_SUCCESS 232
#define IDS_RECV_BUTTON_OK 233 #define IDS_RECV_BUTTON_OK 233
@ -197,11 +196,9 @@
#define IDS_BALANCE_COMPLETE_SHRINK 279 #define IDS_BALANCE_COMPLETE_SHRINK 279
#define IDS_BALANCE_FAILED_SHRINK 280 #define IDS_BALANCE_FAILED_SHRINK 280
#define IDS_COMPRESS_ZSTD 281 #define IDS_COMPRESS_ZSTD 281
#define IDS_RECV_RTLUNICODETOUTF8N_FAILED 282
#define IDS_REGCREATEKEY_FAILED 283 #define IDS_REGCREATEKEY_FAILED 283
#define IDS_REGSETVALUEEX_FAILED 284 #define IDS_REGSETVALUEEX_FAILED 284
#define IDS_REGCLOSEKEY_FAILED 285 #define IDS_REGCLOSEKEY_FAILED 285
#define IDS_REGDELETETREE_FAILED 286
#define IDS_CANT_REFLINK_DIFFERENT_FS 287 #define IDS_CANT_REFLINK_DIFFERENT_FS 287
#define IDS_INITCOMMONCONTROLSEX_FAILED 288 #define IDS_INITCOMMONCONTROLSEX_FAILED 288
#define IDS_CANT_OPEN_MOUNTMGR 289 #define IDS_CANT_OPEN_MOUNTMGR 289
@ -240,6 +237,7 @@
#define IDC_SIZE_ZSTD 1023 #define IDC_SIZE_ZSTD 1023
#define IDC_COMPRESSION_RATIO 1023 #define IDC_COMPRESSION_RATIO 1023
#define IDC_PROFILES 1024 #define IDC_PROFILES 1024
#define IDC_FRAGMENTATION 1024
#define IDC_PROFILES_SINGLE 1025 #define IDC_PROFILES_SINGLE 1025
#define IDC_PROFILES_DUP 1026 #define IDC_PROFILES_DUP 1026
#define IDC_VOL_DEVICES 1026 #define IDC_VOL_DEVICES 1026
@ -332,14 +330,16 @@
#define IDC_RESIZE_CURSIZE 1071 #define IDC_RESIZE_CURSIZE 1071
#define IDC_RESIZE_SLIDER 1072 #define IDC_RESIZE_SLIDER 1072
#define IDC_RESIZE_NEWSIZE 1073 #define IDC_RESIZE_NEWSIZE 1073
#define IDC_VOL_CHANGE_DRIVE_LETTER 1073
#define IDC_DRIVE_LETTER_COMBO 1074
// Next default values for new objects // Next default values for new objects
// //
#ifdef APSTUDIO_INVOKED #ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS #ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 175 #define _APS_NEXT_RESOURCE_VALUE 178
#define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1073 #define _APS_NEXT_CONTROL_VALUE 1075
#define _APS_NEXT_SYMED_VALUE 101 #define _APS_NEXT_SYMED_VALUE 101
#endif #endif
#endif #endif

View file

@ -34,7 +34,7 @@ DWORD BtrfsSend::Thread() {
btrfs_send_subvol* bss; btrfs_send_subvol* bss;
btrfs_send_header header; btrfs_send_header header;
btrfs_send_command end; btrfs_send_command end;
ULONG bss_size, i; ULONG i;
buf = (char*)malloc(SEND_BUFFER_LEN); buf = (char*)malloc(SEND_BUFFER_LEN);
@ -44,7 +44,7 @@ DWORD BtrfsSend::Thread() {
throw string_error(IDS_SEND_CANT_OPEN_DIR, subvol.c_str(), GetLastError(), format_message(GetLastError()).c_str()); throw string_error(IDS_SEND_CANT_OPEN_DIR, subvol.c_str(), GetLastError(), format_message(GetLastError()).c_str());
try { try {
bss_size = offsetof(btrfs_send_subvol, clones[0]) + (clones.size() * sizeof(HANDLE)); size_t bss_size = offsetof(btrfs_send_subvol, clones[0]) + (clones.size() * sizeof(HANDLE));
bss = (btrfs_send_subvol*)malloc(bss_size); bss = (btrfs_send_subvol*)malloc(bss_size);
memset(bss, 0, bss_size); memset(bss, 0, bss_size);
@ -64,7 +64,7 @@ DWORD BtrfsSend::Thread() {
} else } else
bss->parent = nullptr; bss->parent = nullptr;
bss->num_clones = clones.size(); bss->num_clones = (ULONG)clones.size();
for (i = 0; i < bss->num_clones; i++) { for (i = 0; i < bss->num_clones; i++) {
HANDLE h; HANDLE h;
@ -86,7 +86,7 @@ DWORD BtrfsSend::Thread() {
bss->clones[i] = h; bss->clones[i] = h;
} }
Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SEND_SUBVOL, bss, bss_size, nullptr, 0); Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SEND_SUBVOL, bss, (ULONG)bss_size, nullptr, 0);
for (i = 0; i < bss->num_clones; i++) { for (i = 0; i < bss->num_clones; i++) {
CloseHandle(bss->clones[i]); CloseHandle(bss->clones[i]);
@ -141,7 +141,7 @@ DWORD BtrfsSend::Thread() {
Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_READ_SEND_BUFFER, nullptr, 0, buf, SEND_BUFFER_LEN); Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_READ_SEND_BUFFER, nullptr, 0, buf, SEND_BUFFER_LEN);
if (NT_SUCCESS(Status)) { if (NT_SUCCESS(Status)) {
if (!WriteFile(stream, buf, iosb.Information, nullptr, nullptr)) if (!WriteFile(stream, buf, (DWORD)iosb.Information, nullptr, nullptr))
throw string_error(IDS_SEND_WRITEFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str()); throw string_error(IDS_SEND_WRITEFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str());
} }
} while (NT_SUCCESS(Status)); } while (NT_SUCCESS(Status));
@ -162,11 +162,14 @@ DWORD BtrfsSend::Thread() {
fdi.DeleteFile = true; fdi.DeleteFile = true;
SetFileInformationByHandle(stream, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO)); Status = NtSetInformationFile(stream, &iosb, &fdi, sizeof(FILE_DISPOSITION_INFO), FileDispositionInformation);
CloseHandle(stream); CloseHandle(stream);
stream = INVALID_HANDLE_VALUE; stream = INVALID_HANDLE_VALUE;
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
throw; throw;
} }
@ -195,9 +198,7 @@ DWORD BtrfsSend::Thread() {
throw; throw;
} }
} catch (const exception& e) { } catch (const exception& e) {
wstring msg; auto msg = utf8_to_utf16(e.what());
utf8_to_utf16(e.what(), msg);
SetDlgItemTextW(hwnd, IDC_SEND_STATUS, msg.c_str()); SetDlgItemTextW(hwnd, IDC_SEND_STATUS, msg.c_str());
return 0; return 0;
@ -232,7 +233,6 @@ static DWORD WINAPI send_thread(LPVOID lpParameter) {
void BtrfsSend::StartSend(HWND hwnd) { void BtrfsSend::StartSend(HWND hwnd) {
wstring s; wstring s;
HWND cl; HWND cl;
ULONG num_clones;
if (started) if (started)
return; return;
@ -269,16 +269,13 @@ void BtrfsSend::StartSend(HWND hwnd) {
clones.clear(); clones.clear();
cl = GetDlgItem(hwnd, IDC_CLONE_LIST); cl = GetDlgItem(hwnd, IDC_CLONE_LIST);
num_clones = SendMessageW(cl, LB_GETCOUNT, 0, 0); auto num_clones = SendMessageW(cl, LB_GETCOUNT, 0, 0);
if ((LRESULT)num_clones != LB_ERR) { if (num_clones != LB_ERR) {
ULONG i; for (unsigned int i = 0; i < (unsigned int)num_clones; i++) {
for (i = 0; i < num_clones; i++) {
WCHAR* t; WCHAR* t;
ULONG len;
len = SendMessageW(cl, LB_GETTEXTLEN, i, 0); auto len = SendMessageW(cl, LB_GETTEXTLEN, i, 0);
t = (WCHAR*)malloc((len + 1) * sizeof(WCHAR)); t = (WCHAR*)malloc((len + 1) * sizeof(WCHAR));
SendMessageW(cl, LB_GETTEXT, i, (LPARAM)t); SendMessageW(cl, LB_GETTEXT, i, (LPARAM)t);
@ -442,12 +439,18 @@ INT_PTR BtrfsSend::SendDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lP
TerminateThread(thread, 0); TerminateThread(thread, 0);
if (stream != INVALID_HANDLE_VALUE) { if (stream != INVALID_HANDLE_VALUE) {
NTSTATUS Status;
FILE_DISPOSITION_INFO fdi; FILE_DISPOSITION_INFO fdi;
IO_STATUS_BLOCK iosb;
fdi.DeleteFile = true; fdi.DeleteFile = true;
SetFileInformationByHandle(stream, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO)); Status = NtSetInformationFile(stream, &iosb, &fdi, sizeof(FILE_DISPOSITION_INFO), FileDispositionInformation);
CloseHandle(stream); CloseHandle(stream);
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
} }
if (dirh != INVALID_HANDLE_VALUE) if (dirh != INVALID_HANDLE_VALUE)
@ -568,7 +571,7 @@ void CALLBACK SendSubvolGUIW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int
static void send_subvol(const wstring& subvol, const wstring& file, const wstring& parent, const vector<wstring>& clones) { static void send_subvol(const wstring& subvol, const wstring& file, const wstring& parent, const vector<wstring>& clones) {
char* buf; char* buf;
win_handle dirh, stream; win_handle dirh, stream;
ULONG bss_size, i; ULONG i;
btrfs_send_subvol* bss; btrfs_send_subvol* bss;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
NTSTATUS Status; NTSTATUS Status;
@ -587,7 +590,7 @@ static void send_subvol(const wstring& subvol, const wstring& file, const wstrin
throw last_error(GetLastError()); throw last_error(GetLastError());
try { try {
bss_size = offsetof(btrfs_send_subvol, clones[0]) + (clones.size() * sizeof(HANDLE)); size_t bss_size = offsetof(btrfs_send_subvol, clones[0]) + (clones.size() * sizeof(HANDLE));
bss = (btrfs_send_subvol*)malloc(bss_size); bss = (btrfs_send_subvol*)malloc(bss_size);
memset(bss, 0, bss_size); memset(bss, 0, bss_size);
@ -602,7 +605,7 @@ static void send_subvol(const wstring& subvol, const wstring& file, const wstrin
} else } else
bss->parent = nullptr; bss->parent = nullptr;
bss->num_clones = clones.size(); bss->num_clones = (ULONG)clones.size();
for (i = 0; i < bss->num_clones; i++) { for (i = 0; i < bss->num_clones; i++) {
HANDLE h; HANDLE h;
@ -624,7 +627,7 @@ static void send_subvol(const wstring& subvol, const wstring& file, const wstrin
bss->clones[i] = h; bss->clones[i] = h;
} }
Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SEND_SUBVOL, bss, bss_size, nullptr, 0); Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SEND_SUBVOL, bss, (ULONG)bss_size, nullptr, 0);
for (i = 0; i < bss->num_clones; i++) { for (i = 0; i < bss->num_clones; i++) {
CloseHandle(bss->clones[i]); CloseHandle(bss->clones[i]);
@ -645,7 +648,7 @@ static void send_subvol(const wstring& subvol, const wstring& file, const wstrin
Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_READ_SEND_BUFFER, nullptr, 0, buf, SEND_BUFFER_LEN); Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_READ_SEND_BUFFER, nullptr, 0, buf, SEND_BUFFER_LEN);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
WriteFile(stream, buf, iosb.Information, nullptr, nullptr); WriteFile(stream, buf, (DWORD)iosb.Information, nullptr, nullptr);
} while (NT_SUCCESS(Status)); } while (NT_SUCCESS(Status));
if (Status != STATUS_END_OF_FILE) if (Status != STATUS_END_OF_FILE)
@ -664,7 +667,9 @@ static void send_subvol(const wstring& subvol, const wstring& file, const wstrin
fdi.DeleteFile = true; fdi.DeleteFile = true;
SetFileInformationByHandle(stream, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO)); Status = NtSetInformationFile(stream, &iosb, &fdi, sizeof(FILE_DISPOSITION_INFO), FileDispositionInformation);
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
throw; throw;
} }

207
dll/shellext/shellbtrfs/shellbtrfs.rc Normal file → Executable file
View file

@ -25,18 +25,18 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
// TEXTINCLUDE // TEXTINCLUDE
// //
1 TEXTINCLUDE 1 TEXTINCLUDE
BEGIN BEGIN
"resource.h\0" "resource.h\0"
END END
2 TEXTINCLUDE 2 TEXTINCLUDE
BEGIN BEGIN
"#include ""winres.h""\r\n" "#include ""winres.h""\r\n"
"\0" "\0"
END END
3 TEXTINCLUDE 3 TEXTINCLUDE
BEGIN BEGIN
"\r\n" "\r\n"
"\0" "\0"
@ -61,8 +61,8 @@ IDI_ICON1 ICON "subvol.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,1,0,0 FILEVERSION 1,5,0,0
PRODUCTVERSION 1,1,0,0 PRODUCTVERSION 1,5,0,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -78,12 +78,12 @@ BEGIN
BLOCK "080904b0" BLOCK "080904b0"
BEGIN BEGIN
VALUE "FileDescription", "WinBtrfs shell extension" VALUE "FileDescription", "WinBtrfs shell extension"
VALUE "FileVersion", "1.1" VALUE "FileVersion", "1.5"
VALUE "InternalName", "btrfs" VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-18" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-19"
VALUE "OriginalFilename", "shellbtrfs.dll" VALUE "OriginalFilename", "shellbtrfs.dll"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.1" VALUE "ProductVersion", "1.5"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
@ -98,51 +98,53 @@ END
// Dialog // Dialog
// //
IDD_PROP_SHEET DIALOGEX 0, 0, 235, 257 IDD_PROP_SHEET DIALOGEX 0, 0, 235, 271
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
CAPTION "Inode property sheet" CAPTION "Inode property sheet"
FONT 8, "MS Shell Dlg", 400, 0, 0x0 FONT 8, "MS Shell Dlg", 400, 0, 0x0
BEGIN BEGIN
LTEXT "Subvolume:",IDC_STATIC,14,21,38,8 LTEXT "Subvolume:",IDC_STATIC,14,21,38,8
LTEXT "Inode:",IDC_STATIC,14,35,21,8 LTEXT "Inode:",IDC_STATIC,14,35,21,8
GROUPBOX "Information",IDC_GROUP_INFORMATION,7,7,221,85 GROUPBOX "Information",IDC_GROUP_INFORMATION,7,7,221,99
LTEXT "Type:",IDC_STATIC,14,49,18,8 LTEXT "Type:",IDC_STATIC,14,49,18,8
GROUPBOX "POSIX permissions",IDC_STATIC,7,96,221,102 GROUPBOX "POSIX permissions",IDC_STATIC,7,110,221,102
LTEXT "User:",IDC_STATIC,14,111,17,8 LTEXT "User:",IDC_STATIC,14,125,17,8
LTEXT "Group:",IDC_STATIC,14,127,22,8 LTEXT "Group:",IDC_STATIC,14,141,22,8
EDITTEXT IDC_UID,94,109,40,14,ES_AUTOHSCROLL | ES_NUMBER EDITTEXT IDC_UID,94,123,40,14,ES_AUTOHSCROLL | ES_NUMBER
EDITTEXT IDC_GID,94,125,40,14,ES_AUTOHSCROLL | ES_NUMBER EDITTEXT IDC_GID,94,139,40,14,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "User",IDC_STATIC,14,158,15,8 LTEXT "User",IDC_STATIC,14,172,15,8
LTEXT "Group",IDC_STATIC,14,168,20,8 LTEXT "Group",IDC_STATIC,14,182,20,8
LTEXT "Others",IDC_STATIC,14,182,22,8 LTEXT "Others",IDC_STATIC,14,196,22,8
LTEXT "Read",IDC_STATIC,50,148,17,8 LTEXT "Read",IDC_STATIC,50,162,17,8
LTEXT "Write",IDC_STATIC,89,148,18,8 LTEXT "Write",IDC_STATIC,89,162,18,8
LTEXT "Execute",IDC_STATIC,129,148,30,8 LTEXT "Execute",IDC_STATIC,129,162,30,8
CONTROL "",IDC_USERR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,54,161,16,10 CONTROL "",IDC_USERR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,54,175,16,10
CONTROL "",IDC_GROUPR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,54,172,16,10 CONTROL "",IDC_GROUPR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,54,186,16,10
CONTROL "",IDC_OTHERR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,54,182,16,10 CONTROL "",IDC_OTHERR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,54,196,16,10
CONTROL "",IDC_USERW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,161,16,10 CONTROL "",IDC_USERW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,175,16,10
CONTROL "",IDC_GROUPW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,172,16,10 CONTROL "",IDC_GROUPW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,186,16,10
CONTROL "",IDC_OTHERW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,182,16,10 CONTROL "",IDC_OTHERW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,93,196,16,10
CONTROL "",IDC_USERX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,135,161,16,10 CONTROL "",IDC_USERX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,135,175,16,10
CONTROL "",IDC_GROUPX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,135,172,16,10 CONTROL "",IDC_GROUPX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,135,186,16,10
CONTROL "",IDC_OTHERX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,135,182,16,10 CONTROL "",IDC_OTHERX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,135,196,16,10
GROUPBOX "Flags",IDC_STATIC,7,204,221,48 GROUPBOX "Flags",IDC_STATIC,7,218,221,48
CONTROL "Disable Copy-on-Write",IDC_NODATACOW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,218,86,10 CONTROL "Disable Copy-on-Write",IDC_NODATACOW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,232,86,10
LTEXT "(blank)",IDC_INODE,78,35,70,8 LTEXT "(blank)",IDC_INODE,78,35,70,8
LTEXT "(blank)",IDC_TYPE,78,49,116,8 LTEXT "(blank)",IDC_TYPE,78,49,116,8
CONTROL "Compress",IDC_COMPRESS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,232,46,10 CONTROL "Compress",IDC_COMPRESS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,246,46,10
LTEXT "Size on disk:",IDC_STATIC,14,63,61,8 LTEXT "Size on disk:",IDC_STATIC,14,63,61,8
CONTROL "%s (<a>Details</a>)",IDC_SIZE_ON_DISK,"SysLink",WS_TABSTOP,78,63,142,8 CONTROL "%s (<a>Details</a>)",IDC_SIZE_ON_DISK,"SysLink",WS_TABSTOP,78,63,142,8
COMBOBOX IDC_COMPRESS_TYPE,63,231,48,13,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_COMPRESS_TYPE,63,245,48,13,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
CONTROL "Readonly subvolume",IDC_SUBVOL_RO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,124,218,80,10 CONTROL "Readonly subvolume",IDC_SUBVOL_RO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,124,232,80,10
LTEXT "(blank)",IDC_SUBVOL,78,21,70,8 LTEXT "(blank)",IDC_SUBVOL,78,21,70,8
PUSHBUTTON "&Open as Admin",IDC_OPEN_ADMIN,151,21,70,14 PUSHBUTTON "&Open as Admin",IDC_OPEN_ADMIN,151,21,70,14
CONTROL "Set UID",IDC_SETUID,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,177,161,40,10 CONTROL "Set UID",IDC_SETUID,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,177,175,40,10
CONTROL "Set GID",IDC_SETGID,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,177,172,40,10 CONTROL "Set GID",IDC_SETGID,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,177,186,40,10
CONTROL "Sticky",IDC_STICKY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,177,182,34,10 CONTROL "Sticky",IDC_STICKY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,177,196,34,10
LTEXT "Compression ratio:",IDC_STATIC,14,77,61,8 LTEXT "Compression ratio:",IDC_STATIC,14,77,61,8
LTEXT "%1.1f%%",IDC_COMPRESSION_RATIO,78,77,116,8 LTEXT "%1.1f%%",IDC_COMPRESSION_RATIO,78,77,116,8
LTEXT "Fragmentation:",IDC_STATIC,14,91,61,8
LTEXT "%1.1f%%",IDC_FRAGMENTATION,78,91,116,8
END END
IDD_SIZE_DETAILS DIALOGEX 0, 0, 212, 98 IDD_SIZE_DETAILS DIALOGEX 0, 0, 212, 98
@ -163,25 +165,26 @@ BEGIN
LTEXT "(blank)",IDC_SIZE_ZSTD,63,59,142,8 LTEXT "(blank)",IDC_SIZE_ZSTD,63,59,142,8
END END
IDD_VOL_PROP_SHEET DIALOGEX 0, 0, 235, 251 IDD_VOL_PROP_SHEET DIALOGEX 0, 0, 235, 273
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION
CAPTION "s" CAPTION "s"
FONT 8, "MS Shell Dlg", 400, 0, 0x0 FONT 8, "MS Shell Dlg", 400, 0, 0x0
BEGIN BEGIN
PUSHBUTTON "Show &usage...",IDC_VOL_SHOW_USAGE,154,47,67,19
PUSHBUTTON "&Balance...",IDC_VOL_BALANCE,154,105,67,19
PUSHBUTTON "&Devices...",IDC_VOL_DEVICES,154,162,67,19
LTEXT "UUID:",IDC_STATIC,7,15,20,8 LTEXT "UUID:",IDC_STATIC,7,15,20,8
LTEXT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",IDC_UUID,32,15,294,8 LTEXT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",IDC_UUID,32,15,294,8
GROUPBOX "Usage",IDC_STATIC,7,31,221,53 PUSHBUTTON "Change drive &letter...",IDC_VOL_CHANGE_DRIVE_LETTER,7,30,101,19
LTEXT "Show detailed information about internal filesystem usage. This is the equivalent to the command ""btrfs fi usage"" on Linux.",IDC_STATIC,14,44,131,33 PUSHBUTTON "Show &usage...",IDC_VOL_SHOW_USAGE,154,69,67,19
GROUPBOX "Balance",IDC_STATIC,7,87,221,53 PUSHBUTTON "&Balance...",IDC_VOL_BALANCE,154,127,67,19
LTEXT "Balancing reads and rewrites data and metadata. It can be used to consolidate free space, as well as to convert between different RAID types.",IDC_STATIC,15,98,131,39 PUSHBUTTON "&Devices...",IDC_VOL_DEVICES,154,184,67,19
GROUPBOX "Devices",IDC_STATIC,7,146,221,45 GROUPBOX "Usage",IDC_STATIC,7,53,221,53
LTEXT "Allows you to add disks or partitions to this filesystem, or remove those already present.",IDC_STATIC,14,159,131,30 LTEXT "Show detailed information about internal filesystem usage. This is the equivalent to the command ""btrfs fi usage"" on Linux.",IDC_STATIC,14,66,131,33
GROUPBOX "Scrub",IDC_STATIC,7,199,221,45 GROUPBOX "Balance",IDC_STATIC,7,109,221,53
LTEXT "Scrubbing verifies the data and metadata of a filesystem, and where possible will correct any errors.",IDC_STATIC,15,212,131,27 LTEXT "Balancing reads and rewrites data and metadata. It can be used to consolidate free space, as well as to convert between different RAID types.",IDC_STATIC,15,120,131,39
PUSHBUTTON "&Scrub...",IDC_VOL_SCRUB,154,215,67,19 GROUPBOX "Devices",IDC_STATIC,7,168,221,45
LTEXT "Allows you to add disks or partitions to this filesystem, or remove those already present.",IDC_STATIC,14,181,131,30
GROUPBOX "Scrub",IDC_STATIC,7,221,221,45
LTEXT "Scrubbing verifies the data and metadata of a filesystem, and where possible will correct any errors.",IDC_STATIC,15,234,131,27
PUSHBUTTON "&Scrub...",IDC_VOL_SCRUB,154,237,67,19
END END
IDD_VOL_USAGE DIALOGEX 0, 0, 235, 242 IDD_VOL_USAGE DIALOGEX 0, 0, 235, 242
@ -364,6 +367,17 @@ BEGIN
LTEXT "New size: %s",IDC_RESIZE_NEWSIZE,18,53,238,8 LTEXT "New size: %s",IDC_RESIZE_NEWSIZE,18,53,238,8
END END
IDD_DRIVE_LETTER DIALOGEX 0, 0, 131, 61
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Change drive letter"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,7,40,50,14
PUSHBUTTON "Cancel",IDCANCEL,74,40,50,14
COMBOBOX IDC_DRIVE_LETTER_COMBO,64,17,60,30,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
LTEXT "Drive letter:",IDC_STATIC,15,19,45,8
END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
@ -378,7 +392,7 @@ BEGIN
LEFTMARGIN, 7 LEFTMARGIN, 7
RIGHTMARGIN, 228 RIGHTMARGIN, 228
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 238 BOTTOMMARGIN, 266
END END
IDD_SIZE_DETAILS, DIALOG IDD_SIZE_DETAILS, DIALOG
@ -394,7 +408,7 @@ BEGIN
LEFTMARGIN, 7 LEFTMARGIN, 7
RIGHTMARGIN, 228 RIGHTMARGIN, 228
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 244 BOTTOMMARGIN, 266
END END
IDD_VOL_USAGE, DIALOG IDD_VOL_USAGE, DIALOG
@ -476,6 +490,14 @@ BEGIN
TOPMARGIN, 7 TOPMARGIN, 7
BOTTOMMARGIN, 126 BOTTOMMARGIN, 126
END END
IDD_DRIVE_LETTER, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 124
TOPMARGIN, 7
BOTTOMMARGIN, 54
END
END END
#endif // APSTUDIO_INVOKED #endif // APSTUDIO_INVOKED
@ -503,6 +525,16 @@ BEGIN
0 0
END END
IDD_VOL_PROP_SHEET AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_DRIVE_LETTER AFX_DIALOG_LAYOUT
BEGIN
0
END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
@ -595,9 +627,9 @@ BEGIN
IDS_DEVLIST_READONLY_NO "No" IDS_DEVLIST_READONLY_NO "No"
IDS_DEVLIST_ALLOC "Allocated" IDS_DEVLIST_ALLOC "Allocated"
IDS_DEVLIST_ALLOC_PC "%" IDS_DEVLIST_ALLOC_PC "%"
IDS_BALANCE_RUNNING_REMOVAL IDS_BALANCE_RUNNING_REMOVAL
"Currently removing device %llu (%llu out of %llu chunks processed, %1.1f%%)" "Currently removing device %llu (%llu out of %llu chunks processed, %1.1f%%)"
IDS_BALANCE_PAUSED_REMOVAL IDS_BALANCE_PAUSED_REMOVAL
"Removal of device %llu paused (%llu out of %llu chunks processed, %1.1f%%)" "Removal of device %llu paused (%llu out of %llu chunks processed, %1.1f%%)"
IDS_BALANCE_CANCELLED_REMOVAL "Device removal cancelled." IDS_BALANCE_CANCELLED_REMOVAL "Device removal cancelled."
IDS_BALANCE_COMPLETE_REMOVAL "Device removal completed successfully." IDS_BALANCE_COMPLETE_REMOVAL "Device removal completed successfully."
@ -608,12 +640,12 @@ END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_CANNOT_REMOVE_RAID "The current RAID levels do not allow this device to be removed. You must do a conversion balance before you will be able to proceed." IDS_CANNOT_REMOVE_RAID "The current RAID levels do not allow this device to be removed. You must do a conversion balance before you will be able to proceed."
IDS_REMOVE_DEVICE_CONFIRMATION IDS_REMOVE_DEVICE_CONFIRMATION
"Are you sure that you want to remove device %s, %s?" "Are you sure that you want to remove device %s, %s?"
IDS_CONFIRMATION_TITLE "Confirmation" IDS_CONFIRMATION_TITLE "Confirmation"
IDS_ADD_DEVICE_CONFIRMATION IDS_ADD_DEVICE_CONFIRMATION
"Are you sure that you want to add this device?" "Are you sure that you want to add this device?"
IDS_ADD_DEVICE_CONFIRMATION_FS IDS_ADD_DEVICE_CONFIRMATION_FS
"Are you sure that you want to add this device? It already appears to contain a filesystem (%s)." "Are you sure that you want to add this device? It already appears to contain a filesystem (%s)."
IDS_BALANCE_FAILED "Balance failed (error %08x, %s)" IDS_BALANCE_FAILED "Balance failed (error %08x, %s)"
IDS_BALANCE_FAILED_REMOVAL "Device removal failed (error %08x, %s)" IDS_BALANCE_FAILED_REMOVAL "Device removal failed (error %08x, %s)"
@ -624,32 +656,32 @@ BEGIN
IDS_SCRUB_FINISHED "Scrub finished." IDS_SCRUB_FINISHED "Scrub finished."
IDS_SCRUB_PAUSED "Scrub paused (%llu out of %llu chunks processed, %1.1f%%)" IDS_SCRUB_PAUSED "Scrub paused (%llu out of %llu chunks processed, %1.1f%%)"
IDS_SCRUB_MSG_STARTED "Scrub started at %s %s." IDS_SCRUB_MSG_STARTED "Scrub started at %s %s."
IDS_SCRUB_MSG_RECOVERABLE_DATA IDS_SCRUB_MSG_RECOVERABLE_DATA
"Recovered from data checksum error at %llx on device %llx." "Recovered from data checksum error at %llx on device %llx."
IDS_SCRUB_MSG_RECOVERABLE_METADATA IDS_SCRUB_MSG_RECOVERABLE_METADATA
"Recovered from metadata checksum error at %llx on device %llx." "Recovered from metadata checksum error at %llx on device %llx."
END END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_SCRUB_MSG_UNRECOVERABLE_DATA IDS_SCRUB_MSG_UNRECOVERABLE_DATA
"Unrecoverable data checksum error at %llx on device %llx (%.*s, offset %llx)" "Unrecoverable data checksum error at %llx on device %llx (%.*s, offset %llx)"
IDS_SCRUB_MSG_UNRECOVERABLE_DATA_SUBVOL IDS_SCRUB_MSG_UNRECOVERABLE_DATA_SUBVOL
"Unrecoverable data checksum error at %llx on device %llx (subvol %llx, %.*s, offset %llx)" "Unrecoverable data checksum error at %llx on device %llx (subvol %llx, %.*s, offset %llx)"
IDS_SCRUB_MSG_UNRECOVERABLE_METADATA IDS_SCRUB_MSG_UNRECOVERABLE_METADATA
"Unrecoverable metadata checksum error at %llx on device %llx (root %llx, level %x)" "Unrecoverable metadata checksum error at %llx on device %llx (root %llx, level %x)"
IDS_SCRUB_MSG_UNRECOVERABLE_METADATA_FIRSTITEM IDS_SCRUB_MSG_UNRECOVERABLE_METADATA_FIRSTITEM
"Unrecoverable metadata checksum error at %llx on device %llx (root %llx, level %x, first item %llx,%x,%llx)" "Unrecoverable metadata checksum error at %llx on device %llx (root %llx, level %x, first item %llx,%x,%llx)"
IDS_SCRUB_MSG_FINISHED "Scrub finished at %s %s." IDS_SCRUB_MSG_FINISHED "Scrub finished at %s %s."
IDS_SCRUB_MSG_SUMMARY "Scrubbed %s in %llu seconds (%s/s)." IDS_SCRUB_MSG_SUMMARY "Scrubbed %s in %llu seconds (%s/s)."
IDS_BALANCE_SCRUB_RUNNING "Cannot start balance while scrub running." IDS_BALANCE_SCRUB_RUNNING "Cannot start balance while scrub running."
IDS_SCRUB_BALANCE_RUNNING "Cannot start scrub while balance running." IDS_SCRUB_BALANCE_RUNNING "Cannot start scrub while balance running."
IDS_SCRUB_MSG_SUMMARY_ERRORS_RECOVERABLE "Recovered from %llu error(s)." IDS_SCRUB_MSG_SUMMARY_ERRORS_RECOVERABLE "Recovered from %llu error(s)."
IDS_SCRUB_MSG_SUMMARY_ERRORS_UNRECOVERABLE IDS_SCRUB_MSG_SUMMARY_ERRORS_UNRECOVERABLE
"%llu unrecoverable error(s) found." "%llu unrecoverable error(s) found."
IDS_SCRUB_FAILED "Scrub failed with error %08x." IDS_SCRUB_FAILED "Scrub failed with error %08x."
IDS_LOCK_FAILED "Unable to lock volume: error %08x. Make sure that there are no files open, and that you have closed any Explorer windows." IDS_LOCK_FAILED "Unable to lock volume: error %08x. Make sure that there are no files open, and that you have closed any Explorer windows."
IDS_SCRUB_MSG_RECOVERABLE_PARITY IDS_SCRUB_MSG_RECOVERABLE_PARITY
"Recovered from parity error at %llx on device %llx." "Recovered from parity error at %llx on device %llx."
IDS_COMPRESS_ANY "(any)" IDS_COMPRESS_ANY "(any)"
IDS_COMPRESS_ZLIB "Zlib" IDS_COMPRESS_ZLIB "Zlib"
@ -668,13 +700,12 @@ BEGIN
IDS_OUT_OF_MEMORY "Out of memory." IDS_OUT_OF_MEMORY "Out of memory."
IDS_RECV_UNKNOWN_COMMAND "Unrecognized command %u encountered." IDS_RECV_UNKNOWN_COMMAND "Unrecognized command %u encountered."
IDS_RECV_CANT_OPEN_PATH "Couldn't open path %s (error %u, %s)." IDS_RECV_CANT_OPEN_PATH "Couldn't open path %s (error %u, %s)."
IDS_RECV_RTLUTF8TOUNICODEN_FAILED "RtlUTF8ToUnicodeN returned %08x (%s)." IDS_RECV_CREATE_SUBVOL_FAILED
IDS_RECV_CREATE_SUBVOL_FAILED
"FSCTL_BTRFS_CREATE_SUBVOL returned %08x (%s)." "FSCTL_BTRFS_CREATE_SUBVOL returned %08x (%s)."
IDS_RECV_MISSING_PARAM "%S: could not find %s parameter." IDS_RECV_MISSING_PARAM "%S: could not find %s parameter."
IDS_RECV_SHORT_PARAM "%S: length of parameter %s was %u, expected %u." IDS_RECV_SHORT_PARAM "%S: length of parameter %s was %u, expected %u."
IDS_RECV_MKNOD_FAILED "FSCTL_BTRFS_MKNOD returned %08x (%s)." IDS_RECV_MKNOD_FAILED "FSCTL_BTRFS_MKNOD returned %08x (%s)."
IDS_RECV_SET_REPARSE_POINT_FAILED IDS_RECV_SET_REPARSE_POINT_FAILED
"FSCTL_SET_REPARSE_POINT returned %08x (%s)." "FSCTL_SET_REPARSE_POINT returned %08x (%s)."
END END
@ -683,19 +714,17 @@ BEGIN
IDS_RECV_MOVEFILE_FAILED "MoveFile (%s -> %s) failed (error %u, %s)." IDS_RECV_MOVEFILE_FAILED "MoveFile (%s -> %s) failed (error %u, %s)."
IDS_RECV_SETFILEPOINTER_FAILED "SetFilePointer failed (error %u, %s)." IDS_RECV_SETFILEPOINTER_FAILED "SetFilePointer failed (error %u, %s)."
IDS_RECV_WRITEFILE_FAILED "WriteFile failed (error %u, %s)." IDS_RECV_WRITEFILE_FAILED "WriteFile failed (error %u, %s)."
IDS_RECV_CREATEHARDLINK_FAILED IDS_RECV_CREATEHARDLINK_FAILED
"CreateHardLink (%s -> %s) failed (error %u, %s)." "CreateHardLink (%s -> %s) failed (error %u, %s)."
IDS_RECV_SETENDOFFILE_FAILED "SetEndOfFile failed (error %u, %s)." IDS_RECV_SETENDOFFILE_FAILED "SetEndOfFile failed (error %u, %s)."
IDS_RECV_CANT_CREATE_FILE "Couldn't create %s (error %u, %s)." IDS_RECV_CANT_CREATE_FILE "Couldn't create %s (error %u, %s)."
IDS_RECV_SETFILEINFO_FAILED IDS_RECV_SETINODEINFO_FAILED
"SetFileInformationByHandle failed (error %u, %s)."
IDS_RECV_SETINODEINFO_FAILED
"FSCTL_BTRFS_SET_INODE_INFO returned %08x (%s)." "FSCTL_BTRFS_SET_INODE_INFO returned %08x (%s)."
IDS_RECV_SUCCESS "Received 1 subvolume successfully." IDS_RECV_SUCCESS "Received 1 subvolume successfully."
IDS_RECV_BUTTON_OK "OK" IDS_RECV_BUTTON_OK "OK"
IDS_RECV_SETFILEATTRIBUTES_FAILED IDS_RECV_SETFILEATTRIBUTES_FAILED
"SetFileAttributes failed (error %u, %s)." "SetFileAttributes failed (error %u, %s)."
IDS_RECV_GETFILEATTRIBUTES_FAILED IDS_RECV_GETFILEATTRIBUTES_FAILED
"GetFileAttributes failed (error %u, %s)." "GetFileAttributes failed (error %u, %s)."
IDS_RECV_CSUM_ERROR "Checksum error." IDS_RECV_CSUM_ERROR "Checksum error."
IDS_RECV_NOT_A_SEND_STREAM "File was not a send stream." IDS_RECV_NOT_A_SEND_STREAM "File was not a send stream."
@ -705,28 +734,28 @@ END
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_RECV_RECEIVED_SUBVOL_FAILED IDS_RECV_RECEIVED_SUBVOL_FAILED
"FSCTL_BTRFS_RECEIVED_SUBVOL returned %08x (%s)." "FSCTL_BTRFS_RECEIVED_SUBVOL returned %08x (%s)."
IDS_RECV_SETSECURITYOBJECT_FAILED IDS_RECV_SETSECURITYOBJECT_FAILED
"NtSetSecurityObject returned %08x (%s)." "NtSetSecurityObject returned %08x (%s)."
IDS_RECV_SETXATTR_FAILED "FSCTL_BTRFS_SET_XATTR returned %08x (%s)." IDS_RECV_SETXATTR_FAILED "FSCTL_BTRFS_SET_XATTR returned %08x (%s)."
IDS_RECV_CREATETHREAD_FAILED "CreateThread failed (error %u, %s)." IDS_RECV_CREATETHREAD_FAILED "CreateThread failed (error %u, %s)."
IDS_RECV_FILE_TRUNCATED "File was truncated." IDS_RECV_FILE_TRUNCATED "File was truncated."
IDS_RECV_RESERVE_SUBVOL_FAILED IDS_RECV_RESERVE_SUBVOL_FAILED
"FSCTL_BTRFS_RESERVE_SUBVOL returned %08x (%s)." "FSCTL_BTRFS_RESERVE_SUBVOL returned %08x (%s)."
IDS_RECV_CANCELLED "Receiving cancelled." IDS_RECV_CANCELLED "Receiving cancelled."
IDS_RECV_CANT_FIND_PARENT_SUBVOL "Could not find parent subvolume." IDS_RECV_CANT_FIND_PARENT_SUBVOL "Could not find parent subvolume."
IDS_RECV_FIND_SUBVOL_FAILED "FSCTL_BTRFS_FIND_SUBVOL returned %08x (%s)." IDS_RECV_FIND_SUBVOL_FAILED "FSCTL_BTRFS_FIND_SUBVOL returned %08x (%s)."
IDS_RECV_CREATE_SNAPSHOT_FAILED IDS_RECV_CREATE_SNAPSHOT_FAILED
"FSCTL_BTRFS_CREATE_SNAPSHOT returned %08x (%s)." "FSCTL_BTRFS_CREATE_SNAPSHOT returned %08x (%s)."
IDS_RECV_GETVOLUMEPATHNAME_FAILED IDS_RECV_GETVOLUMEPATHNAME_FAILED
"GetVolumePathName failed (error %u, %s)." "GetVolumePathName failed (error %u, %s)."
IDS_RECV_DELETEFILE_FAILED "DeleteFile failed for %s (error %u, %s)." IDS_RECV_DELETEFILE_FAILED "DeleteFile failed for %s (error %u, %s)."
IDS_RECV_REMOVEDIRECTORY_FAILED IDS_RECV_REMOVEDIRECTORY_FAILED
"RemoveDirectory failed for %s (error %u, %s)." "RemoveDirectory failed for %s (error %u, %s)."
IDS_RECV_CANT_FIND_CLONE_SUBVOL "Could not find clone subvolume." IDS_RECV_CANT_FIND_CLONE_SUBVOL "Could not find clone subvolume."
IDS_RECV_GETFILESIZEEX_FAILED "GetFileSizeEx failed (error %u, %s)." IDS_RECV_GETFILESIZEEX_FAILED "GetFileSizeEx failed (error %u, %s)."
IDS_RECV_DUPLICATE_EXTENTS_FAILED IDS_RECV_DUPLICATE_EXTENTS_FAILED
"FSCTL_DUPLICATE_EXTENTS_TO_FILE returned %08x (%s)." "FSCTL_DUPLICATE_EXTENTS_TO_FILE returned %08x (%s)."
END END
@ -737,13 +766,13 @@ BEGIN
IDS_SEND_SUBVOL_HELP "Exports a subvolume so that it can be recreated on another volume." IDS_SEND_SUBVOL_HELP "Exports a subvolume so that it can be recreated on another volume."
IDS_SEND_CANT_OPEN_FILE "Error opening file %s (error %u, %s)." IDS_SEND_CANT_OPEN_FILE "Error opening file %s (error %u, %s)."
IDS_SEND_CANT_OPEN_DIR "Error opening directory %s (error %u, %s)." IDS_SEND_CANT_OPEN_DIR "Error opening directory %s (error %u, %s)."
IDS_SEND_FSCTL_BTRFS_SEND_SUBVOL_FAILED IDS_SEND_FSCTL_BTRFS_SEND_SUBVOL_FAILED
"FSCTL_BTRFS_SEND_SUBVOL returned error %08x (%s)." "FSCTL_BTRFS_SEND_SUBVOL returned error %08x (%s)."
IDS_SEND_FSCTL_BTRFS_READ_SEND_BUFFER_FAILED IDS_SEND_FSCTL_BTRFS_READ_SEND_BUFFER_FAILED
"FSCTL_BTRFS_READ_SEND_BUFFER returned error %08x (%s)." "FSCTL_BTRFS_READ_SEND_BUFFER returned error %08x (%s)."
IDS_SEND_SUCCESS "Stream written successfully." IDS_SEND_SUCCESS "Stream written successfully."
IDS_SEND_WRITEFILE_FAILED "Writing to file failed (error %u, %s)." IDS_SEND_WRITEFILE_FAILED "Writing to file failed (error %u, %s)."
IDS_SEND_GET_FILE_INFO_FAILED IDS_SEND_GET_FILE_INFO_FAILED
"GetFileInformationByHandle failed (error %u, %s)." "GetFileInformationByHandle failed (error %u, %s)."
IDS_SEND_NOT_READONLY "Subvolume not readonly." IDS_SEND_NOT_READONLY "Subvolume not readonly."
IDS_NOT_SUBVOL "Directory was not a subvolume." IDS_NOT_SUBVOL "Directory was not a subvolume."
@ -759,20 +788,18 @@ BEGIN
IDS_SEND_WRITING "Writing..." IDS_SEND_WRITING "Writing..."
IDS_MISSING "(missing)" IDS_MISSING "(missing)"
IDS_RESIZE_SUCCESSFUL "Device %llx successfully resized to %s." IDS_RESIZE_SUCCESSFUL "Device %llx successfully resized to %s."
IDS_BALANCE_RUNNING_SHRINK IDS_BALANCE_RUNNING_SHRINK
"Currently shrinking device %llu (%llu out of %llu chunks processed, %1.1f%%)" "Currently shrinking device %llu (%llu out of %llu chunks processed, %1.1f%%)"
IDS_BALANCE_PAUSED_SHRINK IDS_BALANCE_PAUSED_SHRINK
"Shrinking of device %llu paused (%llu out of %llu chunks processed, %1.1f%%)" "Shrinking of device %llu paused (%llu out of %llu chunks processed, %1.1f%%)"
IDS_BALANCE_CANCELLED_SHRINK "Device shrinking cancelled." IDS_BALANCE_CANCELLED_SHRINK "Device shrinking cancelled."
IDS_BALANCE_COMPLETE_SHRINK "Device successfully shrunk." IDS_BALANCE_COMPLETE_SHRINK "Device successfully shrunk."
IDS_BALANCE_FAILED_SHRINK "Device shrinking failed (error %08x, %s)" IDS_BALANCE_FAILED_SHRINK "Device shrinking failed (error %08x, %s)"
IDS_COMPRESS_ZSTD "Zstd" IDS_COMPRESS_ZSTD "Zstd"
IDS_RECV_RTLUNICODETOUTF8N_FAILED "RtlUnicodeToUTF8N returned %08x (%s)."
IDS_REGCREATEKEY_FAILED "RegCreateKey returned %08x" IDS_REGCREATEKEY_FAILED "RegCreateKey returned %08x"
IDS_REGSETVALUEEX_FAILED "RegSetValueEx returned %08x" IDS_REGSETVALUEEX_FAILED "RegSetValueEx returned %08x"
IDS_REGCLOSEKEY_FAILED "RegCloseKey returned %08x" IDS_REGCLOSEKEY_FAILED "RegCloseKey returned %08x"
IDS_REGDELETETREE_FAILED "RegDeleteTree returned %08x" IDS_CANT_REFLINK_DIFFERENT_FS
IDS_CANT_REFLINK_DIFFERENT_FS
"Cannot create a reflink between two different filesystems." "Cannot create a reflink between two different filesystems."
END END

View file

@ -21,3 +21,4 @@
@ stdcall -private SendSubvolW(ptr ptr wstr long) @ stdcall -private SendSubvolW(ptr ptr wstr long)
@ stdcall -private RecvSubvolW(ptr ptr wstr long) @ stdcall -private RecvSubvolW(ptr ptr wstr long)
@ stdcall -private ResizeDeviceW(ptr ptr wstr long) @ stdcall -private ResizeDeviceW(ptr ptr wstr long)
@ stdcall -private ShowChangeDriveLetterW(ptr ptr wstr long)

72
dll/shellext/shellbtrfs/shellext.h Normal file → Executable file
View file

@ -44,6 +44,10 @@
#include <ndk/obfuncs.h> #include <ndk/obfuncs.h>
#endif #endif
#include <string> #include <string>
#ifdef __REACTOS__
#define string_view string
#define wstring_view wstring
#endif
#include <vector> #include <vector>
#include <stdint.h> #include <stdint.h>
#ifndef __REACTOS__ #ifndef __REACTOS__
@ -105,36 +109,55 @@ NTSYSCALLAPI NTSTATUS NTAPI NtFsControlFile(HANDLE FileHandle, HANDLE Event, PIO
NTSTATUS NTAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, NTSTATUS NTAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer,
ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key);
#endif
NTSTATUS WINAPI RtlUTF8ToUnicodeN(PWSTR UnicodeStringDestination, ULONG UnicodeStringMaxWCharCount,
PULONG UnicodeStringActualWCharCount, PCCH UTF8StringSource,
ULONG UTF8StringByteCount);
NTSTATUS NTAPI RtlUnicodeToUTF8N(PCHAR UTF8StringDestination, ULONG UTF8StringMaxByteCount,
PULONG UTF8StringActualByteCount, PCWCH UnicodeStringSource,
ULONG UnicodeStringByteCount);
#ifndef __REACTOS__
NTSTATUS WINAPI NtSetEaFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length); NTSTATUS WINAPI NtSetEaFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length);
NTSTATUS WINAPI NtSetSecurityObject(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor); NTSTATUS WINAPI NtSetSecurityObject(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor);
NTSTATUS NTAPI NtQueryInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS FileInformationClass); NTSTATUS NTAPI NtQueryInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS FileInformationClass);
NTSTATUS NTAPI NtSetInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS FileInformationClass);
#ifdef _MSC_VER
#define FileBasicInformation (FILE_INFORMATION_CLASS)4
#define FileStandardInformation (FILE_INFORMATION_CLASS)5
#define FileDispositionInformation (FILE_INFORMATION_CLASS)13
#define FileEndOfFileInformation (FILE_INFORMATION_CLASS)20
#define FileStreamInformation (FILE_INFORMATION_CLASS)22
typedef enum _FSINFOCLASS {
FileFsVolumeInformation = 1,
FileFsLabelInformation,
FileFsSizeInformation,
FileFsDeviceInformation,
FileFsAttributeInformation,
FileFsControlInformation,
FileFsFullSizeInformation,
FileFsObjectIdInformation,
FileFsDriverPathInformation,
FileFsVolumeFlagsInformation,
FileFsSectorSizeInformation,
FileFsDataCopyInformation,
FileFsMetadataSizeInformation,
FileFsFullSizeInformationEx,
FileFsMaximumInformation
} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
typedef struct _FILE_STREAM_INFORMATION {
ULONG NextEntryOffset;
ULONG StreamNameLength;
LARGE_INTEGER StreamSize;
LARGE_INTEGER StreamAllocationSize;
WCHAR StreamName[1];
} FILE_STREAM_INFORMATION, *PFILE_STREAM_INFORMATION;
#endif
NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length,
FS_INFORMATION_CLASS FsInformationClass);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#else
BOOL
WINAPI
SetFileInformationByHandle(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize);
BOOL
WINAPI
GetFileInformationByHandleEx(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize);
#ifdef __cplusplus
}
#endif
#endif
#ifndef __REACTOS__ #ifndef __REACTOS__
typedef struct _REPARSE_DATA_BUFFER { typedef struct _REPARSE_DATA_BUFFER {
@ -358,6 +381,8 @@ public:
return msg.c_str(); return msg.c_str();
} }
NTSTATUS Status;
private: private:
string msg; string msg;
}; };
@ -376,7 +401,6 @@ wstring format_message(ULONG last_error);
wstring format_ntstatus(NTSTATUS Status); wstring format_ntstatus(NTSTATUS Status);
bool load_string(HMODULE module, UINT id, wstring& s); bool load_string(HMODULE module, UINT id, wstring& s);
void wstring_sprintf(wstring& s, wstring fmt, ...); void wstring_sprintf(wstring& s, wstring fmt, ...);
void command_line_to_args(LPWSTR cmdline, vector<wstring> args); void command_line_to_args(LPWSTR cmdline, vector<wstring>& args);
void utf8_to_utf16(const string& utf8, wstring& utf16); wstring utf8_to_utf16(const string_view& utf8);
void utf16_to_utf8(const wstring& utf16, string& utf8);
void error_message(HWND hwnd, const char* msg); void error_message(HWND hwnd, const char* msg);

0
dll/shellext/shellbtrfs/subvol.ico Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

217
dll/shellext/shellbtrfs/volpropsheet.cpp Normal file → Executable file
View file

@ -38,6 +38,15 @@
#include "volpropsheet.h" #include "volpropsheet.h"
#include "resource.h" #include "resource.h"
#ifndef __REACTOS__
#include "mountmgr.h"
#else
#include "mountmgr_local.h"
#endif
#ifndef __REACTOS__
static const NTSTATUS STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034;
#endif
HRESULT __stdcall BtrfsVolPropSheet::QueryInterface(REFIID riid, void **ppObj) { HRESULT __stdcall BtrfsVolPropSheet::QueryInterface(REFIID riid, void **ppObj) {
if (riid == IID_IUnknown || riid == IID_IShellPropSheetExt) { if (riid == IID_IUnknown || riid == IID_IShellPropSheetExt) {
@ -705,7 +714,7 @@ void BtrfsVolPropSheet::RefreshDevList(HWND devlist) {
RtlZeroMemory(&lvi, sizeof(LVITEMW)); RtlZeroMemory(&lvi, sizeof(LVITEMW));
lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.mask = LVIF_TEXT | LVIF_PARAM;
lvi.iItem = SendMessageW(devlist, LVM_GETITEMCOUNT, 0, 0); lvi.iItem = (int)SendMessageW(devlist, LVM_GETITEMCOUNT, 0, 0);
lvi.lParam = (LPARAM)bd->dev_id; lvi.lParam = (LPARAM)bd->dev_id;
s = to_wstring(bd->dev_id); s = to_wstring(bd->dev_id);
@ -1035,19 +1044,18 @@ INT_PTR CALLBACK BtrfsVolPropSheet::DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARA
{ {
WCHAR sel[MAX_PATH]; WCHAR sel[MAX_PATH];
HWND devlist; HWND devlist;
int index;
LVITEMW lvi; LVITEMW lvi;
devlist = GetDlgItem(hwndDlg, IDC_DEVLIST); devlist = GetDlgItem(hwndDlg, IDC_DEVLIST);
index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED); auto index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
if (index == -1) if (index == -1)
return true; return true;
RtlZeroMemory(&lvi, sizeof(LVITEMW)); RtlZeroMemory(&lvi, sizeof(LVITEMW));
lvi.mask = LVIF_TEXT; lvi.mask = LVIF_TEXT;
lvi.iItem = index; lvi.iItem = (int)index;
lvi.iSubItem = 0; lvi.iSubItem = 0;
lvi.pszText = sel; lvi.pszText = sel;
lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR); lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR);
@ -1063,19 +1071,18 @@ INT_PTR CALLBACK BtrfsVolPropSheet::DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARA
WCHAR modfn[MAX_PATH], sel[MAX_PATH], sel2[MAX_PATH]; WCHAR modfn[MAX_PATH], sel[MAX_PATH], sel2[MAX_PATH];
HWND devlist; HWND devlist;
SHELLEXECUTEINFOW sei; SHELLEXECUTEINFOW sei;
int index;
LVITEMW lvi; LVITEMW lvi;
devlist = GetDlgItem(hwndDlg, IDC_DEVLIST); devlist = GetDlgItem(hwndDlg, IDC_DEVLIST);
index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED); auto index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
if (index == -1) if (index == -1)
return true; return true;
RtlZeroMemory(&lvi, sizeof(LVITEMW)); RtlZeroMemory(&lvi, sizeof(LVITEMW));
lvi.mask = LVIF_TEXT; lvi.mask = LVIF_TEXT;
lvi.iItem = index; lvi.iItem = (int)index;
lvi.iSubItem = 0; lvi.iSubItem = 0;
lvi.pszText = sel; lvi.pszText = sel;
lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR); lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR);
@ -1129,7 +1136,6 @@ INT_PTR CALLBACK BtrfsVolPropSheet::DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARA
case IDC_DEVICE_RESIZE: case IDC_DEVICE_RESIZE:
{ {
HWND devlist; HWND devlist;
int index;
LVITEMW lvi; LVITEMW lvi;
wstring t; wstring t;
WCHAR modfn[MAX_PATH], sel[100]; WCHAR modfn[MAX_PATH], sel[100];
@ -1137,14 +1143,14 @@ INT_PTR CALLBACK BtrfsVolPropSheet::DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARA
devlist = GetDlgItem(hwndDlg, IDC_DEVLIST); devlist = GetDlgItem(hwndDlg, IDC_DEVLIST);
index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED); auto index = SendMessageW(devlist, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
if (index == -1) if (index == -1)
return true; return true;
RtlZeroMemory(&lvi, sizeof(LVITEMW)); RtlZeroMemory(&lvi, sizeof(LVITEMW));
lvi.mask = LVIF_TEXT; lvi.mask = LVIF_TEXT;
lvi.iItem = index; lvi.iItem = (int)index;
lvi.iSubItem = 0; lvi.iSubItem = 0;
lvi.pszText = sel; lvi.pszText = sel;
lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR); lvi.cchTextMax = sizeof(sel) / sizeof(WCHAR);
@ -1288,6 +1294,36 @@ void BtrfsVolPropSheet::ShowScrub(HWND hwndDlg) {
CloseHandle(sei.hProcess); CloseHandle(sei.hProcess);
} }
void BtrfsVolPropSheet::ShowChangeDriveLetter(HWND hwndDlg) {
wstring t;
WCHAR modfn[MAX_PATH];
SHELLEXECUTEINFOW sei;
GetModuleFileNameW(module, modfn, sizeof(modfn) / sizeof(WCHAR));
#ifndef __REACTOS__
t = L"\""s + modfn + L"\",ShowChangeDriveLetter "s + fn;
#else
t = wstring(L"\"") + modfn + wstring(L"\",ShowChangeDriveLetter ") + fn;
#endif
RtlZeroMemory(&sei, sizeof(sei));
sei.cbSize = sizeof(sei);
sei.hwnd = hwndDlg;
sei.lpVerb = L"runas";
sei.lpFile = L"rundll32.exe";
sei.lpParameters = t.c_str();
sei.nShow = SW_SHOW;
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
if (!ShellExecuteExW(&sei))
throw last_error(GetLastError());
WaitForSingleObject(sei.hProcess, INFINITE);
CloseHandle(sei.hProcess);
}
static INT_PTR CALLBACK PropSheetDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static INT_PTR CALLBACK PropSheetDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
try { try {
switch (uMsg) { switch (uMsg) {
@ -1331,6 +1367,7 @@ static INT_PTR CALLBACK PropSheetDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
SetDlgItemTextW(hwndDlg, IDC_UUID, L""); SetDlgItemTextW(hwndDlg, IDC_UUID, L"");
SendMessageW(GetDlgItem(hwndDlg, IDC_VOL_SCRUB), BCM_SETSHIELD, 0, true); SendMessageW(GetDlgItem(hwndDlg, IDC_VOL_SCRUB), BCM_SETSHIELD, 0, true);
SendMessageW(GetDlgItem(hwndDlg, IDC_VOL_CHANGE_DRIVE_LETTER), BCM_SETSHIELD, 0, true);
return false; return false;
} }
@ -1368,6 +1405,10 @@ static INT_PTR CALLBACK PropSheetDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
case IDC_VOL_SCRUB: case IDC_VOL_SCRUB:
bps->ShowScrub(hwndDlg); bps->ShowScrub(hwndDlg);
break; break;
case IDC_VOL_CHANGE_DRIVE_LETTER:
bps->ShowChangeDriveLetter(hwndDlg);
break;
} }
} }
} }
@ -1430,6 +1471,156 @@ HRESULT __stdcall BtrfsVolPropSheet::ReplacePage(UINT uPageID, LPFNADDPROPSHEETP
return S_OK; return S_OK;
} }
void BtrfsChangeDriveLetter::do_change(HWND hwndDlg) {
unsigned int sel = (unsigned int)SendDlgItemMessageW(hwndDlg, IDC_DRIVE_LETTER_COMBO, CB_GETCURSEL, 0, 0);
if (sel >= 0 && sel < letters.size()) {
wstring dd;
if (fn.length() == 3 && fn[1] == L':' && fn[2] == L'\\') {
dd = L"\\DosDevices\\?:";
dd[12] = fn[0];
} else
#ifndef __REACTOS__
throw runtime_error("Volume path was not root of drive.");
#else
error_message(nullptr, "Volume path was not root of drive.");
#endif
mountmgr mm;
wstring dev_name;
{
auto v = mm.query_points(dd);
if (v.empty())
#ifndef __REACTOS__
throw runtime_error("Error finding device name.");
#else
error_message(nullptr, "Error finding device name.");
#endif
dev_name = v[0].device_name;
}
wstring new_dd = L"\\DosDevices\\?:";
new_dd[12] = letters[sel];
mm.delete_points(dd);
try {
mm.create_point(new_dd, dev_name);
} catch (...) {
// if fails, try to recreate old symlink, so we're not left with no drive letter at all
mm.create_point(dd, dev_name);
throw;
}
}
EndDialog(hwndDlg, 1);
}
INT_PTR BtrfsChangeDriveLetter::DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
try {
switch (uMsg) {
case WM_INITDIALOG:
{
HWND cb = GetDlgItem(hwndDlg, IDC_DRIVE_LETTER_COMBO);
SendMessageW(cb, CB_RESETCONTENT, 0, 0);
mountmgr mm;
wstring drv;
drv = L"\\DosDevices\\?:";
for (wchar_t l = 'A'; l <= 'Z'; l++) {
bool found = true;
drv[12] = l;
try {
auto v = mm.query_points(drv);
if (v.empty())
found = false;
} catch (const ntstatus_error& ntstatus) {
if (ntstatus.Status == STATUS_OBJECT_NAME_NOT_FOUND)
found = false;
else
throw;
}
if (!found) {
wstring str = L"?:";
str[0] = l;
letters.push_back(l);
SendMessageW(cb, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(str.c_str()));
}
}
break;
}
case WM_COMMAND:
switch (HIWORD(wParam)) {
case BN_CLICKED:
switch (LOWORD(wParam)) {
case IDOK:
do_change(hwndDlg);
return true;
case IDCANCEL:
EndDialog(hwndDlg, 0);
return true;
}
break;
}
break;
}
} catch (const exception& e) {
error_message(hwndDlg, e.what());
}
return false;
}
#ifdef __REACTOS__
INT_PTR CALLBACK VolPropSheetDlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
BtrfsChangeDriveLetter* bcdl;
if (uMsg == WM_INITDIALOG) {
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
bcdl = (BtrfsChangeDriveLetter*)lParam;
} else
bcdl = (BtrfsChangeDriveLetter*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
return bcdl->DlgProc(hwndDlg, uMsg, wParam, lParam);
}
#endif
void BtrfsChangeDriveLetter::show() {
#ifndef __REACTOS__
DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_DRIVE_LETTER), hwnd, [](HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
BtrfsChangeDriveLetter* bcdl;
if (uMsg == WM_INITDIALOG) {
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
bcdl = (BtrfsChangeDriveLetter*)lParam;
} else
bcdl = (BtrfsChangeDriveLetter*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
return bcdl->DlgProc(hwndDlg, uMsg, wParam, lParam);
}, (LPARAM)this);
#else
DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_DRIVE_LETTER), hwnd, VolPropSheetDlgproc, (LPARAM)this);
#endif
}
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -1488,6 +1679,12 @@ void CALLBACK ResetStatsW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nC
} }
} }
void CALLBACK ShowChangeDriveLetterW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
BtrfsChangeDriveLetter bcdl(hwnd, lpszCmdLine);
bcdl.show();
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

17
dll/shellext/shellbtrfs/volpropsheet.h Normal file → Executable file
View file

@ -92,6 +92,7 @@ public:
INT_PTR CALLBACK DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK DeviceDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void ShowDevices(HWND hwndDlg); void ShowDevices(HWND hwndDlg);
void ShowScrub(HWND hwndDlg); void ShowScrub(HWND hwndDlg);
void ShowChangeDriveLetter(HWND hwndDlg);
INT_PTR CALLBACK StatsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR CALLBACK StatsDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void ShowStats(HWND hwndDlg, uint64_t devid); void ShowStats(HWND hwndDlg, uint64_t devid);
void ResetStats(HWND hwndDlg); void ResetStats(HWND hwndDlg);
@ -110,3 +111,19 @@ private:
wstring fn; wstring fn;
uint64_t stats_dev; uint64_t stats_dev;
}; };
class BtrfsChangeDriveLetter {
public:
BtrfsChangeDriveLetter(HWND hwnd, const wstring_view& fn) : hwnd(hwnd), fn(fn) {
}
void show();
INT_PTR DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
private:
void do_change(HWND hwndDlg);
HWND hwnd;
wstring fn;
vector<wchar_t> letters;
};