* You should have received a copy of the GNU Lesser General Public Licence
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
-#ifndef __REACTOS__
-#define UNICODE
-#endif
#include "shellext.h"
#ifndef __REACTOS__
#include <windows.h>
#undef DeleteFile
#endif
#include <wincodec.h>
-#include <string>
#include <sstream>
+#include <iostream>
#define NO_SHLWAPI_STRFCNS
#include <shlwapi.h>
USHORT Reserved;
} reparse_header;
+static void path_remove_file(wstring& path);
+
// FIXME - don't assume subvol's top inode is 0x100
HRESULT __stdcall BtrfsContextMenu::QueryInterface(REFIID riid, void **ppObj) {
return S_OK;
}
- *ppObj = NULL;
+ *ppObj = nullptr;
return E_NOINTERFACE;
}
HRESULT __stdcall BtrfsContextMenu::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgID) {
- HANDLE h;
IO_STATUS_BLOCK iosb;
btrfs_get_file_ids bgfi;
NTSTATUS Status;
if (!pidlFolder) {
- FORMATETC format = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ FORMATETC format = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
UINT num_files, i;
WCHAR fn[MAX_PATH];
HDROP hdrop;
if (FAILED(pdtobj->GetData(&format, &stgm)))
return E_INVALIDARG;
- stgm_set = TRUE;
+ stgm_set = true;
hdrop = (HDROP)GlobalLock(stgm.hGlobal);
if (!hdrop) {
ReleaseStgMedium(&stgm);
- stgm_set = FALSE;
+ stgm_set = false;
return E_INVALIDARG;
}
- num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, NULL, 0);
+ num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, nullptr, 0);
for (i = 0; i < num_files; i++) {
if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
- h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ win_handle h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (h != INVALID_HANDLE_VALUE) {
- Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_FILE_IDS, NULL, 0, &bgfi, sizeof(btrfs_get_file_ids));
+ Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_FILE_IDS, nullptr, 0, &bgfi, sizeof(btrfs_get_file_ids));
if (NT_SUCCESS(Status) && bgfi.inode == 0x100 && !bgfi.top) {
- WCHAR parpath[MAX_PATH];
- HANDLE h2;
+ wstring parpath;
- StringCchCopyW(parpath, sizeof(parpath) / sizeof(WCHAR), fn);
+ {
+ win_handle h2;
- PathRemoveFileSpecW(parpath);
+ parpath = fn;
+ path_remove_file(parpath);
- h2 = CreateFileW(parpath, FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ h2 = CreateFileW(parpath.c_str(), FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
- if (h2 != INVALID_HANDLE_VALUE)
- allow_snapshot = TRUE;
-
- CloseHandle(h2);
+ if (h2 != INVALID_HANDLE_VALUE)
+ allow_snapshot = true;
+ }
- ignore = FALSE;
- bg = FALSE;
+ ignore = false;
+ bg = false;
- CloseHandle(h);
GlobalUnlock(hdrop);
return S_OK;
}
-
- CloseHandle(h);
}
}
}
return S_OK;
}
- if (!SHGetPathFromIDListW(pidlFolder, path))
- return E_FAIL;
+ {
+ WCHAR pathbuf[MAX_PATH];
- // check we have permissions to create new subdirectory
+ if (!SHGetPathFromIDListW(pidlFolder, pathbuf))
+ return E_FAIL;
- h = CreateFileW(path, FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ path = pathbuf;
+ }
- if (h == INVALID_HANDLE_VALUE)
- return E_FAIL;
+ {
+ // check we have permissions to create new subdirectory
- // check is Btrfs volume
+ win_handle h = CreateFileW(path.c_str(), FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
- Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_FILE_IDS, NULL, 0, &bgfi, sizeof(btrfs_get_file_ids));
+ if (h == INVALID_HANDLE_VALUE)
+ return E_FAIL;
- if (!NT_SUCCESS(Status)) {
- CloseHandle(h);
- return E_FAIL;
- }
+ // check is Btrfs volume
+
+ Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_FILE_IDS, nullptr, 0, &bgfi, sizeof(btrfs_get_file_ids));
- CloseHandle(h);
+ if (!NT_SUCCESS(Status))
+ return E_FAIL;
+ }
- ignore = FALSE;
- bg = TRUE;
+ ignore = false;
+ bg = true;
return S_OK;
}
-static BOOL get_volume_path_parent(const WCHAR* fn, WCHAR* volpath, ULONG volpathlen) {
+static bool get_volume_path_parent(const WCHAR* fn, WCHAR* volpath, ULONG volpathlen) {
WCHAR *f, *p;
- BOOL b;
+ bool b;
f = PathFindFileNameW(fn);
return b;
}
-static BOOL show_reflink_paste(WCHAR* path) {
+static bool show_reflink_paste(const wstring& path) {
HDROP hdrop;
HANDLE lh;
ULONG num_files;
WCHAR fn[MAX_PATH], volpath1[255], volpath2[255];
if (!IsClipboardFormatAvailable(CF_HDROP))
- return FALSE;
+ return false;
- if (!GetVolumePathNameW(path, volpath1, sizeof(volpath1) / sizeof(WCHAR)))
- return FALSE;
+ if (!GetVolumePathNameW(path.c_str(), volpath1, sizeof(volpath1) / sizeof(WCHAR)))
+ return false;
- if (!OpenClipboard(NULL))
- return FALSE;
+ if (!OpenClipboard(nullptr))
+ return false;
hdrop = (HDROP)GetClipboardData(CF_HDROP);
if (!hdrop) {
CloseClipboard();
- return FALSE;
+ return false;
}
lh = GlobalLock(hdrop);
if (!lh) {
CloseClipboard();
- return FALSE;
+ return false;
}
- num_files = DragQueryFileW(hdrop, 0xFFFFFFFF, NULL, 0);
+ num_files = DragQueryFileW(hdrop, 0xFFFFFFFF, nullptr, 0);
if (num_files == 0) {
GlobalUnlock(lh);
CloseClipboard();
- return FALSE;
+ return false;
}
if (!DragQueryFileW(hdrop, 0, fn, sizeof(fn) / sizeof(WCHAR))) {
GlobalUnlock(lh);
CloseClipboard();
- return FALSE;
+ return false;
}
if (!get_volume_path_parent(fn, volpath2, sizeof(volpath2) / sizeof(WCHAR))) {
GlobalUnlock(lh);
CloseClipboard();
- return FALSE;
+ return false;
}
GlobalUnlock(lh);
BITMAPINFO bmi;
HDC hdcUsed;
- *phBmp = NULL;
+ *phBmp = nullptr;
InitBitmapInfo(&bmi, sizeof(bmi), psize->cx, psize->cy, 32);
- hdcUsed = hdc ? hdc : GetDC(NULL);
+ hdcUsed = hdc ? hdc : GetDC(nullptr);
if (hdcUsed) {
- *phBmp = CreateDIBSection(hdcUsed, &bmi, DIB_RGB_COLORS, ppvBits, NULL, 0);
+ *phBmp = CreateDIBSection(hdcUsed, &bmi, DIB_RGB_COLORS, ppvBits, nullptr, 0);
if (hdc != hdcUsed)
- ReleaseDC(NULL, hdcUsed);
+ ReleaseDC(nullptr, hdcUsed);
}
return !*phBmp ? E_OUTOFMEMORY : S_OK;
}
void BtrfsContextMenu::get_uac_icon() {
- IWICImagingFactory* factory = NULL;
+ IWICImagingFactory* factory = nullptr;
IWICBitmap* bitmap;
HRESULT hr;
#ifdef __REACTOS__
- hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (void **)&factory);
+ hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (void **)&factory);
#else
- hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory));
+ hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory));
#endif
if (SUCCEEDED(hr)) {
sz.cx = (int)cx;
sz.cy = -(int)cy;
- hr = Create32BitHBITMAP(NULL, &sz, (void**)&buf, &uacicon);
+ 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(NULL, stride, buflen, buf);
+ bitmap->CopyPixels(nullptr, stride, buflen, buf);
}
}
}
HRESULT __stdcall BtrfsContextMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) {
- WCHAR str[256];
+ wstring str;
ULONG entries = 0;
if (ignore)
if (!bg) {
if (allow_snapshot) {
- if (LoadStringW(module, IDS_CREATE_SNAPSHOT, str, sizeof(str) / sizeof(WCHAR)) == 0)
+ if (load_string(module, IDS_CREATE_SNAPSHOT, str) == 0)
return E_FAIL;
- if (!InsertMenuW(hmenu, indexMenu, MF_BYPOSITION, idCmdFirst, str))
+ if (!InsertMenuW(hmenu, indexMenu, MF_BYPOSITION, idCmdFirst, str.c_str()))
return E_FAIL;
entries = 1;
if (idCmdFirst + entries <= idCmdLast) {
MENUITEMINFOW mii;
- if (LoadStringW(module, IDS_SEND_SUBVOL, str, sizeof(str) / sizeof(WCHAR)) == 0)
+ if (load_string(module, IDS_SEND_SUBVOL, str) == 0)
return E_FAIL;
if (!uacicon)
memset(&mii, 0, sizeof(MENUITEMINFOW));
mii.cbSize = sizeof(MENUITEMINFOW);
mii.fMask = MIIM_STRING | MIIM_ID | MIIM_BITMAP;
- mii.dwTypeData = str;
+ mii.dwTypeData = (WCHAR*)str.c_str();
mii.wID = idCmdFirst + entries;
mii.hbmpItem = uacicon;
- if (!InsertMenuItemW(hmenu, indexMenu + entries, TRUE, &mii))
+ if (!InsertMenuItemW(hmenu, indexMenu + entries, true, &mii))
return E_FAIL;
entries++;
}
} else {
- if (LoadStringW(module, IDS_NEW_SUBVOL, str, sizeof(str) / sizeof(WCHAR)) == 0)
+ if (load_string(module, IDS_NEW_SUBVOL, str) == 0)
return E_FAIL;
- if (!InsertMenuW(hmenu, indexMenu, MF_BYPOSITION, idCmdFirst, str))
+ if (!InsertMenuW(hmenu, indexMenu, MF_BYPOSITION, idCmdFirst, str.c_str()))
return E_FAIL;
entries = 1;
if (idCmdFirst + 1 <= idCmdLast) {
MENUITEMINFOW mii;
- if (LoadStringW(module, IDS_RECV_SUBVOL, str, sizeof(str) / sizeof(WCHAR)) == 0)
+ if (load_string(module, IDS_RECV_SUBVOL, str) == 0)
return E_FAIL;
if (!uacicon)
memset(&mii, 0, sizeof(MENUITEMINFOW));
mii.cbSize = sizeof(MENUITEMINFOW);
mii.fMask = MIIM_STRING | MIIM_ID | MIIM_BITMAP;
- mii.dwTypeData = str;
+ mii.dwTypeData = (WCHAR*)str.c_str();
mii.wID = idCmdFirst + 1;
mii.hbmpItem = uacicon;
- if (!InsertMenuItemW(hmenu, indexMenu + 1, TRUE, &mii))
+ if (!InsertMenuItemW(hmenu, indexMenu + 1, true, &mii))
return E_FAIL;
entries++;
}
if (idCmdFirst + 2 <= idCmdLast && show_reflink_paste(path)) {
- if (LoadStringW(module, IDS_REFLINK_PASTE, str, sizeof(str) / sizeof(WCHAR)) == 0)
+ if (load_string(module, IDS_REFLINK_PASTE, str) == 0)
return E_FAIL;
- if (!InsertMenuW(hmenu, indexMenu + 2, MF_BYPOSITION, idCmdFirst + 2, str))
+ if (!InsertMenuW(hmenu, indexMenu + 2, MF_BYPOSITION, idCmdFirst + 2, str.c_str()))
return E_FAIL;
entries++;
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, entries);
}
-static void create_snapshot(HWND hwnd, WCHAR* fn) {
- HANDLE h;
+static void path_remove_file(wstring& path) {
+ size_t bs = path.rfind(L"\\");
+
+ if (bs == string::npos)
+ return;
+
+ if (bs == path.find(L"\\")) { // only one backslash
+ path = path.substr(0, bs + 1);
+ return;
+ }
+
+ path = path.substr(0, bs);
+}
+
+static void path_strip_path(wstring& path) {
+ size_t bs = path.rfind(L"\\");
+
+ if (bs == string::npos) {
+ path = L"";
+ return;
+ }
+
+ path = path.substr(bs + 1);
+}
+
+static void create_snapshot(HWND hwnd, const wstring& fn) {
+ win_handle h;
NTSTATUS Status;
IO_STATUS_BLOCK iosb;
btrfs_get_file_ids bgfi;
- h = CreateFileW(fn, FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ h = CreateFileW(fn.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (h != INVALID_HANDLE_VALUE) {
- Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_FILE_IDS, NULL, 0, &bgfi, sizeof(btrfs_get_file_ids));
+ Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_FILE_IDS, nullptr, 0, &bgfi, sizeof(btrfs_get_file_ids));
if (NT_SUCCESS(Status) && bgfi.inode == 0x100 && !bgfi.top) {
- WCHAR parpath[MAX_PATH], subvolname[MAX_PATH], templ[MAX_PATH], name[MAX_PATH], searchpath[MAX_PATH];
- HANDLE h2, fff;
- btrfs_create_snapshot* bcs;
- ULONG namelen, pathend;
+ wstring subvolname, parpath, searchpath, temp1, name, nameorig;
+ win_handle h2;
WIN32_FIND_DATAW wfd;
SYSTEMTIME time;
- StringCchCopyW(parpath, sizeof(parpath) / sizeof(WCHAR), fn);
- PathRemoveFileSpecW(parpath);
+ parpath = fn;
+ path_remove_file(parpath);
- StringCchCopyW(subvolname, sizeof(subvolname) / sizeof(WCHAR), fn);
- PathStripPathW(subvolname);
+ subvolname = fn;
+ path_strip_path(subvolname);
- h2 = CreateFileW(parpath, FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ h2 = CreateFileW(parpath.c_str(), FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
- if (h2 == INVALID_HANDLE_VALUE) {
- ShowError(hwnd, GetLastError());
- CloseHandle(h);
- return;
- }
+ if (h2 == INVALID_HANDLE_VALUE)
+ throw last_error(GetLastError());
- if (!LoadStringW(module, IDS_SNAPSHOT_FILENAME, templ, MAX_PATH)) {
- ShowError(hwnd, GetLastError());
- CloseHandle(h);
- CloseHandle(h2);
- return;
- }
+ if (!load_string(module, IDS_SNAPSHOT_FILENAME, temp1))
+ throw last_error(GetLastError());
GetLocalTime(&time);
- if (StringCchPrintfW(name, sizeof(name) / sizeof(WCHAR), templ, subvolname, time.wYear, time.wMonth, time.wDay) == STRSAFE_E_INSUFFICIENT_BUFFER) {
- MessageBoxW(hwnd, L"Filename too long.\n", L"Error", MB_ICONERROR);
- CloseHandle(h);
- CloseHandle(h2);
- return;
- }
-
- StringCchCopyW(searchpath, sizeof(searchpath) / sizeof(WCHAR), parpath);
- StringCchCatW(searchpath, sizeof(searchpath) / sizeof(WCHAR), L"\\");
- pathend = wcslen(searchpath);
+ wstring_sprintf(name, temp1, subvolname.c_str(), time.wYear, time.wMonth, time.wDay);
+ nameorig = name;
- StringCchCatW(searchpath, sizeof(searchpath) / sizeof(WCHAR), name);
+ searchpath = parpath + L"\\" + name;
- fff = FindFirstFileW(searchpath, &wfd);
+ fff_handle fff = FindFirstFileW(searchpath.c_str(), &wfd);
if (fff != INVALID_HANDLE_VALUE) {
- ULONG i = wcslen(searchpath), num = 2;
+ ULONG num = 2;
do {
- FindClose(fff);
-
- searchpath[i] = 0;
- if (StringCchPrintfW(searchpath, sizeof(searchpath) / sizeof(WCHAR), L"%s (%u)", searchpath, num) == STRSAFE_E_INSUFFICIENT_BUFFER) {
- MessageBoxW(hwnd, L"Filename too long.\n", L"Error", MB_ICONERROR);
- CloseHandle(h);
- CloseHandle(h2);
- return;
+#ifndef __REACTOS__
+ name = nameorig + L" (" + to_wstring(num) + L")";
+#else
+ {
+ WCHAR buffer[32];
+
+ swprintf(buffer, L"%d", num);
+ name = nameorig + L" (" + buffer + L")";
}
+#endif
+ searchpath = parpath + L"\\" + name;
- fff = FindFirstFileW(searchpath, &wfd);
+ fff = FindFirstFileW(searchpath.c_str(), &wfd);
num++;
} while (fff != INVALID_HANDLE_VALUE);
}
- namelen = wcslen(&searchpath[pathend]) * sizeof(WCHAR);
+ size_t namelen = name.length() * sizeof(WCHAR);
- bcs = (btrfs_create_snapshot*)malloc(sizeof(btrfs_create_snapshot) - 1 + namelen);
- bcs->readonly = FALSE;
- bcs->posix = FALSE;
+ auto bcs = (btrfs_create_snapshot*)malloc(sizeof(btrfs_create_snapshot) - 1 + namelen);
+ bcs->readonly = false;
+ bcs->posix = false;
bcs->subvol = h;
- bcs->namelen = namelen;
- memcpy(bcs->name, &searchpath[pathend], namelen);
+ bcs->namelen = (uint16_t)namelen;
+ memcpy(bcs->name, name.c_str(), namelen);
- Status = NtFsControlFile(h2, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, sizeof(btrfs_create_snapshot) - 1 + namelen, NULL, 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))
- ShowNtStatusError(hwnd, Status);
-
- CloseHandle(h2);
+ throw ntstatus_error(Status);
}
-
- CloseHandle(h);
} else
- ShowError(hwnd, GetLastError());
+ throw last_error(GetLastError());
}
-static UINT64 __inline sector_align(UINT64 n, UINT64 a) {
+static uint64_t __inline sector_align(uint64_t n, uint64_t a) {
if (n & (a - 1))
n = (n + a) & ~(a - 1);
return n;
}
-BOOL BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir) {
- HANDLE source, dest;
+void BtrfsContextMenu::reflink_copy(HWND hwnd, const WCHAR* fn, const WCHAR* dir) {
+ win_handle source, dest;
WCHAR* name, volpath1[255], volpath2[255];
- std::wstring dirw, newpath;
- BOOL ret = FALSE;
+ wstring dirw, newpath;
FILE_BASIC_INFO fbi;
FILETIME atime, mtime;
btrfs_inode_info bii;
newpath = dirw;
newpath += name;
- if (!get_volume_path_parent(fn, volpath1, sizeof(volpath1) / sizeof(WCHAR))) {
- ShowError(hwnd, GetLastError());
- return FALSE;
- }
+ if (!get_volume_path_parent(fn, volpath1, sizeof(volpath1) / sizeof(WCHAR)))
+ throw last_error(GetLastError());
- if (!GetVolumePathNameW(dir, volpath2, sizeof(volpath2) / sizeof(WCHAR))) {
- ShowError(hwnd, GetLastError());
- return FALSE;
- }
+ if (!GetVolumePathNameW(dir, volpath2, sizeof(volpath2) / sizeof(WCHAR)))
+ throw last_error(GetLastError());
if (wcscmp(volpath1, volpath2)) // different filesystems
- return FALSE;
+ throw string_error(IDS_CANT_REFLINK_DIFFERENT_FS);
- source = CreateFileW(fn, GENERIC_READ | FILE_TRAVERSE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT, NULL);
- if (source == INVALID_HANDLE_VALUE) {
- ShowError(hwnd, GetLastError());
- return FALSE;
- }
+ source = CreateFileW(fn, GENERIC_READ | FILE_TRAVERSE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT, nullptr);
+ if (source == INVALID_HANDLE_VALUE)
+ throw last_error(GetLastError());
- Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_INODE_INFO, NULL, 0, &bii, sizeof(btrfs_inode_info));
- if (!NT_SUCCESS(Status)) {
- ShowNtStatusError(hwnd, Status);
- CloseHandle(source);
- return FALSE;
- }
+ Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_INODE_INFO, nullptr, 0, &bii, sizeof(btrfs_inode_info));
+ if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
// if subvol, do snapshot instead
if (bii.inode == SUBVOL_ROOT_INODE) {
btrfs_create_snapshot* bcs;
- HANDLE dirh, fff;
- std::wstring destname, search;
+ win_handle dirh;
+ wstring destname, search;
WIN32_FIND_DATAW wfd;
int num = 2;
- dirh = CreateFileW(dir, FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (dirh == INVALID_HANDLE_VALUE) {
- ShowError(hwnd, GetLastError());
- CloseHandle(source);
- return FALSE;
- }
+ dirh = CreateFileW(dir, FILE_ADD_SUBDIRECTORY, 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());
search = dirw;
search += name;
destname = name;
- fff = FindFirstFileW(search.c_str(), &wfd);
+ fff_handle fff = FindFirstFileW(search.c_str(), &wfd);
if (fff != INVALID_HANDLE_VALUE) {
do {
- std::wstringstream ss;
-
- FindClose(fff);
+ wstringstream ss;
ss << name;
ss << L" (";
bcs = (btrfs_create_snapshot*)malloc(sizeof(btrfs_create_snapshot) - sizeof(WCHAR) + (destname.length() * sizeof(WCHAR)));
bcs->subvol = source;
- bcs->namelen = destname.length() * sizeof(WCHAR);
+ bcs->namelen = (uint16_t)(destname.length() * sizeof(WCHAR));
memcpy(bcs->name, destname.c_str(), destname.length() * sizeof(WCHAR));
- Status = NtFsControlFile(dirh, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, sizeof(btrfs_create_snapshot) - sizeof(WCHAR) + bcs->namelen, NULL, 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);
- if (!NT_SUCCESS(Status)) {
- ShowNtStatusError(hwnd, Status);
- CloseHandle(source);
- CloseHandle(dirh);
- return FALSE;
- }
+ if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
- CloseHandle(source);
- CloseHandle(dirh);
- return TRUE;
+ return;
}
- if (!GetFileInformationByHandleEx(source, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO))) {
- ShowError(hwnd, GetLastError());
- CloseHandle(source);
- return FALSE;
- }
+ 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) {
- HANDLE dirh;
- ULONG bmnsize;
+ win_handle dirh;
btrfs_mknod* bmn;
- dirh = CreateFileW(dir, FILE_ADD_FILE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (dirh == INVALID_HANDLE_VALUE) {
- ShowError(hwnd, GetLastError());
- CloseHandle(source);
- return FALSE;
- }
+ 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;
bmn->type = bii.type;
bmn->st_rdev = bii.st_rdev;
- bmn->namelen = wcslen(name) * sizeof(WCHAR);
+ bmn->namelen = (uint16_t)(wcslen(name) * sizeof(WCHAR));
memcpy(bmn->name, name, bmn->namelen);
- Status = NtFsControlFile(dirh, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_MKNOD, bmn, bmnsize, NULL, 0);
+ Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, (ULONG)bmnsize, nullptr, 0);
if (!NT_SUCCESS(Status)) {
- ShowNtStatusError(hwnd, Status);
- CloseHandle(dirh);
- CloseHandle(source);
free(bmn);
- return FALSE;
+ throw ntstatus_error(Status);
}
- CloseHandle(dirh);
free(bmn);
- dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, 0, NULL);
+ dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
} else if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- if (CreateDirectoryExW(fn, newpath.c_str(), NULL))
+ if (CreateDirectoryExW(fn, newpath.c_str(), nullptr))
dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
else
dest = INVALID_HANDLE_VALUE;
} else
- dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW, 0, source);
+ dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, source);
if (dest == INVALID_HANDLE_VALUE) {
int num = 2;
- if (GetLastError() != ERROR_FILE_EXISTS && GetLastError() != ERROR_ALREADY_EXISTS && wcscmp(fn, newpath.c_str())) {
- ShowError(hwnd, GetLastError());
- CloseHandle(source);
- return FALSE;
- }
+ if (GetLastError() != ERROR_FILE_EXISTS && GetLastError() != ERROR_ALREADY_EXISTS && wcscmp(fn, newpath.c_str()))
+ throw last_error(GetLastError());
do {
WCHAR* ext;
- std::wstringstream ss;
+ wstringstream ss;
ext = PathFindExtensionW(fn);
ss << num;
ss << L")";
} else {
- std::wstring namew = name;
+ wstring namew = name;
ss << namew.substr(0, ext - name);
ss << L" (";
newpath = ss.str();
if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- if (CreateDirectoryExW(fn, newpath.c_str(), NULL))
- dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (CreateDirectoryExW(fn, newpath.c_str(), nullptr))
+ dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
else
dest = INVALID_HANDLE_VALUE;
} else
- dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW, 0, source);
+ dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, source);
if (dest == INVALID_HANDLE_VALUE) {
- if (GetLastError() != ERROR_FILE_EXISTS && GetLastError() != ERROR_ALREADY_EXISTS) {
- ShowError(hwnd, GetLastError());
- CloseHandle(source);
- return FALSE;
- }
+ if (GetLastError() != ERROR_FILE_EXISTS && GetLastError() != ERROR_ALREADY_EXISTS)
+ throw last_error(GetLastError());
num++;
} else
break;
- } while (TRUE);
+ } while (true);
}
- memset(&bsii, 0, sizeof(btrfs_set_inode_info));
-
- bsii.flags_changed = TRUE;
- bsii.flags = bii.flags;
-
- if (bii.flags & BTRFS_INODE_COMPRESS) {
- bsii.compression_type_changed = TRUE;
- bsii.compression_type = bii.compression_type;
- }
+ try {
+ memset(&bsii, 0, sizeof(btrfs_set_inode_info));
- Status = NtFsControlFile(dest, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), NULL, 0);
- if (!NT_SUCCESS(Status)) {
- ShowNtStatusError(hwnd, Status);
- goto end;
- }
+ bsii.flags_changed = true;
+ bsii.flags = bii.flags;
- if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- if (!(fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
- HANDLE h;
- WIN32_FIND_DATAW fff;
- std::wstring qs;
+ if (bii.flags & BTRFS_INODE_COMPRESS) {
+ bsii.compression_type_changed = true;
+ bsii.compression_type = bii.compression_type;
+ }
- qs = fn;
- qs += L"\\*";
+ Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), nullptr, 0);
+ if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
- h = FindFirstFileW(qs.c_str(), &fff);
- if (h != INVALID_HANDLE_VALUE) {
- do {
- std::wstring fn2;
+ if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ if (!(fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ fff_handle h;
+ WIN32_FIND_DATAW fff;
+ wstring qs;
- if (fff.cFileName[0] == '.' && (fff.cFileName[1] == 0 || (fff.cFileName[1] == '.' && fff.cFileName[2] == 0)))
- continue;
+ qs = fn;
+ qs += L"\\*";
- fn2 = fn;
- fn2 += L"\\";
- fn2 += fff.cFileName;
+ h = FindFirstFileW(qs.c_str(), &fff);
+ if (h != INVALID_HANDLE_VALUE) {
+ do {
+ wstring fn2;
- if (!reflink_copy(hwnd, fn2.c_str(), newpath.c_str()))
- goto end;
- } while (FindNextFileW(h, &fff));
+ if (fff.cFileName[0] == '.' && (fff.cFileName[1] == 0 || (fff.cFileName[1] == '.' && fff.cFileName[2] == 0)))
+ continue;
- FindClose(h);
- }
- }
+ fn2 = fn;
+ fn2 += L"\\";
+ fn2 += fff.cFileName;
- // CreateDirectoryExW also copies streams, no need to do it here
- } else {
- HANDLE h;
- WIN32_FIND_STREAM_DATA fsd;
-
- if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- reparse_header rh;
- ULONG rplen;
- UINT8* rp;
-
- if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, NULL, 0, &rh, sizeof(reparse_header), &bytesret, NULL)) {
- if (GetLastError() != ERROR_MORE_DATA) {
- ShowError(hwnd, GetLastError());
- goto end;
+ reflink_copy(hwnd, fn2.c_str(), newpath.c_str());
+ } while (FindNextFileW(h, &fff));
}
}
- rplen = sizeof(reparse_header) + rh.ReparseDataLength;
- rp = (UINT8*)malloc(rplen);
+ // CreateDirectoryExW also copies streams, no need to do it here
+ } else {
+ if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ reparse_header rh;
+ uint8_t* rp;
- if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, NULL, 0, rp, rplen, &bytesret, NULL)) {
- ShowError(hwnd, GetLastError());
- goto end;
- }
+ if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, &rh, sizeof(reparse_header), &bytesret, nullptr)) {
+ if (GetLastError() != ERROR_MORE_DATA)
+ throw last_error(GetLastError());
+ }
- if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, rplen, NULL, 0, &bytesret, NULL)) {
- ShowError(hwnd, GetLastError());
- goto end;
- }
+ size_t rplen = sizeof(reparse_header) + rh.ReparseDataLength;
+ rp = (uint8_t*)malloc(rplen);
- free(rp);
- } else {
- FILE_STANDARD_INFO fsi;
- FILE_END_OF_FILE_INFO feofi;
- FSCTL_GET_INTEGRITY_INFORMATION_BUFFER fgiib;
- FSCTL_SET_INTEGRITY_INFORMATION_BUFFER fsiib;
- DUPLICATE_EXTENTS_DATA ded;
- UINT64 offset, alloc_size;
- ULONG maxdup;
-
- if (!GetFileInformationByHandleEx(source, FileStandardInfo, &fsi, sizeof(FILE_STANDARD_INFO))) {
- ShowError(hwnd, GetLastError());
- goto end;
- }
+ if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, rp, (ULONG)rplen, &bytesret, nullptr))
+ throw last_error(GetLastError());
- if (!DeviceIoControl(source, FSCTL_GET_INTEGRITY_INFORMATION, NULL, 0, &fgiib, sizeof(FSCTL_GET_INTEGRITY_INFORMATION_BUFFER), &bytesret, NULL)) {
- ShowError(hwnd, GetLastError());
- goto end;
- }
+ if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, (ULONG)rplen, nullptr, 0, &bytesret, nullptr))
+ throw last_error(GetLastError());
- if (fbi.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) {
- if (!DeviceIoControl(dest, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &bytesret, NULL)) {
- ShowError(hwnd, GetLastError());
- goto end;
+ free(rp);
+ } else {
+ FILE_STANDARD_INFO fsi;
+ FILE_END_OF_FILE_INFO feofi;
+ FSCTL_GET_INTEGRITY_INFORMATION_BUFFER fgiib;
+ FSCTL_SET_INTEGRITY_INFORMATION_BUFFER fsiib;
+ DUPLICATE_EXTENTS_DATA ded;
+ uint64_t offset, alloc_size;
+ ULONG maxdup;
+
+ 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());
+
+ if (fbi.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) {
+ if (!DeviceIoControl(dest, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &bytesret, nullptr))
+ throw last_error(GetLastError());
}
- }
- fsiib.ChecksumAlgorithm = fgiib.ChecksumAlgorithm;
- fsiib.Reserved = 0;
- fsiib.Flags = fgiib.Flags;
- if (!DeviceIoControl(dest, FSCTL_SET_INTEGRITY_INFORMATION, &fsiib, sizeof(FSCTL_SET_INTEGRITY_INFORMATION_BUFFER), NULL, 0, &bytesret, NULL)) {
- ShowError(hwnd, GetLastError());
- goto end;
- }
+ fsiib.ChecksumAlgorithm = fgiib.ChecksumAlgorithm;
+ fsiib.Reserved = 0;
+ fsiib.Flags = fgiib.Flags;
+ if (!DeviceIoControl(dest, FSCTL_SET_INTEGRITY_INFORMATION, &fsiib, sizeof(FSCTL_SET_INTEGRITY_INFORMATION_BUFFER), nullptr, 0, &bytesret, nullptr))
+ throw last_error(GetLastError());
- feofi.EndOfFile = fsi.EndOfFile;
- if (!SetFileInformationByHandle(dest, FileEndOfFileInfo, &feofi, sizeof(FILE_END_OF_FILE_INFO))){
- ShowError(hwnd, GetLastError());
- goto end;
- }
+ feofi.EndOfFile = fsi.EndOfFile;
+ 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;
+ ded.FileHandle = source;
+ maxdup = 0xffffffff - fgiib.ClusterSizeInBytes + 1;
- alloc_size = sector_align(fsi.EndOfFile.QuadPart, fgiib.ClusterSizeInBytes);
+ alloc_size = sector_align(fsi.EndOfFile.QuadPart, fgiib.ClusterSizeInBytes);
- offset = 0;
- while (offset < alloc_size) {
- ded.SourceFileOffset.QuadPart = ded.TargetFileOffset.QuadPart = offset;
- ded.ByteCount.QuadPart = maxdup < (alloc_size - offset) ? maxdup : (alloc_size - offset);
- if (!DeviceIoControl(dest, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &ded, sizeof(DUPLICATE_EXTENTS_DATA), NULL, 0, &bytesret, NULL)) {
- ShowError(hwnd, GetLastError());
- goto end;
- }
+ offset = 0;
+ while (offset < alloc_size) {
+ ded.SourceFileOffset.QuadPart = ded.TargetFileOffset.QuadPart = offset;
+ ded.ByteCount.QuadPart = maxdup < (alloc_size - offset) ? maxdup : (alloc_size - offset);
+ if (!DeviceIoControl(dest, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &ded, sizeof(DUPLICATE_EXTENTS_DATA), nullptr, 0, &bytesret, nullptr))
+ throw last_error(GetLastError());
- offset += ded.ByteCount.QuadPart;
+ offset += ded.ByteCount.QuadPart;
+ }
}
- }
- h = FindFirstStreamW(fn, FindStreamInfoStandard, &fsd, 0);
- if (h != INVALID_HANDLE_VALUE) {
+ ULONG streambufsize = 0;
+ vector<char> streambuf;
+
do {
- std::wstring sn;
+ streambufsize += 0x1000;
+ streambuf.resize(streambufsize);
- sn = fsd.cStreamName;
+ memset(streambuf.data(), 0, streambufsize);
- if (sn != L"::$DATA" && sn.length() > 6 && sn.substr(sn.length() - 6, 6) == L":$DATA") {
- HANDLE stream;
- UINT8* data = NULL;
+ Status = NtQueryInformationFile(source, &iosb, streambuf.data(), streambufsize, FileStreamInformation);
+ } while (Status == STATUS_BUFFER_OVERFLOW);
- if (fsd.StreamSize.QuadPart > 0) {
- std::wstring fn2;
+ if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
- fn2 = fn;
- fn2 += sn;
+ auto fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(streambuf.data());
- stream = CreateFileW(fn2.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+ while (true) {
+ if (fsi->StreamNameLength > 0) {
+ wstring sn = wstring(fsi->StreamName, fsi->StreamNameLength / sizeof(WCHAR));
- if (stream == INVALID_HANDLE_VALUE) {
- ShowError(hwnd, GetLastError());
- goto end;
- }
+ 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;
- // We can get away with this because our streams are guaranteed to be below 64 KB -
- // don't do this on NTFS!
- data = (UINT8*)malloc(fsd.StreamSize.QuadPart);
- if (!ReadFile(stream, data, fsd.StreamSize.QuadPart, &bytesret, NULL)) {
- ShowError(hwnd, GetLastError());
- free(data);
- CloseHandle(stream);
- goto end;
- }
+ if (stream_size > 0) {
+ wstring fn2;
- CloseHandle(stream);
- }
+ fn2 = fn;
+ fn2 += sn;
- stream = CreateFileW((newpath + sn).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW, 0, NULL);
+ stream = CreateFileW(fn2.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
- if (stream == INVALID_HANDLE_VALUE) {
- ShowError(hwnd, GetLastError());
+ if (stream == INVALID_HANDLE_VALUE)
+ throw last_error(GetLastError());
- if (data) free(data);
+ // We can get away with this because our streams are guaranteed to be below 64 KB -
+ // don't do this on NTFS!
+ data = (uint8_t*)malloc(stream_size);
- goto end;
- }
+ if (!ReadFile(stream, data, stream_size, &bytesret, nullptr)) {
+ free(data);
+ throw last_error(GetLastError());
+ }
+ }
- if (data) {
- if (!WriteFile(stream, data, fsd.StreamSize.QuadPart, &bytesret, NULL)) {
- ShowError(hwnd, GetLastError());
- free(data);
- CloseHandle(stream);
- goto end;
+ stream = CreateFileW((newpath + sn).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, nullptr);
+
+ if (stream == INVALID_HANDLE_VALUE) {
+ if (data) free(data);
+ throw last_error(GetLastError());
}
- free(data);
- }
+ if (data) {
+ if (!WriteFile(stream, data, stream_size, &bytesret, nullptr)) {
+ free(data);
+ throw last_error(GetLastError());
+ }
- CloseHandle(stream);
+ free(data);
+ }
+ }
}
- } while (FindNextStreamW(h, &fsd));
- FindClose(h);
+ if (fsi->NextEntryOffset == 0)
+ break;
+
+ fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(reinterpret_cast<char*>(fsi) + fsi->NextEntryOffset);
+ }
}
- }
- atime.dwLowDateTime = fbi.LastAccessTime.LowPart;
- atime.dwHighDateTime = fbi.LastAccessTime.HighPart;
- mtime.dwLowDateTime = fbi.LastWriteTime.LowPart;
- mtime.dwHighDateTime = fbi.LastWriteTime.HighPart;
- SetFileTime(dest, NULL, &atime, &mtime);
+ atime.dwLowDateTime = fbi.LastAccessTime.LowPart;
+ atime.dwHighDateTime = fbi.LastAccessTime.HighPart;
+ mtime.dwLowDateTime = fbi.LastWriteTime.LowPart;
+ mtime.dwHighDateTime = fbi.LastWriteTime.HighPart;
+ SetFileTime(dest, nullptr, &atime, &mtime);
- Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_XATTRS, NULL, 0, &bsxa, sizeof(btrfs_set_xattr));
+ Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_XATTRS, nullptr, 0, &bsxa, sizeof(btrfs_set_xattr));
- if (Status == STATUS_BUFFER_OVERFLOW || (NT_SUCCESS(Status) && bsxa.valuelen > 0)) {
- ULONG xalen = 0;
- btrfs_set_xattr *xa = NULL, *xa2;
+ if (Status == STATUS_BUFFER_OVERFLOW || (NT_SUCCESS(Status) && bsxa.valuelen > 0)) {
+ ULONG xalen = 0;
+ btrfs_set_xattr *xa = nullptr, *xa2;
- do {
- xalen += 1024;
+ do {
+ xalen += 1024;
- if (xa) free(xa);
- xa = (btrfs_set_xattr*)malloc(xalen);
+ if (xa) free(xa);
+ xa = (btrfs_set_xattr*)malloc(xalen);
- Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_XATTRS, NULL, 0, xa, xalen);
- } while (Status == STATUS_BUFFER_OVERFLOW);
+ Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_XATTRS, nullptr, 0, xa, xalen);
+ } while (Status == STATUS_BUFFER_OVERFLOW);
- if (!NT_SUCCESS(Status)) {
- free(xa);
- ShowNtStatusError(hwnd, Status);
- goto end;
- }
-
- xa2 = xa;
- while (xa2->valuelen > 0) {
- Status = NtFsControlFile(dest, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_XATTR, xa2,
- offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen, NULL, 0);
if (!NT_SUCCESS(Status)) {
free(xa);
- ShowNtStatusError(hwnd, Status);
- goto end;
+ throw ntstatus_error(Status);
}
- xa2 = (btrfs_set_xattr*)&xa2->data[xa2->namelen + xa2->valuelen];
- }
- free(xa);
- } else if (!NT_SUCCESS(Status)) {
- ShowNtStatusError(hwnd, Status);
- goto end;
- }
-
- ret = TRUE;
+ xa2 = xa;
+ while (xa2->valuelen > 0) {
+ Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, xa2,
+ (ULONG)(offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen), nullptr, 0);
+ if (!NT_SUCCESS(Status)) {
+ free(xa);
+ throw ntstatus_error(Status);
+ }
+ xa2 = (btrfs_set_xattr*)&xa2->data[xa2->namelen + xa2->valuelen];
+ }
-end:
- if (!ret) {
+ free(xa);
+ } else if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
+ } catch (...) {
FILE_DISPOSITION_INFO fdi;
- fdi.DeleteFile = TRUE;
- if (!SetFileInformationByHandle(dest, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO)))
- ShowError(hwnd, GetLastError());
- }
-
- CloseHandle(dest);
- CloseHandle(source);
+ fdi.DeleteFile = true;
+ Status = NtSetInformationFile(dest, &iosb, &fdi, sizeof(FILE_DISPOSITION_INFO), FileDispositionInformation);
+ if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
- return ret;
+ throw;
+ }
}
HRESULT __stdcall BtrfsContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO picia) {
LPCMINVOKECOMMANDINFOEX pici = (LPCMINVOKECOMMANDINFOEX)picia;
- if (ignore)
- return E_INVALIDARG;
+ try {
+ if (ignore)
+ return E_INVALIDARG;
- if (!bg) {
- if ((IS_INTRESOURCE(pici->lpVerb) && allow_snapshot && pici->lpVerb == 0) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, SNAPSHOT_VERBA))) {
- UINT num_files, i;
- WCHAR fn[MAX_PATH];
+ if (!bg) {
+ if ((IS_INTRESOURCE(pici->lpVerb) && allow_snapshot && pici->lpVerb == 0) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, SNAPSHOT_VERBA))) {
+ UINT num_files, i;
+ WCHAR fn[MAX_PATH];
- if (!stgm_set)
- return E_FAIL;
+ if (!stgm_set)
+ return E_FAIL;
- num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, NULL, 0);
+ num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, nullptr, 0);
- if (num_files == 0)
- return E_FAIL;
+ if (num_files == 0)
+ return E_FAIL;
- for (i = 0; i < num_files; i++) {
- if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
- create_snapshot(pici->hwnd, fn);
+ for (i = 0; i < num_files; i++) {
+ if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
+ create_snapshot(pici->hwnd, fn);
+ }
}
- }
- return S_OK;
- } else if ((IS_INTRESOURCE(pici->lpVerb) && ((allow_snapshot && (ULONG_PTR)pici->lpVerb == 1) || (!allow_snapshot && (ULONG_PTR)pici->lpVerb == 0))) ||
- (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, SEND_VERBA))) {
- UINT num_files, i;
- WCHAR dll[MAX_PATH], fn[MAX_PATH];
- std::wstring t;
- SHELLEXECUTEINFOW sei;
+ return S_OK;
+ } else if ((IS_INTRESOURCE(pici->lpVerb) && ((allow_snapshot && (ULONG_PTR)pici->lpVerb == 1) || (!allow_snapshot && (ULONG_PTR)pici->lpVerb == 0))) ||
+ (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, SEND_VERBA))) {
+ UINT num_files, i;
+ WCHAR dll[MAX_PATH], fn[MAX_PATH];
+ wstring t;
+ SHELLEXECUTEINFOW sei;
- GetModuleFileNameW(module, dll, sizeof(dll) / sizeof(WCHAR));
+ GetModuleFileNameW(module, dll, sizeof(dll) / sizeof(WCHAR));
- if (!stgm_set)
- return E_FAIL;
+ if (!stgm_set)
+ return E_FAIL;
- num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, NULL, 0);
+ num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, nullptr, 0);
- if (num_files == 0)
- return E_FAIL;
+ if (num_files == 0)
+ return E_FAIL;
- for (i = 0; i < num_files; i++) {
- if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
- t = L"\"";
- t += dll;
- t += L"\",SendSubvolGUI ";
- t += fn;
-
- RtlZeroMemory(&sei, sizeof(sei));
-
- sei.cbSize = sizeof(sei);
- sei.hwnd = pici->hwnd;
- 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)) {
- ShowError(pici->hwnd, GetLastError());
- return E_FAIL;
- }
+ for (i = 0; i < num_files; i++) {
+ if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
+ t = L"\"";
+ t += dll;
+ t += L"\",SendSubvolGUI ";
+ t += fn;
- WaitForSingleObject(sei.hProcess, INFINITE);
- CloseHandle(sei.hProcess);
- }
- }
+ RtlZeroMemory(&sei, sizeof(sei));
- return S_OK;
- }
- } else {
- if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 0) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, NEW_SUBVOL_VERBA))) {
- HANDLE h;
- IO_STATUS_BLOCK iosb;
- NTSTATUS Status;
- ULONG pathlen, searchpathlen, pathend, bcslen;
- WCHAR name[MAX_PATH], *searchpath;
- btrfs_create_subvol* bcs;
- HANDLE fff;
- WIN32_FIND_DATAW wfd;
+ sei.cbSize = sizeof(sei);
+ sei.hwnd = pici->hwnd;
+ sei.lpVerb = L"runas";
+ sei.lpFile = L"rundll32.exe";
+ sei.lpParameters = t.c_str();
+ sei.nShow = SW_SHOW;
+ sei.fMask = SEE_MASK_NOCLOSEPROCESS;
- if (!LoadStringW(module, IDS_NEW_SUBVOL_FILENAME, name, MAX_PATH)) {
- ShowError(pici->hwnd, GetLastError());
- return E_FAIL;
- }
+ if (!ShellExecuteExW(&sei))
+ throw last_error(GetLastError());
- h = CreateFileW(path, FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ WaitForSingleObject(sei.hProcess, INFINITE);
+ CloseHandle(sei.hProcess);
+ }
+ }
- if (h == INVALID_HANDLE_VALUE) {
- ShowError(pici->hwnd, GetLastError());
- return E_FAIL;
+ return S_OK;
}
+ } else {
+ if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 0) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, NEW_SUBVOL_VERBA))) {
+ win_handle h;
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS Status;
+ wstring name, nameorig, searchpath;
+ btrfs_create_subvol* bcs;
+ WIN32_FIND_DATAW wfd;
- pathlen = wcslen(path);
-
- searchpathlen = pathlen + wcslen(name) + 10;
- searchpath = (WCHAR*)malloc(searchpathlen * sizeof(WCHAR));
+ if (!load_string(module, IDS_NEW_SUBVOL_FILENAME, name))
+ throw last_error(GetLastError());
- StringCchCopyW(searchpath, searchpathlen, path);
- StringCchCatW(searchpath, searchpathlen, L"\\");
- pathend = wcslen(searchpath);
+ h = CreateFileW(path.c_str(), FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
- StringCchCatW(searchpath, searchpathlen, name);
+ if (h == INVALID_HANDLE_VALUE)
+ throw last_error(GetLastError());
- fff = FindFirstFileW(searchpath, &wfd);
+ searchpath = path + L"\\" + name;
+ nameorig = name;
- if (fff != INVALID_HANDLE_VALUE) {
- ULONG i = wcslen(searchpath), num = 2;
+ {
+ fff_handle fff = FindFirstFileW(searchpath.c_str(), &wfd);
- do {
- FindClose(fff);
+ if (fff != INVALID_HANDLE_VALUE) {
+ ULONG num = 2;
- searchpath[i] = 0;
- if (StringCchPrintfW(searchpath, searchpathlen, L"%s (%u)", searchpath, num) == STRSAFE_E_INSUFFICIENT_BUFFER) {
- MessageBoxW(pici->hwnd, L"Filename too long.\n", L"Error", MB_ICONERROR);
- CloseHandle(h);
- return E_FAIL;
- }
-
- fff = FindFirstFileW(searchpath, &wfd);
- num++;
- } while (fff != INVALID_HANDLE_VALUE);
- }
+ do {
+#ifndef __REACTOS__
+ name = nameorig + L" (" + to_wstring(num) + L")";
+#else
+ {
+ WCHAR buffer[32];
- bcslen = offsetof(btrfs_create_subvol, name[0]) + (wcslen(&searchpath[pathend]) * sizeof(WCHAR));
- bcs = (btrfs_create_subvol*)malloc(bcslen);
+ swprintf(buffer, L"%d", num);
+ name = nameorig + L" (" + buffer + L")";
+ }
+#endif
+ searchpath = path + L"\\" + name;
- bcs->readonly = FALSE;
- bcs->posix = FALSE;
- bcs->namelen = wcslen(&searchpath[pathend]) * sizeof(WCHAR);
- memcpy(bcs->name, &searchpath[pathend], bcs->namelen);
+ fff = FindFirstFileW(searchpath.c_str(), &wfd);
+ num++;
+ } while (fff != INVALID_HANDLE_VALUE);
+ }
+ }
- Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, bcslen, NULL, 0);
+ size_t bcslen = offsetof(btrfs_create_subvol, name[0]) + (name.length() * sizeof(WCHAR));
+ bcs = (btrfs_create_subvol*)malloc(bcslen);
- free(searchpath);
- free(bcs);
+ bcs->readonly = false;
+ bcs->posix = false;
+ bcs->namelen = (uint16_t)(name.length() * sizeof(WCHAR));
+ memcpy(bcs->name, name.c_str(), name.length() * sizeof(WCHAR));
- if (!NT_SUCCESS(Status)) {
- CloseHandle(h);
- ShowNtStatusError(pici->hwnd, Status);
- return E_FAIL;
- }
+ Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, (ULONG)bcslen, nullptr, 0);
- CloseHandle(h);
+ free(bcs);
- return S_OK;
- } else if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 1) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, RECV_VERBA))) {
- WCHAR dll[MAX_PATH];
- std::wstring t;
- SHELLEXECUTEINFOW sei;
+ if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
- GetModuleFileNameW(module, dll, sizeof(dll) / sizeof(WCHAR));
+ return S_OK;
+ } else if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 1) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, RECV_VERBA))) {
+ WCHAR dll[MAX_PATH];
+ wstring t;
+ SHELLEXECUTEINFOW sei;
- t = L"\"";
- t += dll;
- t += L"\",RecvSubvolGUI ";
- t += path;
+ GetModuleFileNameW(module, dll, sizeof(dll) / sizeof(WCHAR));
- RtlZeroMemory(&sei, sizeof(sei));
+ t = L"\"";
+ t += dll;
+ t += L"\",RecvSubvolGUI ";
+ t += path;
- sei.cbSize = sizeof(sei);
- sei.hwnd = pici->hwnd;
- sei.lpVerb = L"runas";
- sei.lpFile = L"rundll32.exe";
- sei.lpParameters = t.c_str();
- sei.nShow = SW_SHOW;
- sei.fMask = SEE_MASK_NOCLOSEPROCESS;
+ RtlZeroMemory(&sei, sizeof(sei));
- if (!ShellExecuteExW(&sei)) {
- ShowError(pici->hwnd, GetLastError());
- return E_FAIL;
- }
+ sei.cbSize = sizeof(sei);
+ sei.hwnd = pici->hwnd;
+ sei.lpVerb = L"runas";
+ sei.lpFile = L"rundll32.exe";
+ sei.lpParameters = t.c_str();
+ sei.nShow = SW_SHOW;
+ sei.fMask = SEE_MASK_NOCLOSEPROCESS;
- WaitForSingleObject(sei.hProcess, INFINITE);
- CloseHandle(sei.hProcess);
+ if (!ShellExecuteExW(&sei))
+ throw last_error(GetLastError());
- return S_OK;
- } else if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 2) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, REFLINK_VERBA))) {
- HDROP hdrop;
+ WaitForSingleObject(sei.hProcess, INFINITE);
+ CloseHandle(sei.hProcess);
- if (!IsClipboardFormatAvailable(CF_HDROP))
return S_OK;
+ } else if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 2) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, REFLINK_VERBA))) {
+ HDROP hdrop;
- if (!OpenClipboard(pici->hwnd)) {
- ShowError(pici->hwnd, GetLastError());
- return E_FAIL;
- }
+ if (!IsClipboardFormatAvailable(CF_HDROP))
+ return S_OK;
+
+ if (!OpenClipboard(pici->hwnd))
+ throw last_error(GetLastError());
- hdrop = (HDROP)GetClipboardData(CF_HDROP);
+ try {
+ hdrop = (HDROP)GetClipboardData(CF_HDROP);
- if (hdrop) {
- HANDLE lh;
+ if (hdrop) {
+ HANDLE lh;
- lh = GlobalLock(hdrop);
+ lh = GlobalLock(hdrop);
- if (lh) {
- ULONG num_files, i;
- WCHAR fn[MAX_PATH];
+ if (lh) {
+ try {
+ ULONG num_files, i;
+ WCHAR fn[MAX_PATH];
- num_files = DragQueryFileW(hdrop, 0xFFFFFFFF, NULL, 0);
+ num_files = DragQueryFileW(hdrop, 0xFFFFFFFF, nullptr, 0);
- for (i = 0; i < num_files; i++) {
- if (DragQueryFileW(hdrop, i, fn, sizeof(fn) / sizeof(WCHAR))) {
- if (!reflink_copy(pici->hwnd, fn, pici->lpDirectoryW)) {
+ for (i = 0; i < num_files; i++) {
+ if (DragQueryFileW(hdrop, i, fn, sizeof(fn) / sizeof(WCHAR))) {
+ reflink_copy(pici->hwnd, fn, pici->lpDirectoryW);
+ }
+ }
+ } catch (...) {
GlobalUnlock(lh);
- CloseClipboard();
- return E_FAIL;
+ throw;
}
+
+ GlobalUnlock(lh);
}
}
-
- GlobalUnlock(lh);
+ } catch (...) {
+ CloseClipboard();
+ throw;
}
- }
- CloseClipboard();
+ CloseClipboard();
- return S_OK;
+ return S_OK;
+ }
}
+ } catch (const exception& e) {
+ error_message(pici->hwnd, e.what());
}
return E_FAIL;
}
}
-static void reflink_copy2(std::wstring srcfn, std::wstring destdir, std::wstring destname) {
- HANDLE source, dest;
- BOOL ret = FALSE;
+static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const wstring& destname) {
+ win_handle source, dest;
FILE_BASIC_INFO fbi;
FILETIME atime, mtime;
btrfs_inode_info bii;
IO_STATUS_BLOCK iosb;
btrfs_set_xattr bsxa;
- source = CreateFileW(srcfn.c_str(), GENERIC_READ | FILE_TRAVERSE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT, NULL);
+ source = CreateFileW(srcfn.c_str(), GENERIC_READ | FILE_TRAVERSE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT, nullptr);
if (source == INVALID_HANDLE_VALUE)
- return;
+ throw last_error(GetLastError());
- Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_INODE_INFO, NULL, 0, &bii, sizeof(btrfs_inode_info));
- if (!NT_SUCCESS(Status)) {
- CloseHandle(source);
- return;
- }
+ Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_INODE_INFO, nullptr, 0, &bii, sizeof(btrfs_inode_info));
+ if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
// if subvol, do snapshot instead
if (bii.inode == SUBVOL_ROOT_INODE) {
- ULONG bcslen;
btrfs_create_snapshot* bcs;
- HANDLE dirh;
+ win_handle dirh;
- dirh = CreateFileW(destdir.c_str(), FILE_ADD_SUBDIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (dirh == INVALID_HANDLE_VALUE) {
- CloseHandle(source);
- return;
- }
+ dirh = CreateFileW(destdir.c_str(), FILE_ADD_SUBDIRECTORY, 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());
- 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 = destname.length() * sizeof(WCHAR);
+ bcs->namelen = (uint16_t)(destname.length() * sizeof(WCHAR));
memcpy(bcs->name, destname.c_str(), destname.length() * sizeof(WCHAR));
- Status = NtFsControlFile(dirh, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, bcslen, NULL, 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);
+ }
free(bcs);
- CloseHandle(source);
- CloseHandle(dirh);
-
return;
}
- if (!GetFileInformationByHandleEx(source, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO))) {
- CloseHandle(source);
- return;
- }
+ 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) {
- HANDLE dirh;
- ULONG bmnsize;
+ win_handle dirh;
btrfs_mknod* bmn;
- dirh = CreateFileW(destdir.c_str(), FILE_ADD_FILE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (dirh == INVALID_HANDLE_VALUE) {
- CloseHandle(source);
- return;
- }
+ 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;
bmn->type = bii.type;
bmn->st_rdev = bii.st_rdev;
- bmn->namelen = destname.length() * sizeof(WCHAR);
+ bmn->namelen = (uint16_t)(destname.length() * sizeof(WCHAR));
memcpy(bmn->name, destname.c_str(), bmn->namelen);
- Status = NtFsControlFile(dirh, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_MKNOD, bmn, bmnsize, NULL, 0);
+ Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, (ULONG)bmnsize, nullptr, 0);
if (!NT_SUCCESS(Status)) {
- CloseHandle(dirh);
- CloseHandle(source);
free(bmn);
- return;
+ throw ntstatus_error(Status);
}
- CloseHandle(dirh);
free(bmn);
- dest = CreateFileW((destdir + destname).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, 0, NULL);
+ dest = CreateFileW((destdir + destname).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
} else if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- if (CreateDirectoryExW(srcfn.c_str(), (destdir + destname).c_str(), NULL))
+ if (CreateDirectoryExW(srcfn.c_str(), (destdir + destname).c_str(), nullptr))
dest = CreateFileW((destdir + destname).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- else
- dest = INVALID_HANDLE_VALUE;
+ nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
+ else
+ dest = INVALID_HANDLE_VALUE;
} else
- dest = CreateFileW((destdir + destname).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW, 0, source);
+ dest = CreateFileW((destdir + destname).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, source);
- if (dest == INVALID_HANDLE_VALUE) {
- CloseHandle(source);
- return;
- }
+ if (dest == INVALID_HANDLE_VALUE)
+ throw last_error(GetLastError());
memset(&bsii, 0, sizeof(btrfs_set_inode_info));
- bsii.flags_changed = TRUE;
+ bsii.flags_changed = true;
bsii.flags = bii.flags;
if (bii.flags & BTRFS_INODE_COMPRESS) {
- bsii.compression_type_changed = TRUE;
+ bsii.compression_type_changed = true;
bsii.compression_type = bii.compression_type;
}
- Status = NtFsControlFile(dest, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), NULL, 0);
- if (!NT_SUCCESS(Status))
- goto end;
+ try {
+ Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), nullptr, 0);
+ if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
- if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- if (!(fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
- HANDLE h;
- WIN32_FIND_DATAW fff;
- std::wstring qs;
+ if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ if (!(fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ WIN32_FIND_DATAW fff;
+ wstring qs;
- qs = srcfn;
- qs += L"\\*";
+ qs = srcfn;
+ qs += L"\\*";
- h = FindFirstFileW(qs.c_str(), &fff);
- if (h != INVALID_HANDLE_VALUE) {
- do {
- std::wstring fn2;
-
- if (fff.cFileName[0] == '.' && (fff.cFileName[1] == 0 || (fff.cFileName[1] == '.' && fff.cFileName[2] == 0)))
- continue;
+ fff_handle h = FindFirstFileW(qs.c_str(), &fff);
+ if (h != INVALID_HANDLE_VALUE) {
+ do {
+ wstring fn2;
- fn2 = srcfn;
- fn2 += L"\\";
- fn2 += fff.cFileName;
+ if (fff.cFileName[0] == '.' && (fff.cFileName[1] == 0 || (fff.cFileName[1] == '.' && fff.cFileName[2] == 0)))
+ continue;
- reflink_copy2(fn2, destdir + destname + L"\\", fff.cFileName);
- } while (FindNextFileW(h, &fff));
+ fn2 = srcfn;
+ fn2 += L"\\";
+ fn2 += fff.cFileName;
- FindClose(h);
+ reflink_copy2(fn2, destdir + destname + L"\\", fff.cFileName);
+ } while (FindNextFileW(h, &fff));
+ }
}
- }
- // CreateDirectoryExW also copies streams, no need to do it here
- } else {
- HANDLE h;
- WIN32_FIND_STREAM_DATA fsd;
-
- if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- reparse_header rh;
- ULONG rplen;
- UINT8* rp;
+ // CreateDirectoryExW also copies streams, no need to do it here
+ } else {
+ if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ reparse_header rh;
+ uint8_t* rp;
- if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, NULL, 0, &rh, sizeof(reparse_header), &bytesret, NULL)) {
- if (GetLastError() != ERROR_MORE_DATA)
- goto end;
- }
+ if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, &rh, sizeof(reparse_header), &bytesret, nullptr)) {
+ if (GetLastError() != ERROR_MORE_DATA)
+ throw last_error(GetLastError());
+ }
- rplen = sizeof(reparse_header) + rh.ReparseDataLength;
- rp = (UINT8*)malloc(rplen);
+ size_t rplen = sizeof(reparse_header) + rh.ReparseDataLength;
+ rp = (uint8_t*)malloc(rplen);
- if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, NULL, 0, rp, rplen, &bytesret, NULL))
- goto end;
+ try {
+ 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, NULL, 0, &bytesret, NULL))
- goto end;
+ if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, (DWORD)rplen, nullptr, 0, &bytesret, nullptr))
+ throw last_error(GetLastError());
+ } catch (...) {
+ free(rp);
+ throw;
+ }
- free(rp);
- } else {
- FILE_STANDARD_INFO fsi;
- FILE_END_OF_FILE_INFO feofi;
- FSCTL_GET_INTEGRITY_INFORMATION_BUFFER fgiib;
- FSCTL_SET_INTEGRITY_INFORMATION_BUFFER fsiib;
- DUPLICATE_EXTENTS_DATA ded;
- UINT64 offset, alloc_size;
- ULONG maxdup;
-
- if (!GetFileInformationByHandleEx(source, FileStandardInfo, &fsi, sizeof(FILE_STANDARD_INFO)))
- goto end;
-
- if (!DeviceIoControl(source, FSCTL_GET_INTEGRITY_INFORMATION, NULL, 0, &fgiib, sizeof(FSCTL_GET_INTEGRITY_INFORMATION_BUFFER), &bytesret, NULL))
- goto end;
-
- if (fbi.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) {
- if (!DeviceIoControl(dest, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &bytesret, NULL))
- goto end;
- }
+ free(rp);
+ } else {
+ FILE_STANDARD_INFO fsi;
+ FILE_END_OF_FILE_INFO feofi;
+ FSCTL_GET_INTEGRITY_INFORMATION_BUFFER fgiib;
+ FSCTL_SET_INTEGRITY_INFORMATION_BUFFER fsiib;
+ DUPLICATE_EXTENTS_DATA ded;
+ uint64_t offset, alloc_size;
+ ULONG maxdup;
+
+ 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());
+
+ if (fbi.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) {
+ if (!DeviceIoControl(dest, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &bytesret, nullptr))
+ throw last_error(GetLastError());
+ }
- fsiib.ChecksumAlgorithm = fgiib.ChecksumAlgorithm;
- fsiib.Reserved = 0;
- fsiib.Flags = fgiib.Flags;
- if (!DeviceIoControl(dest, FSCTL_SET_INTEGRITY_INFORMATION, &fsiib, sizeof(FSCTL_SET_INTEGRITY_INFORMATION_BUFFER), NULL, 0, &bytesret, NULL))
- goto end;
+ fsiib.ChecksumAlgorithm = fgiib.ChecksumAlgorithm;
+ fsiib.Reserved = 0;
+ fsiib.Flags = fgiib.Flags;
+ if (!DeviceIoControl(dest, FSCTL_SET_INTEGRITY_INFORMATION, &fsiib, sizeof(FSCTL_SET_INTEGRITY_INFORMATION_BUFFER), nullptr, 0, &bytesret, nullptr))
+ throw last_error(GetLastError());
- feofi.EndOfFile = fsi.EndOfFile;
- if (!SetFileInformationByHandle(dest, FileEndOfFileInfo, &feofi, sizeof(FILE_END_OF_FILE_INFO)))
- goto end;
+ feofi.EndOfFile = fsi.EndOfFile;
+ 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;
+ ded.FileHandle = source;
+ maxdup = 0xffffffff - fgiib.ClusterSizeInBytes + 1;
- alloc_size = sector_align(fsi.EndOfFile.QuadPart, fgiib.ClusterSizeInBytes);
+ alloc_size = sector_align(fsi.EndOfFile.QuadPart, fgiib.ClusterSizeInBytes);
- offset = 0;
- while (offset < alloc_size) {
- ded.SourceFileOffset.QuadPart = ded.TargetFileOffset.QuadPart = offset;
- ded.ByteCount.QuadPart = maxdup < (alloc_size - offset) ? maxdup : (alloc_size - offset);
- if (!DeviceIoControl(dest, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &ded, sizeof(DUPLICATE_EXTENTS_DATA), NULL, 0, &bytesret, NULL))
- goto end;
+ offset = 0;
+ while (offset < alloc_size) {
+ ded.SourceFileOffset.QuadPart = ded.TargetFileOffset.QuadPart = offset;
+ ded.ByteCount.QuadPart = maxdup < (alloc_size - offset) ? maxdup : (alloc_size - offset);
+ if (!DeviceIoControl(dest, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &ded, sizeof(DUPLICATE_EXTENTS_DATA), nullptr, 0, &bytesret, nullptr))
+ throw last_error(GetLastError());
- offset += ded.ByteCount.QuadPart;
+ offset += ded.ByteCount.QuadPart;
+ }
}
- }
- h = FindFirstStreamW(srcfn.c_str(), FindStreamInfoStandard, &fsd, 0);
- if (h != INVALID_HANDLE_VALUE) {
+ ULONG streambufsize = 0;
+ vector<char> streambuf;
+
do {
- std::wstring sn;
+ streambufsize += 0x1000;
+ streambuf.resize(streambufsize);
- sn = fsd.cStreamName;
+ memset(streambuf.data(), 0, streambufsize);
- if (sn != L"::$DATA" && sn.length() > 6 && sn.substr(sn.length() - 6, 6) == L":$DATA") {
- HANDLE stream;
- UINT8* data = NULL;
+ Status = NtQueryInformationFile(source, &iosb, streambuf.data(), streambufsize, FileStreamInformation);
+ } while (Status == STATUS_BUFFER_OVERFLOW);
- if (fsd.StreamSize.QuadPart > 0) {
- std::wstring fn2;
+ if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
- fn2 = srcfn;
- fn2 += sn;
+ auto fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(streambuf.data());
- stream = CreateFileW(fn2.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+ while (true) {
+ if (fsi->StreamNameLength > 0) {
+ wstring sn = wstring(fsi->StreamName, fsi->StreamNameLength / sizeof(WCHAR));
- if (stream == INVALID_HANDLE_VALUE)
- goto end;
+ 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;
- // We can get away with this because our streams are guaranteed to be below 64 KB -
- // don't do this on NTFS!
- data = (UINT8*)malloc(fsd.StreamSize.QuadPart);
+ if (stream_size > 0) {
+ wstring fn2;
- if (!ReadFile(stream, data, fsd.StreamSize.QuadPart, &bytesret, NULL)) {
- free(data);
- CloseHandle(stream);
- goto end;
+ fn2 = srcfn;
+ fn2 += sn;
+
+ stream = CreateFileW(fn2.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
+
+ if (stream == INVALID_HANDLE_VALUE)
+ throw last_error(GetLastError());
+
+ // We can get away with this because our streams are guaranteed to be below 64 KB -
+ // don't do this on NTFS!
+ data = (uint8_t*)malloc(stream_size);
+
+ if (!ReadFile(stream, data, stream_size, &bytesret, nullptr)) {
+ free(data);
+ throw last_error(GetLastError());
+ }
}
- CloseHandle(stream);
- }
+ stream = CreateFileW((destdir + destname + sn).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, nullptr);
- stream = CreateFileW((destdir + destname + sn).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW, 0, NULL);
+ if (stream == INVALID_HANDLE_VALUE) {
+ if (data) free(data);
+ throw last_error(GetLastError());
+ }
- if (stream == INVALID_HANDLE_VALUE) {
- if (data) free(data);
- goto end;
- }
+ if (data) {
+ if (!WriteFile(stream, data, stream_size, &bytesret, nullptr)) {
+ free(data);
+ throw last_error(GetLastError());
+ }
- if (data) {
- if (!WriteFile(stream, data, fsd.StreamSize.QuadPart, &bytesret, NULL)) {
free(data);
- CloseHandle(stream);
- goto end;
}
-
- free(data);
}
- CloseHandle(stream);
}
- } while (FindNextStreamW(h, &fsd));
- FindClose(h);
- }
- }
+ if (fsi->NextEntryOffset == 0)
+ break;
- atime.dwLowDateTime = fbi.LastAccessTime.LowPart;
- atime.dwHighDateTime = fbi.LastAccessTime.HighPart;
- mtime.dwLowDateTime = fbi.LastWriteTime.LowPart;
- mtime.dwHighDateTime = fbi.LastWriteTime.HighPart;
- SetFileTime(dest, NULL, &atime, &mtime);
+ fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(reinterpret_cast<char*>(fsi) + fsi->NextEntryOffset);
+ }
+ }
- Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_XATTRS, NULL, 0, &bsxa, sizeof(btrfs_set_xattr));
+ atime.dwLowDateTime = fbi.LastAccessTime.LowPart;
+ atime.dwHighDateTime = fbi.LastAccessTime.HighPart;
+ mtime.dwLowDateTime = fbi.LastWriteTime.LowPart;
+ mtime.dwHighDateTime = fbi.LastWriteTime.HighPart;
+ SetFileTime(dest, nullptr, &atime, &mtime);
- if (Status == STATUS_BUFFER_OVERFLOW || (NT_SUCCESS(Status) && bsxa.valuelen > 0)) {
- ULONG xalen = 0;
- btrfs_set_xattr *xa = NULL, *xa2;
+ Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_XATTRS, nullptr, 0, &bsxa, sizeof(btrfs_set_xattr));
- do {
- xalen += 1024;
+ if (Status == STATUS_BUFFER_OVERFLOW || (NT_SUCCESS(Status) && bsxa.valuelen > 0)) {
+ ULONG xalen = 0;
+ btrfs_set_xattr *xa = nullptr, *xa2;
- if (xa) free(xa);
- xa = (btrfs_set_xattr*)malloc(xalen);
+ do {
+ xalen += 1024;
- Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_XATTRS, NULL, 0, xa, xalen);
- } while (Status == STATUS_BUFFER_OVERFLOW);
+ if (xa) free(xa);
+ xa = (btrfs_set_xattr*)malloc(xalen);
- if (!NT_SUCCESS(Status)) {
- free(xa);
- goto end;
- }
+ Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_XATTRS, nullptr, 0, xa, xalen);
+ } while (Status == STATUS_BUFFER_OVERFLOW);
- xa2 = xa;
- while (xa2->valuelen > 0) {
- Status = NtFsControlFile(dest, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_XATTR, xa2,
- offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen, NULL, 0);
if (!NT_SUCCESS(Status)) {
free(xa);
- goto end;
+ throw ntstatus_error(Status);
}
- xa2 = (btrfs_set_xattr*)&xa2->data[xa2->namelen + xa2->valuelen];
- }
- free(xa);
- } else if (!NT_SUCCESS(Status))
- goto end;
-
- ret = TRUE;
+ xa2 = xa;
+ while (xa2->valuelen > 0) {
+ Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, xa2,
+ (ULONG)(offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen), nullptr, 0);
+ if (!NT_SUCCESS(Status)) {
+ free(xa);
+ throw ntstatus_error(Status);
+ }
+ xa2 = (btrfs_set_xattr*)&xa2->data[xa2->namelen + xa2->valuelen];
+ }
-end:
- if (!ret) {
+ free(xa);
+ } else if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
+ } catch (...) {
FILE_DISPOSITION_INFO fdi;
- fdi.DeleteFile = TRUE;
- SetFileInformationByHandle(dest, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO));
- }
+ fdi.DeleteFile = true;
+ Status = NtSetInformationFile(dest, &iosb, &fdi, sizeof(FILE_DISPOSITION_INFO), FileDispositionInformation);
+ if (!NT_SUCCESS(Status))
+ throw ntstatus_error(Status);
- CloseHandle(dest);
- CloseHandle(source);
+ throw;
+ }
}
-void CALLBACK ReflinkCopyW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
- LPWSTR* args;
- int num_args;
+#ifdef __REACTOS__
+extern "C" {
+#endif
- args = CommandLineToArgvW(lpszCmdLine, &num_args);
+void CALLBACK ReflinkCopyW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
+ vector<wstring> args;
- if (!args)
- return;
+ command_line_to_args(lpszCmdLine, args);
- if (num_args >= 2) {
- HANDLE destdirh;
- BOOL dest_is_dir = FALSE;
- std::wstring dest = args[num_args - 1], destdir, destname;
+ if (args.size() >= 2) {
+ bool dest_is_dir = false;
+ wstring dest = args[args.size() - 1], destdir, destname;
WCHAR volpath2[MAX_PATH];
- int i;
- destdirh = CreateFileW(dest.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- if (destdirh != INVALID_HANDLE_VALUE) {
- BY_HANDLE_FILE_INFORMATION bhfi;
+ {
+ win_handle destdirh = CreateFileW(dest.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
+
+ if (destdirh != INVALID_HANDLE_VALUE) {
+ BY_HANDLE_FILE_INFORMATION bhfi;
- if (GetFileInformationByHandle(destdirh, &bhfi) && bhfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- dest_is_dir = TRUE;
+ if (GetFileInformationByHandle(destdirh, &bhfi) && bhfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ dest_is_dir = true;
- destdir = dest;
- if (destdir.substr(destdir.length() - 1, 1) != L"\\")
- destdir += L"\\";
+ destdir = dest;
+ if (destdir.substr(destdir.length() - 1, 1) != L"\\")
+ destdir += L"\\";
+ }
}
- CloseHandle(destdirh);
}
if (!dest_is_dir) {
size_t found = dest.rfind(L"\\");
- if (found == std::wstring::npos) {
+ if (found == wstring::npos) {
destdir = L"";
destname = dest;
} else {
}
if (!GetVolumePathNameW(dest.c_str(), volpath2, sizeof(volpath2) / sizeof(WCHAR)))
- goto end;
+ return;
- for (i = 0; i < num_args - 1; i++) {
+ for (unsigned int i = 0; i < args.size() - 1; i++) {
WIN32_FIND_DATAW ffd;
- HANDLE h;
- h = FindFirstFileW(args[i], &ffd);
+ fff_handle h = FindFirstFileW(args[i].c_str(), &ffd);
if (h != INVALID_HANDLE_VALUE) {
WCHAR volpath1[MAX_PATH];
- std::wstring path = args[i];
+ wstring path = args[i];
size_t found = path.rfind(L"\\");
- if (found == std::wstring::npos)
+ if (found == wstring::npos)
path = L"";
else
path = path.substr(0, found);
if (get_volume_path_parent(path.c_str(), volpath1, sizeof(volpath1) / sizeof(WCHAR))) {
if (!wcscmp(volpath1, volpath2)) {
do {
- reflink_copy2(path + ffd.cFileName, destdir, dest_is_dir ? ffd.cFileName : destname);
+ try {
+ reflink_copy2(path + ffd.cFileName, destdir, dest_is_dir ? ffd.cFileName : destname);
+ } catch (const exception& e) {
+ cerr << "Error: " << e.what() << endl;
+ }
} while (FindNextFileW(h, &ffd));
}
}
-
- FindClose(h);
}
}
}
-
-end:
- LocalFree(args);
}
+
+#ifdef __REACTOS__
+} /* extern "C" */
+#endif