ReactOS  0.4.14-dev-608-gd495a4f
contextmenu.cpp
Go to the documentation of this file.
1 /* Copyright (c) Mark Harmstone 2016-17
2  *
3  * This file is part of WinBtrfs.
4  *
5  * WinBtrfs is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public Licence as published by
7  * the Free Software Foundation, either version 3 of the Licence, or
8  * (at your option) any later version.
9  *
10  * WinBtrfs is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public Licence for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public Licence
16  * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17 
18 #include "shellext.h"
19 #ifndef __REACTOS__
20 #include <windows.h>
21 #include <strsafe.h>
22 #include <stddef.h>
23 #include <winternl.h>
24 #else
25 #define WIN32_NO_STATUS
26 #include <windef.h>
27 #include <winbase.h>
28 #include <strsafe.h>
29 #include <shellapi.h>
30 #include <winioctl.h>
31 #include <ndk/iofuncs.h>
32 #undef DeleteFile
33 #endif
34 #include <wincodec.h>
35 #include <sstream>
36 #include <iostream>
37 
38 #define NO_SHLWAPI_STRFCNS
39 #include <shlwapi.h>
40 
41 #include "contextmenu.h"
42 #include "resource.h"
43 #ifndef __REACTOS__
44 #include "../btrfsioctl.h"
45 #else
46 #include "btrfsioctl.h"
47 #endif
48 
49 #define NEW_SUBVOL_VERBA "newsubvol"
50 #define NEW_SUBVOL_VERBW L"newsubvol"
51 #define SNAPSHOT_VERBA "snapshot"
52 #define SNAPSHOT_VERBW L"snapshot"
53 #define REFLINK_VERBA "reflink"
54 #define REFLINK_VERBW L"reflink"
55 #define RECV_VERBA "recvsubvol"
56 #define RECV_VERBW L"recvsubvol"
57 #define SEND_VERBA "sendsubvol"
58 #define SEND_VERBW L"sendsubvol"
59 
60 typedef struct {
65 
66 static void path_remove_file(wstring& path);
67 
68 // FIXME - don't assume subvol's top inode is 0x100
69 
71  if (riid == IID_IUnknown || riid == IID_IContextMenu) {
72  *ppObj = static_cast<IContextMenu*>(this);
73  AddRef();
74  return S_OK;
75  } else if (riid == IID_IShellExtInit) {
76  *ppObj = static_cast<IShellExtInit*>(this);
77  AddRef();
78  return S_OK;
79  }
80 
81  *ppObj = nullptr;
82  return E_NOINTERFACE;
83 }
84 
87  btrfs_get_file_ids bgfi;
89 
90  if (!pidlFolder) {
91  FORMATETC format = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
92  UINT num_files, i;
93  WCHAR fn[MAX_PATH];
94  HDROP hdrop;
95 
96  if (!pdtobj)
97  return E_FAIL;
98 
99  stgm.tymed = TYMED_HGLOBAL;
100 
101  if (FAILED(pdtobj->GetData(&format, &stgm)))
102  return E_INVALIDARG;
103 
104  stgm_set = true;
105 
106  hdrop = (HDROP)GlobalLock(stgm.hGlobal);
107 
108  if (!hdrop) {
110  stgm_set = false;
111  return E_INVALIDARG;
112  }
113 
114  num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, nullptr, 0);
115 
116  for (i = 0; i < num_files; i++) {
117  if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
119 
120  if (h != INVALID_HANDLE_VALUE) {
121  Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_FILE_IDS, nullptr, 0, &bgfi, sizeof(btrfs_get_file_ids));
122 
123  if (NT_SUCCESS(Status) && bgfi.inode == 0x100 && !bgfi.top) {
124  wstring parpath;
125 
126  {
127  win_handle h2;
128 
129  parpath = fn;
130  path_remove_file(parpath);
131 
134 
135  if (h2 != INVALID_HANDLE_VALUE)
136  allow_snapshot = true;
137  }
138 
139  ignore = false;
140  bg = false;
141 
142  GlobalUnlock(hdrop);
143  return S_OK;
144  }
145  }
146  }
147  }
148 
149  GlobalUnlock(hdrop);
150 
151  return S_OK;
152  }
153 
154  {
155  WCHAR pathbuf[MAX_PATH];
156 
157  if (!SHGetPathFromIDListW(pidlFolder, pathbuf))
158  return E_FAIL;
159 
160  path = pathbuf;
161  }
162 
163  {
164  // check we have permissions to create new subdirectory
165 
167 
168  if (h == INVALID_HANDLE_VALUE)
169  return E_FAIL;
170 
171  // check is Btrfs volume
172 
173  Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_FILE_IDS, nullptr, 0, &bgfi, sizeof(btrfs_get_file_ids));
174 
175  if (!NT_SUCCESS(Status))
176  return E_FAIL;
177  }
178 
179  ignore = false;
180  bg = true;
181 
182  return S_OK;
183 }
184 
185 static bool get_volume_path_parent(const WCHAR* fn, WCHAR* volpath, ULONG volpathlen) {
186  WCHAR *f, *p;
187  bool b;
188 
190 
191  if (f == fn)
192  return GetVolumePathNameW(fn, volpath, volpathlen);
193 
194  p = (WCHAR*)malloc((f - fn + 1) * sizeof(WCHAR));
195  memcpy(p, fn, (f - fn) * sizeof(WCHAR));
196  p[f - fn] = 0;
197 
198  b = GetVolumePathNameW(p, volpath, volpathlen);
199 
200  free(p);
201 
202  return b;
203 }
204 
205 static bool show_reflink_paste(const wstring& path) {
206  HDROP hdrop;
207  HANDLE lh;
208  ULONG num_files;
209  WCHAR fn[MAX_PATH], volpath1[255], volpath2[255];
210 
212  return false;
213 
214  if (!GetVolumePathNameW(path.c_str(), volpath1, sizeof(volpath1) / sizeof(WCHAR)))
215  return false;
216 
217  if (!OpenClipboard(nullptr))
218  return false;
219 
220  hdrop = (HDROP)GetClipboardData(CF_HDROP);
221 
222  if (!hdrop) {
223  CloseClipboard();
224  return false;
225  }
226 
227  lh = GlobalLock(hdrop);
228 
229  if (!lh) {
230  CloseClipboard();
231  return false;
232  }
233 
234  num_files = DragQueryFileW(hdrop, 0xFFFFFFFF, nullptr, 0);
235 
236  if (num_files == 0) {
237  GlobalUnlock(lh);
238  CloseClipboard();
239  return false;
240  }
241 
242  if (!DragQueryFileW(hdrop, 0, fn, sizeof(fn) / sizeof(WCHAR))) {
243  GlobalUnlock(lh);
244  CloseClipboard();
245  return false;
246  }
247 
248  if (!get_volume_path_parent(fn, volpath2, sizeof(volpath2) / sizeof(WCHAR))) {
249  GlobalUnlock(lh);
250  CloseClipboard();
251  return false;
252  }
253 
254  GlobalUnlock(lh);
255 
256  CloseClipboard();
257 
258  return !wcscmp(volpath1, volpath2);
259 }
260 
261 // The code for putting an icon against a menu item comes from:
262 // http://web.archive.org/web/20070208005514/http://shellrevealed.com/blogs/shellblog/archive/2007/02/06/Vista-Style-Menus_2C00_-Part-1-_2D00_-Adding-icons-to-standard-menus.aspx
263 
264 static void InitBitmapInfo(BITMAPINFO* pbmi, ULONG cbInfo, LONG cx, LONG cy, WORD bpp) {
265  ZeroMemory(pbmi, cbInfo);
267  pbmi->bmiHeader.biPlanes = 1;
269 
273 }
274 
275 static HRESULT Create32BitHBITMAP(HDC hdc, const SIZE *psize, void **ppvBits, HBITMAP* phBmp) {
276  BITMAPINFO bmi;
277  HDC hdcUsed;
278 
279  *phBmp = nullptr;
280 
281  InitBitmapInfo(&bmi, sizeof(bmi), psize->cx, psize->cy, 32);
282 
283  hdcUsed = hdc ? hdc : GetDC(nullptr);
284 
285  if (hdcUsed) {
286  *phBmp = CreateDIBSection(hdcUsed, &bmi, DIB_RGB_COLORS, ppvBits, nullptr, 0);
287  if (hdc != hdcUsed)
288  ReleaseDC(nullptr, hdcUsed);
289  }
290 
291  return !*phBmp ? E_OUTOFMEMORY : S_OK;
292 }
293 
295  IWICImagingFactory* factory = nullptr;
297  HRESULT hr;
298 
299 #ifdef __REACTOS__
300  hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (void **)&factory);
301 #else
302  hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory));
303 #endif
304 
305  if (SUCCEEDED(hr)) {
306  HANDLE icon;
307 
308  // We can't use IDI_SHIELD, as that will only give us the full-size icon
309  icon = LoadImageW(GetModuleHandleW(L"user32.dll"), MAKEINTRESOURCEW(106)/* UAC shield */, IMAGE_ICON,
311 
312  hr = factory->CreateBitmapFromHICON((HICON)icon, &bitmap);
313  if (SUCCEEDED(hr)) {
314  UINT cx, cy;
315 
316  hr = bitmap->GetSize(&cx, &cy);
317  if (SUCCEEDED(hr)) {
318  SIZE sz;
319  BYTE* buf;
320 
321  sz.cx = (int)cx;
322  sz.cy = -(int)cy;
323 
324  hr = Create32BitHBITMAP(nullptr, &sz, (void**)&buf, &uacicon);
325  if (SUCCEEDED(hr)) {
326  UINT stride = (UINT)(cx * sizeof(DWORD));
327  UINT buflen = cy * stride;
328  bitmap->CopyPixels(nullptr, stride, buflen, buf);
329  }
330  }
331 
332  bitmap->Release();
333  }
334 
335  factory->Release();
336  }
337 }
338 
340  wstring str;
341  ULONG entries = 0;
342 
343  if (ignore)
344  return E_INVALIDARG;
345 
346  if (uFlags & CMF_DEFAULTONLY)
347  return S_OK;
348 
349  if (!bg) {
350  if (allow_snapshot) {
352  return E_FAIL;
353 
354  if (!InsertMenuW(hmenu, indexMenu, MF_BYPOSITION, idCmdFirst, str.c_str()))
355  return E_FAIL;
356 
357  entries = 1;
358  }
359 
360  if (idCmdFirst + entries <= idCmdLast) {
361  MENUITEMINFOW mii;
362 
364  return E_FAIL;
365 
366  if (!uacicon)
367  get_uac_icon();
368 
369  memset(&mii, 0, sizeof(MENUITEMINFOW));
370  mii.cbSize = sizeof(MENUITEMINFOW);
372  mii.dwTypeData = (WCHAR*)str.c_str();
373  mii.wID = idCmdFirst + entries;
374  mii.hbmpItem = uacicon;
375 
376  if (!InsertMenuItemW(hmenu, indexMenu + entries, true, &mii))
377  return E_FAIL;
378 
379  entries++;
380  }
381  } else {
382  if (load_string(module, IDS_NEW_SUBVOL, str) == 0)
383  return E_FAIL;
384 
385  if (!InsertMenuW(hmenu, indexMenu, MF_BYPOSITION, idCmdFirst, str.c_str()))
386  return E_FAIL;
387 
388  entries = 1;
389 
390  if (idCmdFirst + 1 <= idCmdLast) {
391  MENUITEMINFOW mii;
392 
394  return E_FAIL;
395 
396  if (!uacicon)
397  get_uac_icon();
398 
399  memset(&mii, 0, sizeof(MENUITEMINFOW));
400  mii.cbSize = sizeof(MENUITEMINFOW);
402  mii.dwTypeData = (WCHAR*)str.c_str();
403  mii.wID = idCmdFirst + 1;
404  mii.hbmpItem = uacicon;
405 
406  if (!InsertMenuItemW(hmenu, indexMenu + 1, true, &mii))
407  return E_FAIL;
408 
409  entries++;
410  }
411 
412  if (idCmdFirst + 2 <= idCmdLast && show_reflink_paste(path)) {
414  return E_FAIL;
415 
416  if (!InsertMenuW(hmenu, indexMenu + 2, MF_BYPOSITION, idCmdFirst + 2, str.c_str()))
417  return E_FAIL;
418 
419  entries++;
420  }
421  }
422 
423  return MAKE_HRESULT(SEVERITY_SUCCESS, 0, entries);
424 }
425 
426 static void path_remove_file(wstring& path) {
427  size_t bs = path.rfind(L"\\");
428 
429  if (bs == string::npos)
430  return;
431 
432  if (bs == path.find(L"\\")) { // only one backslash
433  path = path.substr(0, bs + 1);
434  return;
435  }
436 
437  path = path.substr(0, bs);
438 }
439 
440 static void path_strip_path(wstring& path) {
441  size_t bs = path.rfind(L"\\");
442 
443  if (bs == string::npos) {
444  path = L"";
445  return;
446  }
447 
448  path = path.substr(bs + 1);
449 }
450 
451 static void create_snapshot(HWND hwnd, const wstring& fn) {
452  win_handle h;
455  btrfs_get_file_ids bgfi;
456 
458 
459  if (h != INVALID_HANDLE_VALUE) {
460  Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_FILE_IDS, nullptr, 0, &bgfi, sizeof(btrfs_get_file_ids));
461 
462  if (NT_SUCCESS(Status) && bgfi.inode == 0x100 && !bgfi.top) {
463  wstring subvolname, parpath, searchpath, temp1, name, nameorig;
464  win_handle h2;
465  WIN32_FIND_DATAW wfd;
467 
468  parpath = fn;
469  path_remove_file(parpath);
470 
471  subvolname = fn;
472  path_strip_path(subvolname);
473 
475 
476  if (h2 == INVALID_HANDLE_VALUE)
477  throw last_error(GetLastError());
478 
480  throw last_error(GetLastError());
481 
482  GetLocalTime(&time);
483 
484  wstring_sprintf(name, temp1, subvolname.c_str(), time.wYear, time.wMonth, time.wDay);
485  nameorig = name;
486 
487  searchpath = parpath + L"\\" + name;
488 
489  fff_handle fff = FindFirstFileW(searchpath.c_str(), &wfd);
490 
491  if (fff != INVALID_HANDLE_VALUE) {
492  ULONG num = 2;
493 
494  do {
495 #ifndef __REACTOS__
496  name = nameorig + L" (" + to_wstring(num) + L")";
497 #else
498  {
499  WCHAR buffer[32];
500 
501  swprintf(buffer, L"%d", num);
502  name = nameorig + L" (" + buffer + L")";
503  }
504 #endif
505  searchpath = parpath + L"\\" + name;
506 
507  fff = FindFirstFileW(searchpath.c_str(), &wfd);
508  num++;
509  } while (fff != INVALID_HANDLE_VALUE);
510  }
511 
512  size_t namelen = name.length() * sizeof(WCHAR);
513 
514  auto bcs = (btrfs_create_snapshot*)malloc(sizeof(btrfs_create_snapshot) - 1 + namelen);
515  bcs->readonly = false;
516  bcs->posix = false;
517  bcs->subvol = h;
518  bcs->namelen = (uint16_t)namelen;
519  memcpy(bcs->name, name.c_str(), namelen);
520 
521  Status = NtFsControlFile(h2, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs,
522  (ULONG)(sizeof(btrfs_create_snapshot) - 1 + namelen), nullptr, 0);
523 
524  if (!NT_SUCCESS(Status))
525  throw ntstatus_error(Status);
526  }
527  } else
528  throw last_error(GetLastError());
529 }
530 
532  if (n & (a - 1))
533  n = (n + a) & ~(a - 1);
534 
535  return n;
536 }
537 
540  WCHAR* name, volpath1[255], volpath2[255];
541  wstring dirw, newpath;
542  FILE_BASIC_INFO fbi;
543  FILETIME atime, mtime;
544  btrfs_inode_info bii;
546  ULONG bytesret;
549  btrfs_set_xattr bsxa;
550 
551  // Thanks to 0xbadfca11, whose version of reflink for Windows provided a few pointers on what
552  // to do here - https://github.com/0xbadfca11/reflink
553 
555 
556  dirw = dir;
557 
558  if (dir[0] != 0 && dir[wcslen(dir) - 1] != '\\')
559  dirw += L"\\";
560 
561  newpath = dirw;
562  newpath += name;
563 
564  if (!get_volume_path_parent(fn, volpath1, sizeof(volpath1) / sizeof(WCHAR)))
565  throw last_error(GetLastError());
566 
567  if (!GetVolumePathNameW(dir, volpath2, sizeof(volpath2) / sizeof(WCHAR)))
568  throw last_error(GetLastError());
569 
570  if (wcscmp(volpath1, volpath2)) // different filesystems
572 
575  throw last_error(GetLastError());
576 
577  Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_INODE_INFO, nullptr, 0, &bii, sizeof(btrfs_inode_info));
578  if (!NT_SUCCESS(Status))
579  throw ntstatus_error(Status);
580 
581  // if subvol, do snapshot instead
582  if (bii.inode == SUBVOL_ROOT_INODE) {
584  win_handle dirh;
585  wstring destname, search;
586  WIN32_FIND_DATAW wfd;
587  int num = 2;
588 
590  if (dirh == INVALID_HANDLE_VALUE)
591  throw last_error(GetLastError());
592 
593  search = dirw;
594  search += name;
595  destname = name;
596 
597  fff_handle fff = FindFirstFileW(search.c_str(), &wfd);
598 
599  if (fff != INVALID_HANDLE_VALUE) {
600  do {
602 
603  ss << name;
604  ss << L" (";
605  ss << num;
606  ss << L")";
607  destname = ss.str();
608 
609  search = dirw + destname;
610 
611  fff = FindFirstFileW(search.c_str(), &wfd);
612  num++;
613  } while (fff != INVALID_HANDLE_VALUE);
614  }
615 
616  bcs = (btrfs_create_snapshot*)malloc(sizeof(btrfs_create_snapshot) - sizeof(WCHAR) + (destname.length() * sizeof(WCHAR)));
617  bcs->subvol = source;
618  bcs->namelen = (uint16_t)(destname.length() * sizeof(WCHAR));
619  memcpy(bcs->name, destname.c_str(), destname.length() * sizeof(WCHAR));
620 
621  Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs,
622  (ULONG)(sizeof(btrfs_create_snapshot) - sizeof(WCHAR) + bcs->namelen), nullptr, 0);
623 
624  free(bcs);
625 
626  if (!NT_SUCCESS(Status))
627  throw ntstatus_error(Status);
628 
629  return;
630  }
631 
632  Status = NtQueryInformationFile(source, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation);
633  if (!NT_SUCCESS(Status))
634  throw ntstatus_error(Status);
635 
636  if (bii.type == BTRFS_TYPE_CHARDEV || bii.type == BTRFS_TYPE_BLOCKDEV || bii.type == BTRFS_TYPE_FIFO || bii.type == BTRFS_TYPE_SOCKET) {
637  win_handle dirh;
638  btrfs_mknod* bmn;
639 
641  if (dirh == INVALID_HANDLE_VALUE)
642  throw last_error(GetLastError());
643 
644  size_t bmnsize = offsetof(btrfs_mknod, name[0]) + (wcslen(name) * sizeof(WCHAR));
645  bmn = (btrfs_mknod*)malloc(bmnsize);
646 
647  bmn->inode = 0;
648  bmn->type = bii.type;
649  bmn->st_rdev = bii.st_rdev;
650  bmn->namelen = (uint16_t)(wcslen(name) * sizeof(WCHAR));
651  memcpy(bmn->name, name, bmn->namelen);
652 
653  Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, (ULONG)bmnsize, nullptr, 0);
654  if (!NT_SUCCESS(Status)) {
655  free(bmn);
656  throw ntstatus_error(Status);
657  }
658 
659  free(bmn);
660 
661  dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
662  } else if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
663  if (CreateDirectoryExW(fn, newpath.c_str(), nullptr))
665  nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
666  else
668  } else
669  dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, source);
670 
671  if (dest == INVALID_HANDLE_VALUE) {
672  int num = 2;
673 
674  if (GetLastError() != ERROR_FILE_EXISTS && GetLastError() != ERROR_ALREADY_EXISTS && wcscmp(fn, newpath.c_str()))
675  throw last_error(GetLastError());
676 
677  do {
678  WCHAR* ext;
680 
682 
683  ss << dirw;
684 
685  if (*ext == 0) {
686  ss << name;
687  ss << L" (";
688  ss << num;
689  ss << L")";
690  } else {
691  wstring namew = name;
692 
693  ss << namew.substr(0, ext - name);
694  ss << L" (";
695  ss << num;
696  ss << L")";
697  ss << ext;
698  }
699 
700  newpath = ss.str();
701  if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
702  if (CreateDirectoryExW(fn, newpath.c_str(), nullptr))
703  dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
704  else
706  } else
707  dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, source);
708 
709  if (dest == INVALID_HANDLE_VALUE) {
711  throw last_error(GetLastError());
712 
713  num++;
714  } else
715  break;
716  } while (true);
717  }
718 
719  try {
720  memset(&bsii, 0, sizeof(btrfs_set_inode_info));
721 
722  bsii.flags_changed = true;
723  bsii.flags = bii.flags;
724 
725  if (bii.flags & BTRFS_INODE_COMPRESS) {
726  bsii.compression_type_changed = true;
728  }
729 
730  Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), nullptr, 0);
731  if (!NT_SUCCESS(Status))
732  throw ntstatus_error(Status);
733 
734  if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
735  if (!(fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
736  fff_handle h;
737  WIN32_FIND_DATAW fff;
738  wstring qs;
739 
740  qs = fn;
741  qs += L"\\*";
742 
743  h = FindFirstFileW(qs.c_str(), &fff);
744  if (h != INVALID_HANDLE_VALUE) {
745  do {
746  wstring fn2;
747 
748  if (fff.cFileName[0] == '.' && (fff.cFileName[1] == 0 || (fff.cFileName[1] == '.' && fff.cFileName[2] == 0)))
749  continue;
750 
751  fn2 = fn;
752  fn2 += L"\\";
753  fn2 += fff.cFileName;
754 
755  reflink_copy(hwnd, fn2.c_str(), newpath.c_str());
756  } while (FindNextFileW(h, &fff));
757  }
758  }
759 
760  // CreateDirectoryExW also copies streams, no need to do it here
761  } else {
762  if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
763  reparse_header rh;
764  uint8_t* rp;
765 
766  if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, &rh, sizeof(reparse_header), &bytesret, nullptr)) {
767  if (GetLastError() != ERROR_MORE_DATA)
768  throw last_error(GetLastError());
769  }
770 
771  size_t rplen = sizeof(reparse_header) + rh.ReparseDataLength;
772  rp = (uint8_t*)malloc(rplen);
773 
774  if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, rp, (ULONG)rplen, &bytesret, nullptr))
775  throw last_error(GetLastError());
776 
777  if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, (ULONG)rplen, nullptr, 0, &bytesret, nullptr))
778  throw last_error(GetLastError());
779 
780  free(rp);
781  } else {
782  FILE_STANDARD_INFO fsi;
783  FILE_END_OF_FILE_INFO feofi;
787  uint64_t offset, alloc_size;
788  ULONG maxdup;
789 
790  Status = NtQueryInformationFile(source, &iosb, &fsi, sizeof(FILE_STANDARD_INFO), FileStandardInformation);
791  if (!NT_SUCCESS(Status))
792  throw ntstatus_error(Status);
793 
794  if (!DeviceIoControl(source, FSCTL_GET_INTEGRITY_INFORMATION, nullptr, 0, &fgiib, sizeof(FSCTL_GET_INTEGRITY_INFORMATION_BUFFER), &bytesret, nullptr))
795  throw last_error(GetLastError());
796 
797  if (fbi.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) {
798  if (!DeviceIoControl(dest, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &bytesret, nullptr))
799  throw last_error(GetLastError());
800  }
801 
802  fsiib.ChecksumAlgorithm = fgiib.ChecksumAlgorithm;
803  fsiib.Reserved = 0;
804  fsiib.Flags = fgiib.Flags;
805  if (!DeviceIoControl(dest, FSCTL_SET_INTEGRITY_INFORMATION, &fsiib, sizeof(FSCTL_SET_INTEGRITY_INFORMATION_BUFFER), nullptr, 0, &bytesret, nullptr))
806  throw last_error(GetLastError());
807 
808  feofi.EndOfFile = fsi.EndOfFile;
809  Status = NtSetInformationFile(dest, &iosb, &feofi, sizeof(FILE_END_OF_FILE_INFO), FileEndOfFileInformation);
810  if (!NT_SUCCESS(Status))
811  throw ntstatus_error(Status);
812 
813  ded.FileHandle = source;
814  maxdup = 0xffffffff - fgiib.ClusterSizeInBytes + 1;
815 
816  alloc_size = sector_align(fsi.EndOfFile.QuadPart, fgiib.ClusterSizeInBytes);
817 
818  offset = 0;
819  while (offset < alloc_size) {
821  ded.ByteCount.QuadPart = maxdup < (alloc_size - offset) ? maxdup : (alloc_size - offset);
822  if (!DeviceIoControl(dest, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &ded, sizeof(DUPLICATE_EXTENTS_DATA), nullptr, 0, &bytesret, nullptr))
823  throw last_error(GetLastError());
824 
825  offset += ded.ByteCount.QuadPart;
826  }
827  }
828 
829  ULONG streambufsize = 0;
830  vector<char> streambuf;
831 
832  do {
833  streambufsize += 0x1000;
834  streambuf.resize(streambufsize);
835 
836  memset(streambuf.data(), 0, streambufsize);
837 
839  } while (Status == STATUS_BUFFER_OVERFLOW);
840 
841  if (!NT_SUCCESS(Status))
842  throw ntstatus_error(Status);
843 
844  auto fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(streambuf.data());
845 
846  while (true) {
847  if (fsi->StreamNameLength > 0) {
848  wstring sn = wstring(fsi->StreamName, fsi->StreamNameLength / sizeof(WCHAR));
849 
850  if (sn != L"::$DATA" && sn.length() > 6 && sn.substr(sn.length() - 6, 6) == L":$DATA") {
852  uint8_t* data = nullptr;
853  auto stream_size = (uint16_t)fsi->StreamSize.QuadPart;
854 
855 
856  if (stream_size > 0) {
857  wstring fn2;
858 
859  fn2 = fn;
860  fn2 += sn;
861 
862  stream = CreateFileW(fn2.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
863 
865  throw last_error(GetLastError());
866 
867  // We can get away with this because our streams are guaranteed to be below 64 KB -
868  // don't do this on NTFS!
870 
871  if (!ReadFile(stream, data, stream_size, &bytesret, nullptr)) {
872  free(data);
873  throw last_error(GetLastError());
874  }
875  }
876 
877  stream = CreateFileW((newpath + sn).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, nullptr);
878 
879  if (stream == INVALID_HANDLE_VALUE) {
880  if (data) free(data);
881  throw last_error(GetLastError());
882  }
883 
884  if (data) {
885  if (!WriteFile(stream, data, stream_size, &bytesret, nullptr)) {
886  free(data);
887  throw last_error(GetLastError());
888  }
889 
890  free(data);
891  }
892  }
893  }
894 
895  if (fsi->NextEntryOffset == 0)
896  break;
897 
898  fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(reinterpret_cast<char*>(fsi) + fsi->NextEntryOffset);
899  }
900  }
901 
902  atime.dwLowDateTime = fbi.LastAccessTime.LowPart;
903  atime.dwHighDateTime = fbi.LastAccessTime.HighPart;
904  mtime.dwLowDateTime = fbi.LastWriteTime.LowPart;
905  mtime.dwHighDateTime = fbi.LastWriteTime.HighPart;
906  SetFileTime(dest, nullptr, &atime, &mtime);
907 
908  Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_XATTRS, nullptr, 0, &bsxa, sizeof(btrfs_set_xattr));
909 
910  if (Status == STATUS_BUFFER_OVERFLOW || (NT_SUCCESS(Status) && bsxa.valuelen > 0)) {
911  ULONG xalen = 0;
912  btrfs_set_xattr *xa = nullptr, *xa2;
913 
914  do {
915  xalen += 1024;
916 
917  if (xa) free(xa);
918  xa = (btrfs_set_xattr*)malloc(xalen);
919 
920  Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_XATTRS, nullptr, 0, xa, xalen);
921  } while (Status == STATUS_BUFFER_OVERFLOW);
922 
923  if (!NT_SUCCESS(Status)) {
924  free(xa);
925  throw ntstatus_error(Status);
926  }
927 
928  xa2 = xa;
929  while (xa2->valuelen > 0) {
930  Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, xa2,
931  (ULONG)(offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen), nullptr, 0);
932  if (!NT_SUCCESS(Status)) {
933  free(xa);
934  throw ntstatus_error(Status);
935  }
936  xa2 = (btrfs_set_xattr*)&xa2->data[xa2->namelen + xa2->valuelen];
937  }
938 
939  free(xa);
940  } else if (!NT_SUCCESS(Status))
941  throw ntstatus_error(Status);
942  } catch (...) {
943  FILE_DISPOSITION_INFO fdi;
944 
945  fdi.DeleteFile = true;
946  Status = NtSetInformationFile(dest, &iosb, &fdi, sizeof(FILE_DISPOSITION_INFO), FileDispositionInformation);
947  if (!NT_SUCCESS(Status))
948  throw ntstatus_error(Status);
949 
950  throw;
951  }
952 }
953 
956 
957  try {
958  if (ignore)
959  return E_INVALIDARG;
960 
961  if (!bg) {
962  if ((IS_INTRESOURCE(pici->lpVerb) && allow_snapshot && pici->lpVerb == 0) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, SNAPSHOT_VERBA))) {
963  UINT num_files, i;
964  WCHAR fn[MAX_PATH];
965 
966  if (!stgm_set)
967  return E_FAIL;
968 
969  num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, nullptr, 0);
970 
971  if (num_files == 0)
972  return E_FAIL;
973 
974  for (i = 0; i < num_files; i++) {
975  if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
976  create_snapshot(pici->hwnd, fn);
977  }
978  }
979 
980  return S_OK;
981  } else if ((IS_INTRESOURCE(pici->lpVerb) && ((allow_snapshot && (ULONG_PTR)pici->lpVerb == 1) || (!allow_snapshot && (ULONG_PTR)pici->lpVerb == 0))) ||
982  (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, SEND_VERBA))) {
983  UINT num_files, i;
985  wstring t;
986  SHELLEXECUTEINFOW sei;
987 
988  GetModuleFileNameW(module, dll, sizeof(dll) / sizeof(WCHAR));
989 
990  if (!stgm_set)
991  return E_FAIL;
992 
993  num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, nullptr, 0);
994 
995  if (num_files == 0)
996  return E_FAIL;
997 
998  for (i = 0; i < num_files; i++) {
999  if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
1000  t = L"\"";
1001  t += dll;
1002  t += L"\",SendSubvolGUI ";
1003  t += fn;
1004 
1005  RtlZeroMemory(&sei, sizeof(sei));
1006 
1007  sei.cbSize = sizeof(sei);
1008  sei.hwnd = pici->hwnd;
1009  sei.lpVerb = L"runas";
1010  sei.lpFile = L"rundll32.exe";
1011  sei.lpParameters = t.c_str();
1012  sei.nShow = SW_SHOW;
1014 
1015  if (!ShellExecuteExW(&sei))
1016  throw last_error(GetLastError());
1017 
1019  CloseHandle(sei.hProcess);
1020  }
1021  }
1022 
1023  return S_OK;
1024  }
1025  } else {
1026  if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 0) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, NEW_SUBVOL_VERBA))) {
1027  win_handle h;
1029  NTSTATUS Status;
1030  wstring name, nameorig, searchpath;
1031  btrfs_create_subvol* bcs;
1032  WIN32_FIND_DATAW wfd;
1033 
1035  throw last_error(GetLastError());
1036 
1038 
1039  if (h == INVALID_HANDLE_VALUE)
1040  throw last_error(GetLastError());
1041 
1042  searchpath = path + L"\\" + name;
1043  nameorig = name;
1044 
1045  {
1046  fff_handle fff = FindFirstFileW(searchpath.c_str(), &wfd);
1047 
1048  if (fff != INVALID_HANDLE_VALUE) {
1049  ULONG num = 2;
1050 
1051  do {
1052 #ifndef __REACTOS__
1053  name = nameorig + L" (" + to_wstring(num) + L")";
1054 #else
1055  {
1056  WCHAR buffer[32];
1057 
1058  swprintf(buffer, L"%d", num);
1059  name = nameorig + L" (" + buffer + L")";
1060  }
1061 #endif
1062  searchpath = path + L"\\" + name;
1063 
1064  fff = FindFirstFileW(searchpath.c_str(), &wfd);
1065  num++;
1066  } while (fff != INVALID_HANDLE_VALUE);
1067  }
1068  }
1069 
1070  size_t bcslen = offsetof(btrfs_create_subvol, name[0]) + (name.length() * sizeof(WCHAR));
1071  bcs = (btrfs_create_subvol*)malloc(bcslen);
1072 
1073  bcs->readonly = false;
1074  bcs->posix = false;
1075  bcs->namelen = (uint16_t)(name.length() * sizeof(WCHAR));
1076  memcpy(bcs->name, name.c_str(), name.length() * sizeof(WCHAR));
1077 
1078  Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, (ULONG)bcslen, nullptr, 0);
1079 
1080  free(bcs);
1081 
1082  if (!NT_SUCCESS(Status))
1083  throw ntstatus_error(Status);
1084 
1085  return S_OK;
1086  } else if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 1) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, RECV_VERBA))) {
1087  WCHAR dll[MAX_PATH];
1088  wstring t;
1089  SHELLEXECUTEINFOW sei;
1090 
1091  GetModuleFileNameW(module, dll, sizeof(dll) / sizeof(WCHAR));
1092 
1093  t = L"\"";
1094  t += dll;
1095  t += L"\",RecvSubvolGUI ";
1096  t += path;
1097 
1098  RtlZeroMemory(&sei, sizeof(sei));
1099 
1100  sei.cbSize = sizeof(sei);
1101  sei.hwnd = pici->hwnd;
1102  sei.lpVerb = L"runas";
1103  sei.lpFile = L"rundll32.exe";
1104  sei.lpParameters = t.c_str();
1105  sei.nShow = SW_SHOW;
1107 
1108  if (!ShellExecuteExW(&sei))
1109  throw last_error(GetLastError());
1110 
1112  CloseHandle(sei.hProcess);
1113 
1114  return S_OK;
1115  } else if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 2) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, REFLINK_VERBA))) {
1116  HDROP hdrop;
1117 
1119  return S_OK;
1120 
1121  if (!OpenClipboard(pici->hwnd))
1122  throw last_error(GetLastError());
1123 
1124  try {
1125  hdrop = (HDROP)GetClipboardData(CF_HDROP);
1126 
1127  if (hdrop) {
1128  HANDLE lh;
1129 
1130  lh = GlobalLock(hdrop);
1131 
1132  if (lh) {
1133  try {
1134  ULONG num_files, i;
1135  WCHAR fn[MAX_PATH];
1136 
1137  num_files = DragQueryFileW(hdrop, 0xFFFFFFFF, nullptr, 0);
1138 
1139  for (i = 0; i < num_files; i++) {
1140  if (DragQueryFileW(hdrop, i, fn, sizeof(fn) / sizeof(WCHAR))) {
1141  reflink_copy(pici->hwnd, fn, pici->lpDirectoryW);
1142  }
1143  }
1144  } catch (...) {
1145  GlobalUnlock(lh);
1146  throw;
1147  }
1148 
1149  GlobalUnlock(lh);
1150  }
1151  }
1152  } catch (...) {
1153  CloseClipboard();
1154  throw;
1155  }
1156 
1157  CloseClipboard();
1158 
1159  return S_OK;
1160  }
1161  }
1162  } catch (const exception& e) {
1163  error_message(pici->hwnd, e.what());
1164  }
1165 
1166  return E_FAIL;
1167 }
1168 
1170  if (ignore)
1171  return E_INVALIDARG;
1172 
1173  if (idCmd != 0)
1174  return E_INVALIDARG;
1175 
1176  if (!bg) {
1177  if (idCmd == 0) {
1178  switch (uFlags) {
1179  case GCS_HELPTEXTA:
1181  return S_OK;
1182  else
1183  return E_FAIL;
1184 
1185  case GCS_HELPTEXTW:
1187  return S_OK;
1188  else
1189  return E_FAIL;
1190 
1191  case GCS_VALIDATEA:
1192  case GCS_VALIDATEW:
1193  return S_OK;
1194 
1195  case GCS_VERBA:
1196  return StringCchCopyA(pszName, cchMax, SNAPSHOT_VERBA);
1197 
1198  case GCS_VERBW:
1200 
1201  default:
1202  return E_INVALIDARG;
1203  }
1204  } else if (idCmd == 1) {
1205  switch (uFlags) {
1206  case GCS_HELPTEXTA:
1208  return S_OK;
1209  else
1210  return E_FAIL;
1211 
1212  case GCS_HELPTEXTW:
1214  return S_OK;
1215  else
1216  return E_FAIL;
1217 
1218  case GCS_VALIDATEA:
1219  case GCS_VALIDATEW:
1220  return S_OK;
1221 
1222  case GCS_VERBA:
1223  return StringCchCopyA(pszName, cchMax, SEND_VERBA);
1224 
1225  case GCS_VERBW:
1226  return StringCchCopyW((STRSAFE_LPWSTR)pszName, cchMax, SEND_VERBW);
1227 
1228  default:
1229  return E_INVALIDARG;
1230  }
1231  } else
1232  return E_INVALIDARG;
1233  } else {
1234  if (idCmd == 0) {
1235  switch (uFlags) {
1236  case GCS_HELPTEXTA:
1238  return S_OK;
1239  else
1240  return E_FAIL;
1241 
1242  case GCS_HELPTEXTW:
1244  return S_OK;
1245  else
1246  return E_FAIL;
1247 
1248  case GCS_VALIDATEA:
1249  case GCS_VALIDATEW:
1250  return S_OK;
1251 
1252  case GCS_VERBA:
1253  return StringCchCopyA(pszName, cchMax, NEW_SUBVOL_VERBA);
1254 
1255  case GCS_VERBW:
1257 
1258  default:
1259  return E_INVALIDARG;
1260  }
1261  } else if (idCmd == 1) {
1262  switch (uFlags) {
1263  case GCS_HELPTEXTA:
1265  return S_OK;
1266  else
1267  return E_FAIL;
1268 
1269  case GCS_HELPTEXTW:
1271  return S_OK;
1272  else
1273  return E_FAIL;
1274 
1275  case GCS_VALIDATEA:
1276  case GCS_VALIDATEW:
1277  return S_OK;
1278 
1279  case GCS_VERBA:
1280  return StringCchCopyA(pszName, cchMax, RECV_VERBA);
1281 
1282  case GCS_VERBW:
1283  return StringCchCopyW((STRSAFE_LPWSTR)pszName, cchMax, RECV_VERBW);
1284 
1285  default:
1286  return E_INVALIDARG;
1287  }
1288  } else if (idCmd == 2) {
1289  switch (uFlags) {
1290  case GCS_HELPTEXTA:
1292  return S_OK;
1293  else
1294  return E_FAIL;
1295 
1296  case GCS_HELPTEXTW:
1298  return S_OK;
1299  else
1300  return E_FAIL;
1301 
1302  case GCS_VALIDATEA:
1303  case GCS_VALIDATEW:
1304  return S_OK;
1305 
1306  case GCS_VERBA:
1307  return StringCchCopyA(pszName, cchMax, REFLINK_VERBA);
1308 
1309  case GCS_VERBW:
1311 
1312  default:
1313  return E_INVALIDARG;
1314  }
1315  } else
1316  return E_INVALIDARG;
1317  }
1318 }
1319 
1320 static void reflink_copy2(const wstring& srcfn, const wstring& destdir, const wstring& destname) {
1322  FILE_BASIC_INFO fbi;
1323  FILETIME atime, mtime;
1324  btrfs_inode_info bii;
1325  btrfs_set_inode_info bsii;
1326  ULONG bytesret;
1327  NTSTATUS Status;
1329  btrfs_set_xattr bsxa;
1330 
1333  throw last_error(GetLastError());
1334 
1335  Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_INODE_INFO, nullptr, 0, &bii, sizeof(btrfs_inode_info));
1336  if (!NT_SUCCESS(Status))
1337  throw ntstatus_error(Status);
1338 
1339  // if subvol, do snapshot instead
1340  if (bii.inode == SUBVOL_ROOT_INODE) {
1341  btrfs_create_snapshot* bcs;
1342  win_handle dirh;
1343 
1345  if (dirh == INVALID_HANDLE_VALUE)
1346  throw last_error(GetLastError());
1347 
1348  size_t bcslen = offsetof(btrfs_create_snapshot, name[0]) + (destname.length() * sizeof(WCHAR));
1349  bcs = (btrfs_create_snapshot*)malloc(bcslen);
1350  bcs->subvol = source;
1351  bcs->namelen = (uint16_t)(destname.length() * sizeof(WCHAR));
1352  memcpy(bcs->name, destname.c_str(), destname.length() * sizeof(WCHAR));
1353 
1354  Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, (ULONG)bcslen, nullptr, 0);
1355  if (!NT_SUCCESS(Status)) {
1356  free(bcs);
1357  throw ntstatus_error(Status);
1358  }
1359 
1360  free(bcs);
1361 
1362  return;
1363  }
1364 
1365  Status = NtQueryInformationFile(source, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation);
1366  if (!NT_SUCCESS(Status))
1367  throw ntstatus_error(Status);
1368 
1369  if (bii.type == BTRFS_TYPE_CHARDEV || bii.type == BTRFS_TYPE_BLOCKDEV || bii.type == BTRFS_TYPE_FIFO || bii.type == BTRFS_TYPE_SOCKET) {
1370  win_handle dirh;
1371  btrfs_mknod* bmn;
1372 
1374  if (dirh == INVALID_HANDLE_VALUE)
1375  throw last_error(GetLastError());
1376 
1377  size_t bmnsize = offsetof(btrfs_mknod, name[0]) + (destname.length() * sizeof(WCHAR));
1378  bmn = (btrfs_mknod*)malloc(bmnsize);
1379 
1380  bmn->inode = 0;
1381  bmn->type = bii.type;
1382  bmn->st_rdev = bii.st_rdev;
1383  bmn->namelen = (uint16_t)(destname.length() * sizeof(WCHAR));
1384  memcpy(bmn->name, destname.c_str(), bmn->namelen);
1385 
1386  Status = NtFsControlFile(dirh, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, (ULONG)bmnsize, nullptr, 0);
1387  if (!NT_SUCCESS(Status)) {
1388  free(bmn);
1389  throw ntstatus_error(Status);
1390  }
1391 
1392  free(bmn);
1393 
1394  dest = CreateFileW((destdir + destname).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
1395  } else if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1396  if (CreateDirectoryExW(srcfn.c_str(), (destdir + destname).c_str(), nullptr))
1398  nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
1399  else
1401  } else
1402  dest = CreateFileW((destdir + destname).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, source);
1403 
1404  if (dest == INVALID_HANDLE_VALUE)
1405  throw last_error(GetLastError());
1406 
1407  memset(&bsii, 0, sizeof(btrfs_set_inode_info));
1408 
1409  bsii.flags_changed = true;
1410  bsii.flags = bii.flags;
1411 
1412  if (bii.flags & BTRFS_INODE_COMPRESS) {
1413  bsii.compression_type_changed = true;
1415  }
1416 
1417  try {
1418  Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), nullptr, 0);
1419  if (!NT_SUCCESS(Status))
1420  throw ntstatus_error(Status);
1421 
1422  if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1423  if (!(fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
1424  WIN32_FIND_DATAW fff;
1425  wstring qs;
1426 
1427  qs = srcfn;
1428  qs += L"\\*";
1429 
1430  fff_handle h = FindFirstFileW(qs.c_str(), &fff);
1431  if (h != INVALID_HANDLE_VALUE) {
1432  do {
1433  wstring fn2;
1434 
1435  if (fff.cFileName[0] == '.' && (fff.cFileName[1] == 0 || (fff.cFileName[1] == '.' && fff.cFileName[2] == 0)))
1436  continue;
1437 
1438  fn2 = srcfn;
1439  fn2 += L"\\";
1440  fn2 += fff.cFileName;
1441 
1442  reflink_copy2(fn2, destdir + destname + L"\\", fff.cFileName);
1443  } while (FindNextFileW(h, &fff));
1444  }
1445  }
1446 
1447  // CreateDirectoryExW also copies streams, no need to do it here
1448  } else {
1449  if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1450  reparse_header rh;
1451  uint8_t* rp;
1452 
1453  if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, &rh, sizeof(reparse_header), &bytesret, nullptr)) {
1454  if (GetLastError() != ERROR_MORE_DATA)
1455  throw last_error(GetLastError());
1456  }
1457 
1458  size_t rplen = sizeof(reparse_header) + rh.ReparseDataLength;
1459  rp = (uint8_t*)malloc(rplen);
1460 
1461  try {
1462  if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, nullptr, 0, rp, (DWORD)rplen, &bytesret, nullptr))
1463  throw last_error(GetLastError());
1464 
1465  if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, (DWORD)rplen, nullptr, 0, &bytesret, nullptr))
1466  throw last_error(GetLastError());
1467  } catch (...) {
1468  free(rp);
1469  throw;
1470  }
1471 
1472  free(rp);
1473  } else {
1474  FILE_STANDARD_INFO fsi;
1475  FILE_END_OF_FILE_INFO feofi;
1479  uint64_t offset, alloc_size;
1480  ULONG maxdup;
1481 
1482  Status = NtQueryInformationFile(source, &iosb, &fsi, sizeof(FILE_STANDARD_INFO), FileStandardInformation);
1483  if (!NT_SUCCESS(Status))
1484  throw ntstatus_error(Status);
1485 
1486  if (!DeviceIoControl(source, FSCTL_GET_INTEGRITY_INFORMATION, nullptr, 0, &fgiib, sizeof(FSCTL_GET_INTEGRITY_INFORMATION_BUFFER), &bytesret, nullptr))
1487  throw last_error(GetLastError());
1488 
1489  if (fbi.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) {
1490  if (!DeviceIoControl(dest, FSCTL_SET_SPARSE, nullptr, 0, nullptr, 0, &bytesret, nullptr))
1491  throw last_error(GetLastError());
1492  }
1493 
1494  fsiib.ChecksumAlgorithm = fgiib.ChecksumAlgorithm;
1495  fsiib.Reserved = 0;
1496  fsiib.Flags = fgiib.Flags;
1497  if (!DeviceIoControl(dest, FSCTL_SET_INTEGRITY_INFORMATION, &fsiib, sizeof(FSCTL_SET_INTEGRITY_INFORMATION_BUFFER), nullptr, 0, &bytesret, nullptr))
1498  throw last_error(GetLastError());
1499 
1500  feofi.EndOfFile = fsi.EndOfFile;
1501  Status = NtSetInformationFile(dest, &iosb, &feofi, sizeof(FILE_END_OF_FILE_INFO), FileEndOfFileInformation);
1502  if (!NT_SUCCESS(Status))
1503  throw ntstatus_error(Status);
1504 
1505  ded.FileHandle = source;
1506  maxdup = 0xffffffff - fgiib.ClusterSizeInBytes + 1;
1507 
1508  alloc_size = sector_align(fsi.EndOfFile.QuadPart, fgiib.ClusterSizeInBytes);
1509 
1510  offset = 0;
1511  while (offset < alloc_size) {
1513  ded.ByteCount.QuadPart = maxdup < (alloc_size - offset) ? maxdup : (alloc_size - offset);
1514  if (!DeviceIoControl(dest, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &ded, sizeof(DUPLICATE_EXTENTS_DATA), nullptr, 0, &bytesret, nullptr))
1515  throw last_error(GetLastError());
1516 
1517  offset += ded.ByteCount.QuadPart;
1518  }
1519  }
1520 
1521  ULONG streambufsize = 0;
1522  vector<char> streambuf;
1523 
1524  do {
1525  streambufsize += 0x1000;
1526  streambuf.resize(streambufsize);
1527 
1528  memset(streambuf.data(), 0, streambufsize);
1529 
1531  } while (Status == STATUS_BUFFER_OVERFLOW);
1532 
1533  if (!NT_SUCCESS(Status))
1534  throw ntstatus_error(Status);
1535 
1536  auto fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(streambuf.data());
1537 
1538  while (true) {
1539  if (fsi->StreamNameLength > 0) {
1540  wstring sn = wstring(fsi->StreamName, fsi->StreamNameLength / sizeof(WCHAR));
1541 
1542  if (sn != L"::$DATA" && sn.length() > 6 && sn.substr(sn.length() - 6, 6) == L":$DATA") {
1544  uint8_t* data = nullptr;
1545  auto stream_size = (uint16_t)fsi->StreamSize.QuadPart;
1546 
1547  if (stream_size > 0) {
1548  wstring fn2;
1549 
1550  fn2 = srcfn;
1551  fn2 += sn;
1552 
1553  stream = CreateFileW(fn2.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
1554 
1556  throw last_error(GetLastError());
1557 
1558  // We can get away with this because our streams are guaranteed to be below 64 KB -
1559  // don't do this on NTFS!
1561 
1562  if (!ReadFile(stream, data, stream_size, &bytesret, nullptr)) {
1563  free(data);
1564  throw last_error(GetLastError());
1565  }
1566  }
1567 
1568  stream = CreateFileW((destdir + destname + sn).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_NEW, 0, nullptr);
1569 
1570  if (stream == INVALID_HANDLE_VALUE) {
1571  if (data) free(data);
1572  throw last_error(GetLastError());
1573  }
1574 
1575  if (data) {
1576  if (!WriteFile(stream, data, stream_size, &bytesret, nullptr)) {
1577  free(data);
1578  throw last_error(GetLastError());
1579  }
1580 
1581  free(data);
1582  }
1583  }
1584 
1585  }
1586 
1587  if (fsi->NextEntryOffset == 0)
1588  break;
1589 
1590  fsi = reinterpret_cast<FILE_STREAM_INFORMATION*>(reinterpret_cast<char*>(fsi) + fsi->NextEntryOffset);
1591  }
1592  }
1593 
1594  atime.dwLowDateTime = fbi.LastAccessTime.LowPart;
1595  atime.dwHighDateTime = fbi.LastAccessTime.HighPart;
1596  mtime.dwLowDateTime = fbi.LastWriteTime.LowPart;
1597  mtime.dwHighDateTime = fbi.LastWriteTime.HighPart;
1598  SetFileTime(dest, nullptr, &atime, &mtime);
1599 
1600  Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_XATTRS, nullptr, 0, &bsxa, sizeof(btrfs_set_xattr));
1601 
1602  if (Status == STATUS_BUFFER_OVERFLOW || (NT_SUCCESS(Status) && bsxa.valuelen > 0)) {
1603  ULONG xalen = 0;
1604  btrfs_set_xattr *xa = nullptr, *xa2;
1605 
1606  do {
1607  xalen += 1024;
1608 
1609  if (xa) free(xa);
1610  xa = (btrfs_set_xattr*)malloc(xalen);
1611 
1612  Status = NtFsControlFile(source, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_GET_XATTRS, nullptr, 0, xa, xalen);
1613  } while (Status == STATUS_BUFFER_OVERFLOW);
1614 
1615  if (!NT_SUCCESS(Status)) {
1616  free(xa);
1617  throw ntstatus_error(Status);
1618  }
1619 
1620  xa2 = xa;
1621  while (xa2->valuelen > 0) {
1622  Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, xa2,
1623  (ULONG)(offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen), nullptr, 0);
1624  if (!NT_SUCCESS(Status)) {
1625  free(xa);
1626  throw ntstatus_error(Status);
1627  }
1628  xa2 = (btrfs_set_xattr*)&xa2->data[xa2->namelen + xa2->valuelen];
1629  }
1630 
1631  free(xa);
1632  } else if (!NT_SUCCESS(Status))
1633  throw ntstatus_error(Status);
1634  } catch (...) {
1635  FILE_DISPOSITION_INFO fdi;
1636 
1637  fdi.DeleteFile = true;
1638  Status = NtSetInformationFile(dest, &iosb, &fdi, sizeof(FILE_DISPOSITION_INFO), FileDispositionInformation);
1639  if (!NT_SUCCESS(Status))
1640  throw ntstatus_error(Status);
1641 
1642  throw;
1643  }
1644 }
1645 
1646 #ifdef __REACTOS__
1647 extern "C" {
1648 #endif
1649 
1650 void CALLBACK ReflinkCopyW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
1652 
1653  command_line_to_args(lpszCmdLine, args);
1654 
1655  if (args.size() >= 2) {
1656  bool dest_is_dir = false;
1657  wstring dest = args[args.size() - 1], destdir, destname;
1658  WCHAR volpath2[MAX_PATH];
1659 
1660  {
1662  nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
1663 
1664  if (destdirh != INVALID_HANDLE_VALUE) {
1666 
1667  if (GetFileInformationByHandle(destdirh, &bhfi) && bhfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1668  dest_is_dir = true;
1669 
1670  destdir = dest;
1671  if (destdir.substr(destdir.length() - 1, 1) != L"\\")
1672  destdir += L"\\";
1673  }
1674  }
1675  }
1676 
1677  if (!dest_is_dir) {
1678  size_t found = dest.rfind(L"\\");
1679 
1680  if (found == wstring::npos) {
1681  destdir = L"";
1682  destname = dest;
1683  } else {
1684  destdir = dest.substr(0, found);
1685  destname = dest.substr(found + 1);
1686  }
1687  }
1688 
1689  if (!GetVolumePathNameW(dest.c_str(), volpath2, sizeof(volpath2) / sizeof(WCHAR)))
1690  return;
1691 
1692  for (unsigned int i = 0; i < args.size() - 1; i++) {
1693  WIN32_FIND_DATAW ffd;
1694 
1695  fff_handle h = FindFirstFileW(args[i].c_str(), &ffd);
1696  if (h != INVALID_HANDLE_VALUE) {
1697  WCHAR volpath1[MAX_PATH];
1698  wstring path = args[i];
1699  size_t found = path.rfind(L"\\");
1700 
1701  if (found == wstring::npos)
1702  path = L"";
1703  else
1704  path = path.substr(0, found);
1705 
1706  path += L"\\";
1707 
1708  if (get_volume_path_parent(path.c_str(), volpath1, sizeof(volpath1) / sizeof(WCHAR))) {
1709  if (!wcscmp(volpath1, volpath2)) {
1710  do {
1711  try {
1712  reflink_copy2(path + ffd.cFileName, destdir, dest_is_dir ? ffd.cFileName : destname);
1713  } catch (const exception& e) {
1714  cerr << "Error: " << e.what() << endl;
1715  }
1716  } while (FindNextFileW(h, &ffd));
1717  }
1718  }
1719  }
1720  }
1721  }
1722 }
1723 
1724 #ifdef __REACTOS__
1725 } /* extern "C" */
1726 #endif
#define FSCTL_SET_SPARSE
Definition: winioctl.h:100
static short search(int val, const short *table, int size)
Definition: msg711.c:255
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:609
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
static PIO_STATUS_BLOCK iosb
Definition: file.c:98
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
uint16_t namelen
Definition: btrfsioctl.h:239
#define ERROR_FILE_EXISTS
Definition: winerror.h:165
static HICON
Definition: imagelist.c:84
#define REFIID
Definition: guiddef.h:118
#define CloseHandle
Definition: compat.h:406
ULONG __stdcall AddRef()
Definition: contextmenu.h:51
#define E_NOINTERFACE
Definition: winerror.h:2364
#define IMAGE_ICON
Definition: winuser.h:212
NTSTATUS NTAPI NtSetInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS FileInformationClass)
#define FILE_ATTRIBUTE_SPARSE_FILE
Definition: ntifs_ex.h:380
BOOL WINAPI IsClipboardFormatAvailable(_In_ UINT)
_Must_inspect_result_ _Out_ LPSIZE psize
Definition: ntgdi.h:1569
BITMAPINFOHEADER bmiHeader
Definition: wingdi.h:1475
#define BTRFS_TYPE_SOCKET
Definition: shellext.h:90
HRESULT hr
Definition: shlfolder.c:183
static HMENU hmenu
Definition: win.c:66
virtual HRESULT __stdcall QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
BOOL WINAPI InsertMenuW(_In_ HMENU, _In_ UINT, _In_ UINT, _In_ UINT_PTR, _In_opt_ LPCWSTR)
#define SEND_VERBW
Definition: contextmenu.cpp:58
uint8_t compression_type
Definition: btrfsioctl.h:97
void WINAPI ReleaseStgMedium(STGMEDIUM *pmedium)
Definition: ole2.c:2033
HDC WINAPI GetDC(_In_opt_ HWND)
#define NEW_SUBVOL_VERBW
Definition: contextmenu.cpp:50
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
static GLenum _GLUfuncptr fn
Definition: wgl_font.c:159
#define SEE_MASK_NOCLOSEPROCESS
Definition: shellapi.h:31
virtual HRESULT __stdcall GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
#define BTRFS_TYPE_BLOCKDEV
Definition: shellext.h:88
REFIID riid
Definition: precomp.h:44
_In_ HBITMAP _In_ UINT _In_ UINT _Inout_ LPBITMAPINFO pbmi
Definition: ntgdi.h:2780
#define SUBVOL_ROOT_INODE
Definition: propsheet.cpp:42
struct tagBITMAPINFOHEADER BITMAPINFOHEADER
#define free
Definition: debug_ros.c:5
int WINAPI LoadStringA(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPSTR lpBuffer, _In_ int cchBufferMax)
#define IDS_SNAPSHOT_FILENAME
Definition: resource.h:14
LONG NTSTATUS
Definition: precomp.h:26
#define BTRFS_TYPE_FIFO
Definition: shellext.h:89
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1280
static HDC
Definition: imagelist.c:92
GLintptr offset
Definition: glext.h:5920
#define CALLBACK
Definition: compat.h:27
static const size_t npos
Definition: _string_npos.h:26
static void create_snapshot(HWND hwnd, const wstring &fn)
GLdouble n
Definition: glext.h:7729
GLdouble GLdouble t
Definition: gl.h:2047
#define INVALID_HANDLE_VALUE
Definition: compat.h:399
HRESULT GetData([in, unique] FORMATETC *pformatetcIn, [out] STGMEDIUM *pmedium)
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1642
GLuint buffer
Definition: glext.h:5915
#define SM_CYSMICON
Definition: winuser.h:1003
#define RECV_VERBW
Definition: contextmenu.cpp:56
LPWSTR dwTypeData
Definition: winuser.h:3244
NTSYSCALLAPI NTSTATUS NTAPI NtFsControlFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG FsControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength)
BOOL WINAPI GetVolumePathNameW(IN LPCWSTR lpszFileName, IN LPWSTR lpszVolumePathName, IN DWORD cchBufferLength)
Definition: volume.c:815
wchar_t * STRSAFE_LPWSTR
Definition: ntstrsafe.h:53
__u16 time
Definition: mkdosfs.c:366
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
UINT uFlags
Definition: api.c:59
#define uint16_t
Definition: nsiface.idl:60
#define BTRFS_TYPE_CHARDEV
Definition: shellext.h:87
#define FSCTL_GET_REPARSE_POINT
Definition: winioctl.h:97
char * LPSTR
Definition: xmlstorage.h:182
#define E_FAIL
Definition: ddrawi.h:102
GLint namelen
Definition: glext.h:7232
Definition: match.c:390
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
void reflink_copy(HWND hwnd, const WCHAR *fn, const WCHAR *dir)
#define IDS_RECV_SUBVOL_HELP
Definition: resource.h:131
#define MIIM_BITMAP
Definition: winuser.h:723
#define SEVERITY_SUCCESS
Definition: winerror.h:64
#define SEND_VERBA
Definition: contextmenu.cpp:57
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
#define FILE_SHARE_READ
Definition: compat.h:125
#define SNAPSHOT_VERBA
Definition: contextmenu.cpp:51
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
virtual HRESULT __stdcall InvokeCommand(LPCMINVOKECOMMANDINFO pici)
BOOL WINAPI SetFileTime(IN HANDLE hFile, CONST FILETIME *lpCreationTime OPTIONAL, CONST FILETIME *lpLastAccessTime OPTIONAL, CONST FILETIME *lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:1098
uint32_t ULONG_PTR
Definition: typedefs.h:63
static HMODULE dll
Definition: str.c:188
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
#define FILE_TRAVERSE
Definition: nt_native.h:643
DWORD dwHighDateTime
Definition: mapidefs.h:66
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
void error_message(HWND hwnd, const char *msg)
Definition: main.cpp:785
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
basic_ostream< _CharT, _Traits > &_STLP_CALL endl(basic_ostream< _CharT, _Traits > &__os)
Definition: _ostream.h:357
#define FILE_ADD_FILE
Definition: nt_native.h:632
#define IDS_SEND_SUBVOL_HELP
Definition: resource.h:175
#define FSCTL_BTRFS_CREATE_SNAPSHOT
Definition: btrfsioctl.h:9
HANDLE WINAPI LoadImageW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_ UINT, _In_ int, _In_ int, _In_ UINT)
Definition: cursoricon.c:2172
#define BTRFS_INODE_COMPRESS
Definition: propsheet.h:87
long LONG
Definition: pedump.c:60
Definition: main.c:438
#define a
Definition: ke_i.h:78
#define e
Definition: ke_i.h:82
#define MF_BYPOSITION
Definition: winuser.h:203
#define GENERIC_WRITE
Definition: nt_native.h:90
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
int length
Definition: match.c:394
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
DWORD biCompression
Definition: amvideo.idl:35
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:581
#define IDS_NEW_SUBVOL_HELP_TEXT
Definition: resource.h:6
#define E_INVALIDARG
Definition: ddrawi.h:101
const WCHAR * str
#define offsetof(TYPE, MEMBER)
char ext[3]
Definition: mkdosfs.c:358
#define CF_HDROP
Definition: constants.h:410
LONG cx
Definition: windef.h:334
LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
Definition: path.c:389
#define IDS_CREATE_SNAPSHOT
Definition: resource.h:10
int const char int stream_size
Definition: zlib.h:813
#define RECV_VERBA
Definition: contextmenu.cpp:55
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:2235
uint64_t st_rdev
Definition: btrfsioctl.h:76
VOID WINAPI GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:286
unsigned int dir
Definition: maze.c:112
#define SW_SHOW
Definition: winuser.h:769
#define MAKE_HRESULT(sev, fac, code)
Definition: dmerror.h:30
LPWSTR WINAPI PathFindExtensionW(LPCWSTR lpszPath)
Definition: path.c:442
#define FILE_ATTRIBUTE_REPARSE_POINT
Definition: ntifs_ex.h:381
#define OPEN_EXISTING
Definition: compat.h:434
USHORT ReparseDataLength
Definition: contextmenu.cpp:62
#define b
Definition: ke_i.h:79
#define FSCTL_BTRFS_CREATE_SUBVOL
Definition: btrfsioctl.h:8
#define MIIM_ID
Definition: winuser.h:717
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define IDS_REFLINK_PASTE_HELP
Definition: resource.h:129
STGMEDIUM stgm
Definition: contextmenu.h:79
void wstring_sprintf(wstring &s, wstring fmt,...)
Definition: main.cpp:225
static HRESULT Create32BitHBITMAP(HDC hdc, const SIZE *psize, void **ppvBits, HBITMAP *phBmp)
Definition: uimain.c:88
LARGE_INTEGER SourceFileOffset
Definition: shellext.h:200
GLfloat f
Definition: glext.h:7540
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLsizei stride
Definition: glext.h:5848
#define IS_INTRESOURCE(i)
Definition: winuser.h:580
BOOL WINAPI GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
Definition: fileinfo.c:608
if(!(yy_init))
Definition: macro.lex.yy.c:714
static bool show_reflink_paste(const wstring &path)
virtual HRESULT __stdcall Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
Definition: contextmenu.cpp:85
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
_STLP_DECLSPEC _Stl_aligned_buffer< ostream > cerr
Definition: iostream.cpp:102
static bool get_volume_path_parent(const WCHAR *fn, WCHAR *volpath, ULONG volpathlen)
LONG HRESULT
Definition: typedefs.h:77
const GUID IID_IUnknown
#define REFLINK_VERBA
Definition: contextmenu.cpp:53
#define MAX_PATH
Definition: compat.h:26
#define swprintf(buf, format,...)
Definition: sprintf.c:56
unsigned short WORD
Definition: ntddk_ex.h:93
int WINAPI GetSystemMetrics(_In_ int)
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint num
Definition: glext.h:9618
#define FSCTL_BTRFS_GET_XATTRS
Definition: btrfsioctl.h:32
#define __stdcall
Definition: typedefs.h:25
uint64_t flags
Definition: btrfsioctl.h:77
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
UINT cchMax
BOOL compression_type_changed
Definition: btrfsioctl.h:98
BOOL WINAPI CloseClipboard(void)
Definition: ntwrapper.h:178
#define SM_CXSMICON
Definition: winuser.h:1002
#define IDS_RECV_SUBVOL
Definition: resource.h:130
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
static const WCHAR L[]
Definition: oid.c:1250
LPVOID NTAPI GlobalLock(HGLOBAL hMem)
Definition: heapmem.c:755
#define FSCTL_BTRFS_MKNOD
Definition: btrfsioctl.h:30
Definition: parse.h:22
#define SNAPSHOT_VERBW
Definition: contextmenu.cpp:52
HDC hdc
Definition: main.c:9
GLuint GLuint stream
Definition: glext.h:7522
uint64_t inode
Definition: btrfsioctl.h:70
#define FILE_ADD_SUBDIRECTORY
Definition: nt_native.h:635
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
unsigned char BYTE
Definition: mem.h:68
#define FSCTL_BTRFS_GET_FILE_IDS
Definition: btrfsioctl.h:7
#define IDS_SEND_SUBVOL
Definition: resource.h:174
#define GENERIC_READ
Definition: compat.h:124
NTSTATUS NTAPI NtQueryInformationFile(HANDLE hFile, PIO_STATUS_BLOCK io, PVOID ptr, ULONG len, FILE_INFORMATION_CLASS FileInformationClass)
#define FSCTL_BTRFS_SET_INODE_INFO
Definition: btrfsioctl.h:11
#define ERROR_MORE_DATA
Definition: dderror.h:13
BYTE uint8_t
Definition: msvideo1.c:66
Status
Definition: gdiplustypes.h:24
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID iid, LPVOID *ppv)
Definition: compobj.c:3325
uint64_t st_rdev
Definition: btrfsioctl.h:238
uint8_t type
Definition: btrfsioctl.h:237
static void path_remove_file(wstring &path)
#define MIIM_STRING
Definition: winuser.h:722
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
STRSAFEAPI StringCchCopyA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:145
#define NEW_SUBVOL_VERBA
Definition: contextmenu.cpp:49
#define S_OK
Definition: intsafe.h:59
struct IContextMenu::tagCMInvokeCommandInfoEx * LPCMINVOKECOMMANDINFOEX
UINT64 uint64_t
Definition: types.h:77
BOOL WINAPI DeviceIoControl(IN HANDLE hDevice, IN DWORD dwIoControlCode, IN LPVOID lpInBuffer OPTIONAL, IN DWORD nInBufferSize OPTIONAL, OUT LPVOID lpOutBuffer OPTIONAL, IN DWORD nOutBufferSize OPTIONAL, OUT LPDWORD lpBytesReturned OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: deviceio.c:136
#define STATUS_BUFFER_OVERFLOW
Definition: shellext.h:66
unsigned short USHORT
Definition: pedump.c:61
GLsizei GLsizei GLchar * source
Definition: glext.h:6048
LPCWSTR lpParameters
Definition: shellapi.h:331
#define FSCTL_BTRFS_GET_INODE_INFO
Definition: btrfsioctl.h:10
#define f
Definition: ke_i.h:83
HBITMAP WINAPI CreateDIBSection(HDC hDC, CONST BITMAPINFO *BitmapInfo, UINT Usage, VOID **Bits, HANDLE hSection, DWORD dwOffset)
Definition: bitmap.c:197
void command_line_to_args(LPWSTR cmdline, vector< wstring > &args)
Definition: main.cpp:647
static void path_strip_path(wstring &path)
BOOL WINAPI InsertMenuItemW(_In_ HMENU, _In_ UINT, _In_ BOOL, _In_ LPCMENUITEMINFOW)
BOOL WINAPI CreateDirectoryExW(IN LPCWSTR lpTemplateDirectory, IN LPCWSTR lpNewDirectory, IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: dir.c:193
unsigned int UINT
Definition: ndis.h:50
BOOL NTAPI GlobalUnlock(HGLOBAL hMem)
Definition: heapmem.c:1190
LARGE_INTEGER TargetFileOffset
Definition: shellext.h:201
void CALLBACK ReflinkCopyW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
static int load_string(HINSTANCE hModule, UINT resId, LPWSTR pwszBuffer, INT cMaxChars)
Definition: muireg.c:10
static void InitBitmapInfo(BITMAPINFO *pbmi, ULONG cbInfo, LONG cx, LONG cy, WORD bpp)
HANDLE WINAPI GetClipboardData(_In_ UINT)
#define IDS_CANT_REFLINK_DIFFERENT_FS
Definition: resource.h:202
#define FileStandardInformation
Definition: propsheet.cpp:61
#define CreateFileW
Definition: compat.h:408
#define FSCTL_GET_INTEGRITY_INFORMATION
Definition: shellext.h:221
_Out_opt_ int * cx
Definition: commctrl.h:581
uint64_t inode
Definition: btrfsioctl.h:236
Definition: name.c:38
#define REFLINK_VERBW
Definition: contextmenu.cpp:54
#define FILE_FLAG_BACKUP_SEMANTICS
Definition: disk.h:41
static void reflink_copy2(const wstring &srcfn, const wstring &destdir, const wstring &destname)
WCHAR name[1]
Definition: btrfsioctl.h:240
#define IDS_NEW_SUBVOL
Definition: resource.h:7
uint8_t compression_type
Definition: btrfsioctl.h:82
#define FSCTL_BTRFS_SET_XATTR
Definition: btrfsioctl.h:33
unsigned int ULONG
Definition: retypes.h:1
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:847
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
static HINSTANCE hinst
Definition: edit.c:551
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
basic_streambuf< char, char_traits< char > > streambuf
Definition: _iosfwd.h:123
#define malloc
Definition: debug_ros.c:4
DWORD bpp
Definition: surface.c:181
static HBITMAP bitmap
Definition: clipboard.c:1344
static char * dest
Definition: rtl.c:135
#define FSCTL_SET_INTEGRITY_INFORMATION
Definition: shellext.h:222
HRESULT __stdcall QueryInterface(REFIID riid, void **ppObj)
Definition: contextmenu.cpp:70
#define IDS_NEW_SUBVOL_FILENAME
Definition: resource.h:9
#define CREATE_NEW
Definition: disk.h:69
static HBITMAP
Definition: button.c:44
BOOL WINAPI OpenClipboard(_In_opt_ HWND)
#define MAKEINTRESOURCEW(i)
Definition: winuser.h:582
#define FSCTL_SET_REPARSE_POINT
Definition: winioctl.h:98
#define ERROR_ALREADY_EXISTS
Definition: disk.h:80
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define DIB_RGB_COLORS
Definition: wingdi.h:366
#define ss
Definition: i386-dis.c:432
#define INFINITE
Definition: serial.h:102
static struct msdos_boot_sector bs
Definition: mkdosfs.c:539
#define LR_DEFAULTCOLOR
Definition: winuser.h:1077
BOOL WINAPI ReadFile(IN HANDLE hFile, IN LPVOID lpBuffer, IN DWORD nNumberOfBytesToRead, OUT LPDWORD lpNumberOfBytesRead OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:123
#define memset(x, y, z)
Definition: compat.h:39
#define args
Definition: format.c:66
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:60
UINT WINAPI DragQueryFileW(HDROP hDrop, UINT lFile, LPWSTR lpszwFile, UINT lLength)
Definition: shellole.c:627
LONG cy
Definition: windef.h:335
#define FILE_OPEN_REPARSE_POINT
Definition: from_kernel.h:46
#define BI_RGB
Definition: precomp.h:34
static uint64_t __inline sector_align(uint64_t n, uint64_t a)
#define IDS_REFLINK_PASTE
Definition: resource.h:128
LARGE_INTEGER ByteCount
Definition: shellext.h:202
struct tagMENUITEMINFOW MENUITEMINFOW
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
DWORD dwLowDateTime
Definition: mapidefs.h:65
#define SUCCEEDED(hr)
Definition: intsafe.h:57
#define IDS_CREATE_SNAPSHOT_HELP_TEXT
Definition: resource.h:12
#define DELETE
Definition: nt_native.h:57
LONGLONG QuadPart
Definition: typedefs.h:112
#define FSCTL_DUPLICATE_EXTENTS_TO_FILE
Definition: shellext.h:205
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
GLuint const GLchar * name
Definition: glext.h:6031