[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
18 changed files with 1001 additions and 537 deletions

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);
if (SUCCEEDED(hr)) {
UINT stride = cx * sizeof(DWORD);
UINT stride = (UINT)(cx * sizeof(DWORD));
UINT buflen = cy * stride;
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) {
wstring subvolname, parpath, searchpath, temp1, name, nameorig;
win_handle h2;
btrfs_create_snapshot* bcs;
ULONG namelen;
WIN32_FIND_DATAW wfd;
SYSTEMTIME time;
@@ -511,16 +509,17 @@ static void create_snapshot(HWND hwnd, const wstring& fn) {
} 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->posix = false;
bcs->subvol = h;
bcs->namelen = (uint16_t)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))
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));
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);
@@ -629,19 +629,19 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
return;
}
if (!GetFileInformationByHandleEx(source, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO)))
throw last_error(GetLastError());
Status = NtQueryInformationFile(source, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation);
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) {
win_handle dirh;
ULONG bmnsize;
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);
if (dirh == INVALID_HANDLE_VALUE)
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->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));
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)) {
free(bmn);
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
} else {
WIN32_FIND_STREAM_DATA fsd;
if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
reparse_header rh;
ULONG rplen;
uint8_t* rp;
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());
}
rplen = sizeof(reparse_header) + rh.ReparseDataLength;
size_t rplen = sizeof(reparse_header) + rh.ReparseDataLength;
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());
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());
free(rp);
@@ -790,8 +787,9 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
uint64_t offset, alloc_size;
ULONG maxdup;
if (!GetFileInformationByHandleEx(source, FileStandardInfo, &fsi, sizeof(FILE_STANDARD_INFO)))
throw last_error(GetLastError());
Status = NtQueryInformationFile(source, &iosb, &fsi, sizeof(FILE_STANDARD_INFO), FileStandardInformation);
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))
throw last_error(GetLastError());
@@ -808,8 +806,9 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
throw last_error(GetLastError());
feofi.EndOfFile = fsi.EndOfFile;
if (!SetFileInformationByHandle(dest, FileEndOfFileInfo, &feofi, sizeof(FILE_END_OF_FILE_INFO)))
throw last_error(GetLastError());
Status = NtSetInformationFile(dest, &iosb, &feofi, sizeof(FILE_END_OF_FILE_INFO), FileEndOfFileInformation);
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
ded.FileHandle = source;
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);
if (h != INVALID_HANDLE_VALUE) {
do {
wstring sn;
ULONG streambufsize = 0;
vector<char> streambuf;
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") {
win_handle stream;
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;
fn2 = fn;
@@ -876,7 +890,12 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
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;
while (xa2->valuelen > 0) {
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)) {
free(xa);
throw ntstatus_error(Status);
@@ -924,8 +943,9 @@ void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir
FILE_DISPOSITION_INFO fdi;
fdi.DeleteFile = true;
if (!SetFileInformationByHandle(dest, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO)))
throw last_error(GetLastError());
Status = NtSetInformationFile(dest, &iosb, &fdi, sizeof(FILE_DISPOSITION_INFO), FileDispositionInformation);
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
throw;
}
@@ -1007,7 +1027,6 @@ HRESULT __stdcall BtrfsContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO picia) {
win_handle h;
IO_STATUS_BLOCK iosb;
NTSTATUS Status;
ULONG bcslen;
wstring name, nameorig, searchpath;
btrfs_create_subvol* bcs;
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->readonly = false;
@@ -1056,7 +1075,7 @@ HRESULT __stdcall BtrfsContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO picia) {
bcs->namelen = (uint16_t)(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);
@@ -1319,7 +1338,6 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
// if subvol, do snapshot instead
if (bii.inode == SUBVOL_ROOT_INODE) {
ULONG bcslen;
btrfs_create_snapshot* bcs;
win_handle dirh;
@@ -1327,13 +1345,13 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
if (dirh == INVALID_HANDLE_VALUE)
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->subvol = source;
bcs->namelen = (uint16_t)(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)) {
free(bcs);
throw ntstatus_error(Status);
@@ -1344,19 +1362,19 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
return;
}
if (!GetFileInformationByHandleEx(source, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO)))
throw last_error(GetLastError());
Status = NtQueryInformationFile(source, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation);
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) {
win_handle dirh;
ULONG bmnsize;
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);
if (dirh == INVALID_HANDLE_VALUE)
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->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));
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)) {
free(bmn);
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
} else {
WIN32_FIND_STREAM_DATA fsd;
if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
reparse_header rh;
ULONG rplen;
uint8_t* rp;
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());
}
rplen = sizeof(reparse_header) + rh.ReparseDataLength;
size_t rplen = sizeof(reparse_header) + rh.ReparseDataLength;
rp = (uint8_t*)malloc(rplen);
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());
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());
} catch (...) {
free(rp);
@@ -1464,8 +1479,9 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
uint64_t offset, alloc_size;
ULONG maxdup;
if (!GetFileInformationByHandleEx(source, FileStandardInfo, &fsi, sizeof(FILE_STANDARD_INFO)))
throw last_error(GetLastError());
Status = NtQueryInformationFile(source, &iosb, &fsi, sizeof(FILE_STANDARD_INFO), FileStandardInformation);
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))
throw last_error(GetLastError());
@@ -1482,8 +1498,9 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
throw last_error(GetLastError());
feofi.EndOfFile = fsi.EndOfFile;
if (!SetFileInformationByHandle(dest, FileEndOfFileInfo, &feofi, sizeof(FILE_END_OF_FILE_INFO)))
throw last_error(GetLastError());
Status = NtSetInformationFile(dest, &iosb, &feofi, sizeof(FILE_END_OF_FILE_INFO), FileEndOfFileInformation);
if (!NT_SUCCESS(Status))
throw ntstatus_error(Status);
ded.FileHandle = source;
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);
if (h != INVALID_HANDLE_VALUE) {
do {
wstring sn;
ULONG streambufsize = 0;
vector<char> streambuf;
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") {
win_handle stream;
uint8_t* data = nullptr;
auto stream_size = (uint16_t)fsi->StreamSize.QuadPart;
if (fsd.StreamSize.QuadPart > 0) {
if (stream_size > 0) {
wstring fn2;
uint16_t stream_size = (uint16_t)fsd.StreamSize.QuadPart;
fn2 = srcfn;
fn2 += sn;
@@ -1542,7 +1573,7 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
}
if (data) {
if (!WriteFile(stream, data, (uint32_t)fsd.StreamSize.QuadPart, &bytesret, nullptr)) {
if (!WriteFile(stream, data, stream_size, &bytesret, nullptr)) {
free(data);
throw last_error(GetLastError());
}
@@ -1550,7 +1581,13 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
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;
while (xa2->valuelen > 0) {
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)) {
free(xa);
throw ntstatus_error(Status);
@@ -1598,7 +1635,9 @@ static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const ws
FILE_DISPOSITION_INFO fdi;
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;
}