ReactOS  r75907
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 #ifndef __REACTOS__
19 #define UNICODE
20 #endif
21 #include "shellext.h"
22 #ifndef __REACTOS__
23 #include <windows.h>
24 #include <strsafe.h>
25 #include <stddef.h>
26 #include <winternl.h>
27 #else
28 #define WIN32_NO_STATUS
29 #include <windef.h>
30 #include <winbase.h>
31 #include <strsafe.h>
32 #include <shellapi.h>
33 #include <winioctl.h>
34 #include <ndk/iofuncs.h>
35 #undef DeleteFile
36 #endif
37 #include <wincodec.h>
38 #include <string>
39 #include <sstream>
40 
41 #define NO_SHLWAPI_STRFCNS
42 #include <shlwapi.h>
43 
44 #include "contextmenu.h"
45 #include "resource.h"
46 #ifndef __REACTOS__
47 #include "../btrfsioctl.h"
48 #else
49 #include "btrfsioctl.h"
50 #endif
51 
52 #define NEW_SUBVOL_VERBA "newsubvol"
53 #define NEW_SUBVOL_VERBW L"newsubvol"
54 #define SNAPSHOT_VERBA "snapshot"
55 #define SNAPSHOT_VERBW L"snapshot"
56 #define REFLINK_VERBA "reflink"
57 #define REFLINK_VERBW L"reflink"
58 #define RECV_VERBA "recvsubvol"
59 #define RECV_VERBW L"recvsubvol"
60 #define SEND_VERBA "sendsubvol"
61 #define SEND_VERBW L"sendsubvol"
62 
63 typedef struct {
68 
69 // FIXME - don't assume subvol's top inode is 0x100
70 
72  if (riid == IID_IUnknown || riid == IID_IContextMenu) {
73  *ppObj = static_cast<IContextMenu*>(this);
74  AddRef();
75  return S_OK;
76  } else if (riid == IID_IShellExtInit) {
77  *ppObj = static_cast<IShellExtInit*>(this);
78  AddRef();
79  return S_OK;
80  }
81 
82  *ppObj = NULL;
83  return E_NOINTERFACE;
84 }
85 
87  HANDLE h;
89  btrfs_get_file_ids bgfi;
91 
92  if (!pidlFolder) {
93  FORMATETC format = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
94  UINT num_files, i;
95  WCHAR fn[MAX_PATH];
96  HDROP hdrop;
97 
98  if (!pdtobj)
99  return E_FAIL;
100 
101  stgm.tymed = TYMED_HGLOBAL;
102 
103  if (FAILED(pdtobj->GetData(&format, &stgm)))
104  return E_INVALIDARG;
105 
106  stgm_set = TRUE;
107 
108  hdrop = (HDROP)GlobalLock(stgm.hGlobal);
109 
110  if (!hdrop) {
112  stgm_set = FALSE;
113  return E_INVALIDARG;
114  }
115 
116  num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, NULL, 0);
117 
118  for (i = 0; i < num_files; i++) {
119  if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
121 
122  if (h != INVALID_HANDLE_VALUE) {
123  Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_FILE_IDS, NULL, 0, &bgfi, sizeof(btrfs_get_file_ids));
124 
125  if (NT_SUCCESS(Status) && bgfi.inode == 0x100 && !bgfi.top) {
126  WCHAR parpath[MAX_PATH];
127  HANDLE h2;
128 
129  StringCchCopyW(parpath, sizeof(parpath) / sizeof(WCHAR), fn);
130 
131  PathRemoveFileSpecW(parpath);
132 
134 
135  if (h2 != INVALID_HANDLE_VALUE)
137 
138  CloseHandle(h2);
139 
140  ignore = FALSE;
141  bg = FALSE;
142 
143  CloseHandle(h);
144  GlobalUnlock(hdrop);
145  return S_OK;
146  }
147 
148  CloseHandle(h);
149  }
150  }
151  }
152 
153  GlobalUnlock(hdrop);
154 
155  return S_OK;
156  }
157 
158  if (!SHGetPathFromIDListW(pidlFolder, path))
159  return E_FAIL;
160 
161  // check we have permissions to create new subdirectory
162 
164 
165  if (h == INVALID_HANDLE_VALUE)
166  return E_FAIL;
167 
168  // check is Btrfs volume
169 
170  Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_FILE_IDS, NULL, 0, &bgfi, sizeof(btrfs_get_file_ids));
171 
172  if (!NT_SUCCESS(Status)) {
173  CloseHandle(h);
174  return E_FAIL;
175  }
176 
177  CloseHandle(h);
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 
189  f = PathFindFileNameW(fn);
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 
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, volpath1, sizeof(volpath1) / sizeof(WCHAR)))
215  return FALSE;
216 
217  if (!OpenClipboard(NULL))
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, NULL, 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);
266  pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
267  pbmi->bmiHeader.biPlanes = 1;
269 
270  pbmi->bmiHeader.biWidth = cx;
271  pbmi->bmiHeader.biHeight = cy;
272  pbmi->bmiHeader.biBitCount = bpp;
273 }
274 
275 static HRESULT Create32BitHBITMAP(HDC hdc, const SIZE *psize, void **ppvBits, HBITMAP* phBmp) {
276  BITMAPINFO bmi;
277  HDC hdcUsed;
278 
279  *phBmp = NULL;
280 
281  InitBitmapInfo(&bmi, sizeof(bmi), psize->cx, psize->cy, 32);
282 
283  hdcUsed = hdc ? hdc : GetDC(NULL);
284 
285  if (hdcUsed) {
286  *phBmp = CreateDIBSection(hdcUsed, &bmi, DIB_RGB_COLORS, ppvBits, NULL, 0);
287  if (hdc != hdcUsed)
288  ReleaseDC(NULL, hdcUsed);
289  }
290 
291  return !*phBmp ? E_OUTOFMEMORY : S_OK;
292 }
293 
297  HRESULT hr;
298 
299 #ifdef __REACTOS__
300  hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (void **)&factory);
301 #else
302  hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, 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(NULL, &sz, (void**)&buf, &uacicon);
325  if (SUCCEEDED(hr)) {
326  UINT stride = cx * sizeof(DWORD);
327  UINT buflen = cy * stride;
328  bitmap->CopyPixels(NULL, stride, buflen, buf);
329  }
330  }
331 
332  bitmap->Release();
333  }
334 
335  factory->Release();
336  }
337 }
338 
340  WCHAR str[256];
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) {
351  if (LoadStringW(module, IDS_CREATE_SNAPSHOT, str, sizeof(str) / sizeof(WCHAR)) == 0)
352  return E_FAIL;
353 
354  if (!InsertMenuW(hmenu, indexMenu, MF_BYPOSITION, idCmdFirst, str))
355  return E_FAIL;
356 
357  entries = 1;
358  }
359 
360  if (idCmdFirst + entries <= idCmdLast) {
361  MENUITEMINFOW mii;
362 
363  if (LoadStringW(module, IDS_SEND_SUBVOL, str, sizeof(str) / sizeof(WCHAR)) == 0)
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 = 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 (LoadStringW(module, IDS_NEW_SUBVOL, str, sizeof(str) / sizeof(WCHAR)) == 0)
383  return E_FAIL;
384 
385  if (!InsertMenuW(hmenu, indexMenu, MF_BYPOSITION, idCmdFirst, str))
386  return E_FAIL;
387 
388  entries = 1;
389 
390  if (idCmdFirst + 1 <= idCmdLast) {
391  MENUITEMINFOW mii;
392 
393  if (LoadStringW(module, IDS_RECV_SUBVOL, str, sizeof(str) / sizeof(WCHAR)) == 0)
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 = 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)) {
413  if (LoadStringW(module, IDS_REFLINK_PASTE, str, sizeof(str) / sizeof(WCHAR)) == 0)
414  return E_FAIL;
415 
416  if (!InsertMenuW(hmenu, indexMenu + 2, MF_BYPOSITION, idCmdFirst + 2, str))
417  return E_FAIL;
418 
419  entries++;
420  }
421  }
422 
423  return MAKE_HRESULT(SEVERITY_SUCCESS, 0, entries);
424 }
425 
426 static void create_snapshot(HWND hwnd, WCHAR* fn) {
427  HANDLE h;
430  btrfs_get_file_ids bgfi;
431 
433 
434  if (h != INVALID_HANDLE_VALUE) {
435  Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_FILE_IDS, NULL, 0, &bgfi, sizeof(btrfs_get_file_ids));
436 
437  if (NT_SUCCESS(Status) && bgfi.inode == 0x100 && !bgfi.top) {
438  WCHAR parpath[MAX_PATH], subvolname[MAX_PATH], templ[MAX_PATH], name[MAX_PATH], searchpath[MAX_PATH];
439  HANDLE h2, fff;
441  ULONG namelen, pathend;
442  WIN32_FIND_DATAW wfd;
444 
445  StringCchCopyW(parpath, sizeof(parpath) / sizeof(WCHAR), fn);
446  PathRemoveFileSpecW(parpath);
447 
448  StringCchCopyW(subvolname, sizeof(subvolname) / sizeof(WCHAR), fn);
449  PathStripPathW(subvolname);
450 
452 
453  if (h2 == INVALID_HANDLE_VALUE) {
454  ShowError(hwnd, GetLastError());
455  CloseHandle(h);
456  return;
457  }
458 
460  ShowError(hwnd, GetLastError());
461  CloseHandle(h);
462  CloseHandle(h2);
463  return;
464  }
465 
466  GetLocalTime(&time);
467 
468  if (StringCchPrintfW(name, sizeof(name) / sizeof(WCHAR), templ, subvolname, time.wYear, time.wMonth, time.wDay) == STRSAFE_E_INSUFFICIENT_BUFFER) {
469  MessageBoxW(hwnd, L"Filename too long.\n", L"Error", MB_ICONERROR);
470  CloseHandle(h);
471  CloseHandle(h2);
472  return;
473  }
474 
475  StringCchCopyW(searchpath, sizeof(searchpath) / sizeof(WCHAR), parpath);
476  StringCchCatW(searchpath, sizeof(searchpath) / sizeof(WCHAR), L"\\");
477  pathend = wcslen(searchpath);
478 
479  StringCchCatW(searchpath, sizeof(searchpath) / sizeof(WCHAR), name);
480 
481  fff = FindFirstFileW(searchpath, &wfd);
482 
483  if (fff != INVALID_HANDLE_VALUE) {
484  ULONG i = wcslen(searchpath), num = 2;
485 
486  do {
487  FindClose(fff);
488 
489  searchpath[i] = 0;
490  if (StringCchPrintfW(searchpath, sizeof(searchpath) / sizeof(WCHAR), L"%s (%u)", searchpath, num) == STRSAFE_E_INSUFFICIENT_BUFFER) {
491  MessageBoxW(hwnd, L"Filename too long.\n", L"Error", MB_ICONERROR);
492  CloseHandle(h);
493  CloseHandle(h2);
494  return;
495  }
496 
497  fff = FindFirstFileW(searchpath, &wfd);
498  num++;
499  } while (fff != INVALID_HANDLE_VALUE);
500  }
501 
502  namelen = wcslen(&searchpath[pathend]) * sizeof(WCHAR);
503 
505  bcs->readonly = FALSE;
506  bcs->posix = FALSE;
507  bcs->subvol = h;
508  bcs->namelen = namelen;
509  memcpy(bcs->name, &searchpath[pathend], namelen);
510 
511  Status = NtFsControlFile(h2, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, sizeof(btrfs_create_snapshot) - 1 + namelen, NULL, 0);
512 
513  if (!NT_SUCCESS(Status))
514  ShowNtStatusError(hwnd, Status);
515 
516  CloseHandle(h2);
517  }
518 
519  CloseHandle(h);
520  } else
521  ShowError(hwnd, GetLastError());
522 }
523 
524 static UINT64 __inline sector_align(UINT64 n, UINT64 a) {
525  if (n & (a - 1))
526  n = (n + a) & ~(a - 1);
527 
528  return n;
529 }
530 
532  HANDLE source, dest;
533  WCHAR* name, volpath1[255], volpath2[255];
534  std::wstring dirw, newpath;
535  BOOL ret = FALSE;
536  FILE_BASIC_INFO fbi;
537  FILETIME atime, mtime;
538  btrfs_inode_info bii;
540  ULONG bytesret;
543  btrfs_set_xattr bsxa;
544 
545  // Thanks to 0xbadfca11, whose version of reflink for Windows provided a few pointers on what
546  // to do here - https://github.com/0xbadfca11/reflink
547 
548  name = PathFindFileNameW(fn);
549 
550  dirw = dir;
551 
552  if (dir[0] != 0 && dir[wcslen(dir) - 1] != '\\')
553  dirw += L"\\";
554 
555  newpath = dirw;
556  newpath += name;
557 
558  if (!get_volume_path_parent(fn, volpath1, sizeof(volpath1) / sizeof(WCHAR))) {
559  ShowError(hwnd, GetLastError());
560  return FALSE;
561  }
562 
563  if (!GetVolumePathNameW(dir, volpath2, sizeof(volpath2) / sizeof(WCHAR))) {
564  ShowError(hwnd, GetLastError());
565  return FALSE;
566  }
567 
568  if (wcscmp(volpath1, volpath2)) // different filesystems
569  return FALSE;
570 
572  if (source == INVALID_HANDLE_VALUE) {
573  ShowError(hwnd, GetLastError());
574  return FALSE;
575  }
576 
577  Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_INODE_INFO, NULL, 0, &bii, sizeof(btrfs_inode_info));
578  if (!NT_SUCCESS(Status)) {
579  ShowNtStatusError(hwnd, Status);
580  CloseHandle(source);
581  return FALSE;
582  }
583 
584  // if subvol, do snapshot instead
585  if (bii.inode == SUBVOL_ROOT_INODE) {
587  HANDLE dirh, fff;
588  std::wstring destname, search;
589  WIN32_FIND_DATAW wfd;
590  int num = 2;
591 
593  if (dirh == INVALID_HANDLE_VALUE) {
594  ShowError(hwnd, GetLastError());
595  CloseHandle(source);
596  return FALSE;
597  }
598 
599  search = dirw;
600  search += name;
601  destname = name;
602 
603  fff = FindFirstFileW(search.c_str(), &wfd);
604 
605  if (fff != INVALID_HANDLE_VALUE) {
606  do {
608 
609  FindClose(fff);
610 
611  ss << name;
612  ss << L" (";
613  ss << num;
614  ss << L")";
615  destname = ss.str();
616 
617  search = dirw + destname;
618 
619  fff = FindFirstFileW(search.c_str(), &wfd);
620  num++;
621  } while (fff != INVALID_HANDLE_VALUE);
622  }
623 
624  bcs = (btrfs_create_snapshot*)malloc(sizeof(btrfs_create_snapshot) - sizeof(WCHAR) + (destname.length() * sizeof(WCHAR)));
625  bcs->subvol = source;
626  bcs->namelen = destname.length() * sizeof(WCHAR);
627  memcpy(bcs->name, destname.c_str(), destname.length() * sizeof(WCHAR));
628 
629  Status = NtFsControlFile(dirh, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, sizeof(btrfs_create_snapshot) - sizeof(WCHAR) + bcs->namelen, NULL, 0);
630 
631  free(bcs);
632 
633  if (!NT_SUCCESS(Status)) {
634  ShowNtStatusError(hwnd, Status);
635  CloseHandle(source);
636  CloseHandle(dirh);
637  return FALSE;
638  }
639 
640  CloseHandle(source);
641  CloseHandle(dirh);
642  return TRUE;
643  }
644 
645  if (!GetFileInformationByHandleEx(source, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO))) {
646  ShowError(hwnd, GetLastError());
647  CloseHandle(source);
648  return FALSE;
649  }
650 
651  if (bii.type == BTRFS_TYPE_CHARDEV || bii.type == BTRFS_TYPE_BLOCKDEV || bii.type == BTRFS_TYPE_FIFO || bii.type == BTRFS_TYPE_SOCKET) {
652  HANDLE dirh;
653  ULONG bmnsize;
654  btrfs_mknod* bmn;
655 
657  if (dirh == INVALID_HANDLE_VALUE) {
658  ShowError(hwnd, GetLastError());
659  CloseHandle(source);
660  return FALSE;
661  }
662 
663  bmnsize = offsetof(btrfs_mknod, name[0]) + (wcslen(name) * sizeof(WCHAR));
664  bmn = (btrfs_mknod*)malloc(bmnsize);
665 
666  bmn->inode = 0;
667  bmn->type = bii.type;
668  bmn->st_rdev = bii.st_rdev;
669  bmn->namelen = wcslen(name) * sizeof(WCHAR);
670  memcpy(bmn->name, name, bmn->namelen);
671 
672  Status = NtFsControlFile(dirh, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_MKNOD, bmn, bmnsize, NULL, 0);
673  if (!NT_SUCCESS(Status)) {
674  ShowNtStatusError(hwnd, Status);
675  CloseHandle(dirh);
676  CloseHandle(source);
677  free(bmn);
678  return FALSE;
679  }
680 
681  CloseHandle(dirh);
682  free(bmn);
683 
684  dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, 0, NULL);
685  } else if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
686  if (CreateDirectoryExW(fn, newpath.c_str(), NULL))
689  else
690  dest = INVALID_HANDLE_VALUE;
691  } else
692  dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW, 0, source);
693 
694  if (dest == INVALID_HANDLE_VALUE) {
695  int num = 2;
696 
697  if (GetLastError() != ERROR_FILE_EXISTS && GetLastError() != ERROR_ALREADY_EXISTS && wcscmp(fn, newpath.c_str())) {
698  ShowError(hwnd, GetLastError());
699  CloseHandle(source);
700  return FALSE;
701  }
702 
703  do {
704  WCHAR* ext;
706 
707  ext = PathFindExtensionW(fn);
708 
709  ss << dirw;
710 
711  if (*ext == 0) {
712  ss << name;
713  ss << L" (";
714  ss << num;
715  ss << L")";
716  } else {
717  std::wstring namew = name;
718 
719  ss << namew.substr(0, ext - name);
720  ss << L" (";
721  ss << num;
722  ss << L")";
723  ss << ext;
724  }
725 
726  newpath = ss.str();
727  if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
728  if (CreateDirectoryExW(fn, newpath.c_str(), NULL))
730  else
731  dest = INVALID_HANDLE_VALUE;
732  } else
733  dest = CreateFileW(newpath.c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW, 0, source);
734 
735  if (dest == INVALID_HANDLE_VALUE) {
737  ShowError(hwnd, GetLastError());
738  CloseHandle(source);
739  return FALSE;
740  }
741 
742  num++;
743  } else
744  break;
745  } while (TRUE);
746  }
747 
748  memset(&bsii, 0, sizeof(btrfs_set_inode_info));
749 
750  bsii.flags_changed = TRUE;
751  bsii.flags = bii.flags;
752 
753  if (bii.flags & BTRFS_INODE_COMPRESS) {
756  }
757 
758  Status = NtFsControlFile(dest, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), NULL, 0);
759  if (!NT_SUCCESS(Status)) {
760  ShowNtStatusError(hwnd, Status);
761  goto end;
762  }
763 
764  if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
765  if (!(fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
766  HANDLE h;
767  WIN32_FIND_DATAW fff;
768  std::wstring qs;
769 
770  qs = fn;
771  qs += L"\\*";
772 
773  h = FindFirstFileW(qs.c_str(), &fff);
774  if (h != INVALID_HANDLE_VALUE) {
775  do {
776  std::wstring fn2;
777 
778  if (fff.cFileName[0] == '.' && (fff.cFileName[1] == 0 || (fff.cFileName[1] == '.' && fff.cFileName[2] == 0)))
779  continue;
780 
781  fn2 = fn;
782  fn2 += L"\\";
783  fn2 += fff.cFileName;
784 
785  if (!reflink_copy(hwnd, fn2.c_str(), newpath.c_str()))
786  goto end;
787  } while (FindNextFileW(h, &fff));
788 
789  FindClose(h);
790  }
791  }
792 
793  // CreateDirectoryExW also copies streams, no need to do it here
794  } else {
795  HANDLE h;
796  WIN32_FIND_STREAM_DATA fsd;
797 
798  if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
799  reparse_header rh;
800  ULONG rplen;
801  UINT8* rp;
802 
803  if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, NULL, 0, &rh, sizeof(reparse_header), &bytesret, NULL)) {
804  if (GetLastError() != ERROR_MORE_DATA) {
805  ShowError(hwnd, GetLastError());
806  goto end;
807  }
808  }
809 
810  rplen = sizeof(reparse_header) + rh.ReparseDataLength;
811  rp = (UINT8*)malloc(rplen);
812 
813  if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, NULL, 0, rp, rplen, &bytesret, NULL)) {
814  ShowError(hwnd, GetLastError());
815  goto end;
816  }
817 
818  if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, rplen, NULL, 0, &bytesret, NULL)) {
819  ShowError(hwnd, GetLastError());
820  goto end;
821  }
822 
823  free(rp);
824  } else {
825  FILE_STANDARD_INFO fsi;
826  FILE_END_OF_FILE_INFO feofi;
830  UINT64 offset, alloc_size;
831  ULONG maxdup;
832 
833  if (!GetFileInformationByHandleEx(source, FileStandardInfo, &fsi, sizeof(FILE_STANDARD_INFO))) {
834  ShowError(hwnd, GetLastError());
835  goto end;
836  }
837 
838  if (!DeviceIoControl(source, FSCTL_GET_INTEGRITY_INFORMATION, NULL, 0, &fgiib, sizeof(FSCTL_GET_INTEGRITY_INFORMATION_BUFFER), &bytesret, NULL)) {
839  ShowError(hwnd, GetLastError());
840  goto end;
841  }
842 
843  if (fbi.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) {
844  if (!DeviceIoControl(dest, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &bytesret, NULL)) {
845  ShowError(hwnd, GetLastError());
846  goto end;
847  }
848  }
849 
850  fsiib.ChecksumAlgorithm = fgiib.ChecksumAlgorithm;
851  fsiib.Reserved = 0;
852  fsiib.Flags = fgiib.Flags;
853  if (!DeviceIoControl(dest, FSCTL_SET_INTEGRITY_INFORMATION, &fsiib, sizeof(FSCTL_SET_INTEGRITY_INFORMATION_BUFFER), NULL, 0, &bytesret, NULL)) {
854  ShowError(hwnd, GetLastError());
855  goto end;
856  }
857 
858  feofi.EndOfFile = fsi.EndOfFile;
859  if (!SetFileInformationByHandle(dest, FileEndOfFileInfo, &feofi, sizeof(FILE_END_OF_FILE_INFO))){
860  ShowError(hwnd, GetLastError());
861  goto end;
862  }
863 
864  ded.FileHandle = source;
865  maxdup = 0xffffffff - fgiib.ClusterSizeInBytes + 1;
866 
867  alloc_size = sector_align(fsi.EndOfFile.QuadPart, fgiib.ClusterSizeInBytes);
868 
869  offset = 0;
870  while (offset < alloc_size) {
872  ded.ByteCount.QuadPart = maxdup < (alloc_size - offset) ? maxdup : (alloc_size - offset);
873  if (!DeviceIoControl(dest, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &ded, sizeof(DUPLICATE_EXTENTS_DATA), NULL, 0, &bytesret, NULL)) {
874  ShowError(hwnd, GetLastError());
875  goto end;
876  }
877 
878  offset += ded.ByteCount.QuadPart;
879  }
880  }
881 
882  h = FindFirstStreamW(fn, FindStreamInfoStandard, &fsd, 0);
883  if (h != INVALID_HANDLE_VALUE) {
884  do {
885  std::wstring sn;
886 
887  sn = fsd.cStreamName;
888 
889  if (sn != L"::$DATA" && sn.length() > 6 && sn.substr(sn.length() - 6, 6) == L":$DATA") {
890  HANDLE stream;
891  UINT8* data = NULL;
892 
893  if (fsd.StreamSize.QuadPart > 0) {
894  std::wstring fn2;
895 
896  fn2 = fn;
897  fn2 += sn;
898 
899  stream = CreateFileW(fn2.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
900 
901  if (stream == INVALID_HANDLE_VALUE) {
902  ShowError(hwnd, GetLastError());
903  goto end;
904  }
905 
906  // We can get away with this because our streams are guaranteed to be below 64 KB -
907  // don't do this on NTFS!
908  data = (UINT8*)malloc(fsd.StreamSize.QuadPart);
909 
910  if (!ReadFile(stream, data, fsd.StreamSize.QuadPart, &bytesret, NULL)) {
911  ShowError(hwnd, GetLastError());
912  free(data);
913  CloseHandle(stream);
914  goto end;
915  }
916 
917  CloseHandle(stream);
918  }
919 
920  stream = CreateFileW((newpath + sn).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW, 0, NULL);
921 
922  if (stream == INVALID_HANDLE_VALUE) {
923  ShowError(hwnd, GetLastError());
924 
925  if (data) free(data);
926 
927  goto end;
928  }
929 
930  if (data) {
931  if (!WriteFile(stream, data, fsd.StreamSize.QuadPart, &bytesret, NULL)) {
932  ShowError(hwnd, GetLastError());
933  free(data);
934  CloseHandle(stream);
935  goto end;
936  }
937 
938  free(data);
939  }
940 
941  CloseHandle(stream);
942  }
943  } while (FindNextStreamW(h, &fsd));
944 
945  FindClose(h);
946  }
947  }
948 
949  atime.dwLowDateTime = fbi.LastAccessTime.LowPart;
950  atime.dwHighDateTime = fbi.LastAccessTime.HighPart;
951  mtime.dwLowDateTime = fbi.LastWriteTime.LowPart;
952  mtime.dwHighDateTime = fbi.LastWriteTime.HighPart;
953  SetFileTime(dest, NULL, &atime, &mtime);
954 
955  Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_XATTRS, NULL, 0, &bsxa, sizeof(btrfs_set_xattr));
956 
957  if (Status == STATUS_BUFFER_OVERFLOW || (NT_SUCCESS(Status) && bsxa.valuelen > 0)) {
958  ULONG xalen = 0;
959  btrfs_set_xattr *xa = NULL, *xa2;
960 
961  do {
962  xalen += 1024;
963 
964  if (xa) free(xa);
965  xa = (btrfs_set_xattr*)malloc(xalen);
966 
967  Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_XATTRS, NULL, 0, xa, xalen);
968  } while (Status == STATUS_BUFFER_OVERFLOW);
969 
970  if (!NT_SUCCESS(Status)) {
971  free(xa);
972  ShowNtStatusError(hwnd, Status);
973  goto end;
974  }
975 
976  xa2 = xa;
977  while (xa2->valuelen > 0) {
978  Status = NtFsControlFile(dest, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_XATTR, xa2,
979  offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen, NULL, 0);
980  if (!NT_SUCCESS(Status)) {
981  free(xa);
982  ShowNtStatusError(hwnd, Status);
983  goto end;
984  }
985  xa2 = (btrfs_set_xattr*)&xa2->data[xa2->namelen + xa2->valuelen];
986  }
987 
988  free(xa);
989  } else if (!NT_SUCCESS(Status)) {
990  ShowNtStatusError(hwnd, Status);
991  goto end;
992  }
993 
994  ret = TRUE;
995 
996 end:
997  if (!ret) {
998  FILE_DISPOSITION_INFO fdi;
999 
1000  fdi.DeleteFile = TRUE;
1001  if (!SetFileInformationByHandle(dest, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO)))
1002  ShowError(hwnd, GetLastError());
1003  }
1004 
1005  CloseHandle(dest);
1006  CloseHandle(source);
1007 
1008  return ret;
1009 }
1010 
1013 
1014  if (ignore)
1015  return E_INVALIDARG;
1016 
1017  if (!bg) {
1018  if ((IS_INTRESOURCE(pici->lpVerb) && allow_snapshot && pici->lpVerb == 0) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, SNAPSHOT_VERBA))) {
1019  UINT num_files, i;
1020  WCHAR fn[MAX_PATH];
1021 
1022  if (!stgm_set)
1023  return E_FAIL;
1024 
1025  num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, NULL, 0);
1026 
1027  if (num_files == 0)
1028  return E_FAIL;
1029 
1030  for (i = 0; i < num_files; i++) {
1031  if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
1032  create_snapshot(pici->hwnd, fn);
1033  }
1034  }
1035 
1036  return S_OK;
1037  } else if ((IS_INTRESOURCE(pici->lpVerb) && ((allow_snapshot && (ULONG_PTR)pici->lpVerb == 1) || (!allow_snapshot && (ULONG_PTR)pici->lpVerb == 0))) ||
1038  (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, SEND_VERBA))) {
1039  UINT num_files, i;
1041  std::wstring t;
1042  SHELLEXECUTEINFOW sei;
1043 
1044  GetModuleFileNameW(module, dll, sizeof(dll) / sizeof(WCHAR));
1045 
1046  if (!stgm_set)
1047  return E_FAIL;
1048 
1049  num_files = DragQueryFileW((HDROP)stgm.hGlobal, 0xFFFFFFFF, NULL, 0);
1050 
1051  if (num_files == 0)
1052  return E_FAIL;
1053 
1054  for (i = 0; i < num_files; i++) {
1055  if (DragQueryFileW((HDROP)stgm.hGlobal, i, fn, sizeof(fn) / sizeof(WCHAR))) {
1056  t = L"\"";
1057  t += dll;
1058  t += L"\",SendSubvolGUI ";
1059  t += fn;
1060 
1061  RtlZeroMemory(&sei, sizeof(sei));
1062 
1063  sei.cbSize = sizeof(sei);
1064  sei.hwnd = pici->hwnd;
1065  sei.lpVerb = L"runas";
1066  sei.lpFile = L"rundll32.exe";
1067  sei.lpParameters = t.c_str();
1068  sei.nShow = SW_SHOW;
1070 
1071  if (!ShellExecuteExW(&sei)) {
1072  ShowError(pici->hwnd, GetLastError());
1073  return E_FAIL;
1074  }
1075 
1077  CloseHandle(sei.hProcess);
1078  }
1079  }
1080 
1081  return S_OK;
1082  }
1083  } else {
1084  if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 0) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, NEW_SUBVOL_VERBA))) {
1085  HANDLE h;
1087  NTSTATUS Status;
1088  ULONG pathlen, searchpathlen, pathend, bcslen;
1089  WCHAR name[MAX_PATH], *searchpath;
1090  btrfs_create_subvol* bcs;
1091  HANDLE fff;
1092  WIN32_FIND_DATAW wfd;
1093 
1095  ShowError(pici->hwnd, GetLastError());
1096  return E_FAIL;
1097  }
1098 
1100 
1101  if (h == INVALID_HANDLE_VALUE) {
1102  ShowError(pici->hwnd, GetLastError());
1103  return E_FAIL;
1104  }
1105 
1106  pathlen = wcslen(path);
1107 
1108  searchpathlen = pathlen + wcslen(name) + 10;
1109  searchpath = (WCHAR*)malloc(searchpathlen * sizeof(WCHAR));
1110 
1111  StringCchCopyW(searchpath, searchpathlen, path);
1112  StringCchCatW(searchpath, searchpathlen, L"\\");
1113  pathend = wcslen(searchpath);
1114 
1115  StringCchCatW(searchpath, searchpathlen, name);
1116 
1117  fff = FindFirstFileW(searchpath, &wfd);
1118 
1119  if (fff != INVALID_HANDLE_VALUE) {
1120  ULONG i = wcslen(searchpath), num = 2;
1121 
1122  do {
1123  FindClose(fff);
1124 
1125  searchpath[i] = 0;
1126  if (StringCchPrintfW(searchpath, searchpathlen, L"%s (%u)", searchpath, num) == STRSAFE_E_INSUFFICIENT_BUFFER) {
1127  MessageBoxW(pici->hwnd, L"Filename too long.\n", L"Error", MB_ICONERROR);
1128  CloseHandle(h);
1129  return E_FAIL;
1130  }
1131 
1132  fff = FindFirstFileW(searchpath, &wfd);
1133  num++;
1134  } while (fff != INVALID_HANDLE_VALUE);
1135  }
1136 
1137  bcslen = offsetof(btrfs_create_subvol, name[0]) + (wcslen(&searchpath[pathend]) * sizeof(WCHAR));
1138  bcs = (btrfs_create_subvol*)malloc(bcslen);
1139 
1140  bcs->readonly = FALSE;
1141  bcs->posix = FALSE;
1142  bcs->namelen = wcslen(&searchpath[pathend]) * sizeof(WCHAR);
1143  memcpy(bcs->name, &searchpath[pathend], bcs->namelen);
1144 
1145  Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, bcslen, NULL, 0);
1146 
1147  free(searchpath);
1148  free(bcs);
1149 
1150  if (!NT_SUCCESS(Status)) {
1151  CloseHandle(h);
1152  ShowNtStatusError(pici->hwnd, Status);
1153  return E_FAIL;
1154  }
1155 
1156  CloseHandle(h);
1157 
1158  return S_OK;
1159  } else if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 1) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, RECV_VERBA))) {
1160  WCHAR dll[MAX_PATH];
1161  std::wstring t;
1162  SHELLEXECUTEINFOW sei;
1163 
1164  GetModuleFileNameW(module, dll, sizeof(dll) / sizeof(WCHAR));
1165 
1166  t = L"\"";
1167  t += dll;
1168  t += L"\",RecvSubvolGUI ";
1169  t += path;
1170 
1171  RtlZeroMemory(&sei, sizeof(sei));
1172 
1173  sei.cbSize = sizeof(sei);
1174  sei.hwnd = pici->hwnd;
1175  sei.lpVerb = L"runas";
1176  sei.lpFile = L"rundll32.exe";
1177  sei.lpParameters = t.c_str();
1178  sei.nShow = SW_SHOW;
1180 
1181  if (!ShellExecuteExW(&sei)) {
1182  ShowError(pici->hwnd, GetLastError());
1183  return E_FAIL;
1184  }
1185 
1187  CloseHandle(sei.hProcess);
1188 
1189  return S_OK;
1190  } else if ((IS_INTRESOURCE(pici->lpVerb) && (ULONG_PTR)pici->lpVerb == 2) || (!IS_INTRESOURCE(pici->lpVerb) && !strcmp(pici->lpVerb, REFLINK_VERBA))) {
1191  HDROP hdrop;
1192 
1194  return S_OK;
1195 
1196  if (!OpenClipboard(pici->hwnd)) {
1197  ShowError(pici->hwnd, GetLastError());
1198  return E_FAIL;
1199  }
1200 
1201  hdrop = (HDROP)GetClipboardData(CF_HDROP);
1202 
1203  if (hdrop) {
1204  HANDLE lh;
1205 
1206  lh = GlobalLock(hdrop);
1207 
1208  if (lh) {
1209  ULONG num_files, i;
1210  WCHAR fn[MAX_PATH];
1211 
1212  num_files = DragQueryFileW(hdrop, 0xFFFFFFFF, NULL, 0);
1213 
1214  for (i = 0; i < num_files; i++) {
1215  if (DragQueryFileW(hdrop, i, fn, sizeof(fn) / sizeof(WCHAR))) {
1216  if (!reflink_copy(pici->hwnd, fn, pici->lpDirectoryW)) {
1217  GlobalUnlock(lh);
1218  CloseClipboard();
1219  return E_FAIL;
1220  }
1221  }
1222  }
1223 
1224  GlobalUnlock(lh);
1225  }
1226  }
1227 
1228  CloseClipboard();
1229 
1230  return S_OK;
1231  }
1232  }
1233 
1234  return E_FAIL;
1235 }
1236 
1238  if (ignore)
1239  return E_INVALIDARG;
1240 
1241  if (idCmd != 0)
1242  return E_INVALIDARG;
1243 
1244  if (!bg) {
1245  if (idCmd == 0) {
1246  switch (uFlags) {
1247  case GCS_HELPTEXTA:
1248  if (LoadStringA(module, IDS_CREATE_SNAPSHOT_HELP_TEXT, pszName, cchMax))
1249  return S_OK;
1250  else
1251  return E_FAIL;
1252 
1253  case GCS_HELPTEXTW:
1254  if (LoadStringW(module, IDS_CREATE_SNAPSHOT_HELP_TEXT, (LPWSTR)pszName, cchMax))
1255  return S_OK;
1256  else
1257  return E_FAIL;
1258 
1259  case GCS_VALIDATEA:
1260  case GCS_VALIDATEW:
1261  return S_OK;
1262 
1263  case GCS_VERBA:
1264  return StringCchCopyA(pszName, cchMax, SNAPSHOT_VERBA);
1265 
1266  case GCS_VERBW:
1267  return StringCchCopyW((STRSAFE_LPWSTR)pszName, cchMax, SNAPSHOT_VERBW);
1268 
1269  default:
1270  return E_INVALIDARG;
1271  }
1272  } else if (idCmd == 1) {
1273  switch (uFlags) {
1274  case GCS_HELPTEXTA:
1275  if (LoadStringA(module, IDS_SEND_SUBVOL_HELP, pszName, cchMax))
1276  return S_OK;
1277  else
1278  return E_FAIL;
1279 
1280  case GCS_HELPTEXTW:
1281  if (LoadStringW(module, IDS_SEND_SUBVOL_HELP, (LPWSTR)pszName, cchMax))
1282  return S_OK;
1283  else
1284  return E_FAIL;
1285 
1286  case GCS_VALIDATEA:
1287  case GCS_VALIDATEW:
1288  return S_OK;
1289 
1290  case GCS_VERBA:
1291  return StringCchCopyA(pszName, cchMax, SEND_VERBA);
1292 
1293  case GCS_VERBW:
1294  return StringCchCopyW((STRSAFE_LPWSTR)pszName, cchMax, SEND_VERBW);
1295 
1296  default:
1297  return E_INVALIDARG;
1298  }
1299  } else
1300  return E_INVALIDARG;
1301  } else {
1302  if (idCmd == 0) {
1303  switch (uFlags) {
1304  case GCS_HELPTEXTA:
1305  if (LoadStringA(module, IDS_NEW_SUBVOL_HELP_TEXT, pszName, cchMax))
1306  return S_OK;
1307  else
1308  return E_FAIL;
1309 
1310  case GCS_HELPTEXTW:
1311  if (LoadStringW(module, IDS_NEW_SUBVOL_HELP_TEXT, (LPWSTR)pszName, cchMax))
1312  return S_OK;
1313  else
1314  return E_FAIL;
1315 
1316  case GCS_VALIDATEA:
1317  case GCS_VALIDATEW:
1318  return S_OK;
1319 
1320  case GCS_VERBA:
1321  return StringCchCopyA(pszName, cchMax, NEW_SUBVOL_VERBA);
1322 
1323  case GCS_VERBW:
1324  return StringCchCopyW((STRSAFE_LPWSTR)pszName, cchMax, NEW_SUBVOL_VERBW);
1325 
1326  default:
1327  return E_INVALIDARG;
1328  }
1329  } else if (idCmd == 1) {
1330  switch (uFlags) {
1331  case GCS_HELPTEXTA:
1332  if (LoadStringA(module, IDS_RECV_SUBVOL_HELP, pszName, cchMax))
1333  return S_OK;
1334  else
1335  return E_FAIL;
1336 
1337  case GCS_HELPTEXTW:
1338  if (LoadStringW(module, IDS_RECV_SUBVOL_HELP, (LPWSTR)pszName, cchMax))
1339  return S_OK;
1340  else
1341  return E_FAIL;
1342 
1343  case GCS_VALIDATEA:
1344  case GCS_VALIDATEW:
1345  return S_OK;
1346 
1347  case GCS_VERBA:
1348  return StringCchCopyA(pszName, cchMax, RECV_VERBA);
1349 
1350  case GCS_VERBW:
1351  return StringCchCopyW((STRSAFE_LPWSTR)pszName, cchMax, RECV_VERBW);
1352 
1353  default:
1354  return E_INVALIDARG;
1355  }
1356  } else if (idCmd == 2) {
1357  switch (uFlags) {
1358  case GCS_HELPTEXTA:
1359  if (LoadStringA(module, IDS_REFLINK_PASTE_HELP, pszName, cchMax))
1360  return S_OK;
1361  else
1362  return E_FAIL;
1363 
1364  case GCS_HELPTEXTW:
1365  if (LoadStringW(module, IDS_REFLINK_PASTE_HELP, (LPWSTR)pszName, cchMax))
1366  return S_OK;
1367  else
1368  return E_FAIL;
1369 
1370  case GCS_VALIDATEA:
1371  case GCS_VALIDATEW:
1372  return S_OK;
1373 
1374  case GCS_VERBA:
1375  return StringCchCopyA(pszName, cchMax, REFLINK_VERBA);
1376 
1377  case GCS_VERBW:
1378  return StringCchCopyW((STRSAFE_LPWSTR)pszName, cchMax, REFLINK_VERBW);
1379 
1380  default:
1381  return E_INVALIDARG;
1382  }
1383  } else
1384  return E_INVALIDARG;
1385  }
1386 }
1387 
1388 static void reflink_copy2(std::wstring srcfn, std::wstring destdir, std::wstring destname) {
1389  HANDLE source, dest;
1390  BOOL ret = FALSE;
1391  FILE_BASIC_INFO fbi;
1392  FILETIME atime, mtime;
1393  btrfs_inode_info bii;
1394  btrfs_set_inode_info bsii;
1395  ULONG bytesret;
1396  NTSTATUS Status;
1398  btrfs_set_xattr bsxa;
1399 
1401  if (source == INVALID_HANDLE_VALUE)
1402  return;
1403 
1404  Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_INODE_INFO, NULL, 0, &bii, sizeof(btrfs_inode_info));
1405  if (!NT_SUCCESS(Status)) {
1406  CloseHandle(source);
1407  return;
1408  }
1409 
1410  // if subvol, do snapshot instead
1411  if (bii.inode == SUBVOL_ROOT_INODE) {
1412  ULONG bcslen;
1413  btrfs_create_snapshot* bcs;
1414  HANDLE dirh;
1415 
1417  if (dirh == INVALID_HANDLE_VALUE) {
1418  CloseHandle(source);
1419  return;
1420  }
1421 
1422  bcslen = offsetof(btrfs_create_snapshot, name[0]) + (destname.length() * sizeof(WCHAR));
1423  bcs = (btrfs_create_snapshot*)malloc(bcslen);
1424  bcs->subvol = source;
1425  bcs->namelen = destname.length() * sizeof(WCHAR);
1426  memcpy(bcs->name, destname.c_str(), destname.length() * sizeof(WCHAR));
1427 
1428  Status = NtFsControlFile(dirh, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, bcslen, NULL, 0);
1429 
1430  free(bcs);
1431 
1432  CloseHandle(source);
1433  CloseHandle(dirh);
1434 
1435  return;
1436  }
1437 
1438  if (!GetFileInformationByHandleEx(source, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO))) {
1439  CloseHandle(source);
1440  return;
1441  }
1442 
1443  if (bii.type == BTRFS_TYPE_CHARDEV || bii.type == BTRFS_TYPE_BLOCKDEV || bii.type == BTRFS_TYPE_FIFO || bii.type == BTRFS_TYPE_SOCKET) {
1444  HANDLE dirh;
1445  ULONG bmnsize;
1446  btrfs_mknod* bmn;
1447 
1449  if (dirh == INVALID_HANDLE_VALUE) {
1450  CloseHandle(source);
1451  return;
1452  }
1453 
1454  bmnsize = offsetof(btrfs_mknod, name[0]) + (destname.length() * sizeof(WCHAR));
1455  bmn = (btrfs_mknod*)malloc(bmnsize);
1456 
1457  bmn->inode = 0;
1458  bmn->type = bii.type;
1459  bmn->st_rdev = bii.st_rdev;
1460  bmn->namelen = destname.length() * sizeof(WCHAR);
1461  memcpy(bmn->name, destname.c_str(), bmn->namelen);
1462 
1463  Status = NtFsControlFile(dirh, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_MKNOD, bmn, bmnsize, NULL, 0);
1464  if (!NT_SUCCESS(Status)) {
1465  CloseHandle(dirh);
1466  CloseHandle(source);
1467  free(bmn);
1468  return;
1469  }
1470 
1471  CloseHandle(dirh);
1472  free(bmn);
1473 
1474  dest = CreateFileW((destdir + destname).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, OPEN_EXISTING, 0, NULL);
1475  } else if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1476  if (CreateDirectoryExW(srcfn.c_str(), (destdir + destname).c_str(), NULL))
1477  dest = CreateFileW((destdir + destname).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1478  NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1479  else
1480  dest = INVALID_HANDLE_VALUE;
1481  } else
1482  dest = CreateFileW((destdir + destname).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW, 0, source);
1483 
1484  if (dest == INVALID_HANDLE_VALUE) {
1485  CloseHandle(source);
1486  return;
1487  }
1488 
1489  memset(&bsii, 0, sizeof(btrfs_set_inode_info));
1490 
1491  bsii.flags_changed = TRUE;
1492  bsii.flags = bii.flags;
1493 
1494  if (bii.flags & BTRFS_INODE_COMPRESS) {
1497  }
1498 
1499  Status = NtFsControlFile(dest, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), NULL, 0);
1500  if (!NT_SUCCESS(Status))
1501  goto end;
1502 
1503  if (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1504  if (!(fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
1505  HANDLE h;
1506  WIN32_FIND_DATAW fff;
1507  std::wstring qs;
1508 
1509  qs = srcfn;
1510  qs += L"\\*";
1511 
1512  h = FindFirstFileW(qs.c_str(), &fff);
1513  if (h != INVALID_HANDLE_VALUE) {
1514  do {
1515  std::wstring fn2;
1516 
1517  if (fff.cFileName[0] == '.' && (fff.cFileName[1] == 0 || (fff.cFileName[1] == '.' && fff.cFileName[2] == 0)))
1518  continue;
1519 
1520  fn2 = srcfn;
1521  fn2 += L"\\";
1522  fn2 += fff.cFileName;
1523 
1524  reflink_copy2(fn2, destdir + destname + L"\\", fff.cFileName);
1525  } while (FindNextFileW(h, &fff));
1526 
1527  FindClose(h);
1528  }
1529  }
1530 
1531  // CreateDirectoryExW also copies streams, no need to do it here
1532  } else {
1533  HANDLE h;
1534  WIN32_FIND_STREAM_DATA fsd;
1535 
1536  if (fbi.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1537  reparse_header rh;
1538  ULONG rplen;
1539  UINT8* rp;
1540 
1541  if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, NULL, 0, &rh, sizeof(reparse_header), &bytesret, NULL)) {
1542  if (GetLastError() != ERROR_MORE_DATA)
1543  goto end;
1544  }
1545 
1546  rplen = sizeof(reparse_header) + rh.ReparseDataLength;
1547  rp = (UINT8*)malloc(rplen);
1548 
1549  if (!DeviceIoControl(source, FSCTL_GET_REPARSE_POINT, NULL, 0, rp, rplen, &bytesret, NULL))
1550  goto end;
1551 
1552  if (!DeviceIoControl(dest, FSCTL_SET_REPARSE_POINT, rp, rplen, NULL, 0, &bytesret, NULL))
1553  goto end;
1554 
1555  free(rp);
1556  } else {
1557  FILE_STANDARD_INFO fsi;
1558  FILE_END_OF_FILE_INFO feofi;
1562  UINT64 offset, alloc_size;
1563  ULONG maxdup;
1564 
1565  if (!GetFileInformationByHandleEx(source, FileStandardInfo, &fsi, sizeof(FILE_STANDARD_INFO)))
1566  goto end;
1567 
1568  if (!DeviceIoControl(source, FSCTL_GET_INTEGRITY_INFORMATION, NULL, 0, &fgiib, sizeof(FSCTL_GET_INTEGRITY_INFORMATION_BUFFER), &bytesret, NULL))
1569  goto end;
1570 
1571  if (fbi.FileAttributes & FILE_ATTRIBUTE_SPARSE_FILE) {
1572  if (!DeviceIoControl(dest, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &bytesret, NULL))
1573  goto end;
1574  }
1575 
1576  fsiib.ChecksumAlgorithm = fgiib.ChecksumAlgorithm;
1577  fsiib.Reserved = 0;
1578  fsiib.Flags = fgiib.Flags;
1579  if (!DeviceIoControl(dest, FSCTL_SET_INTEGRITY_INFORMATION, &fsiib, sizeof(FSCTL_SET_INTEGRITY_INFORMATION_BUFFER), NULL, 0, &bytesret, NULL))
1580  goto end;
1581 
1582  feofi.EndOfFile = fsi.EndOfFile;
1583  if (!SetFileInformationByHandle(dest, FileEndOfFileInfo, &feofi, sizeof(FILE_END_OF_FILE_INFO)))
1584  goto end;
1585 
1586  ded.FileHandle = source;
1587  maxdup = 0xffffffff - fgiib.ClusterSizeInBytes + 1;
1588 
1589  alloc_size = sector_align(fsi.EndOfFile.QuadPart, fgiib.ClusterSizeInBytes);
1590 
1591  offset = 0;
1592  while (offset < alloc_size) {
1594  ded.ByteCount.QuadPart = maxdup < (alloc_size - offset) ? maxdup : (alloc_size - offset);
1595  if (!DeviceIoControl(dest, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &ded, sizeof(DUPLICATE_EXTENTS_DATA), NULL, 0, &bytesret, NULL))
1596  goto end;
1597 
1598  offset += ded.ByteCount.QuadPart;
1599  }
1600  }
1601 
1602  h = FindFirstStreamW(srcfn.c_str(), FindStreamInfoStandard, &fsd, 0);
1603  if (h != INVALID_HANDLE_VALUE) {
1604  do {
1605  std::wstring sn;
1606 
1607  sn = fsd.cStreamName;
1608 
1609  if (sn != L"::$DATA" && sn.length() > 6 && sn.substr(sn.length() - 6, 6) == L":$DATA") {
1610  HANDLE stream;
1611  UINT8* data = NULL;
1612 
1613  if (fsd.StreamSize.QuadPart > 0) {
1614  std::wstring fn2;
1615 
1616  fn2 = srcfn;
1617  fn2 += sn;
1618 
1619  stream = CreateFileW(fn2.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1620 
1621  if (stream == INVALID_HANDLE_VALUE)
1622  goto end;
1623 
1624  // We can get away with this because our streams are guaranteed to be below 64 KB -
1625  // don't do this on NTFS!
1626  data = (UINT8*)malloc(fsd.StreamSize.QuadPart);
1627 
1628  if (!ReadFile(stream, data, fsd.StreamSize.QuadPart, &bytesret, NULL)) {
1629  free(data);
1630  CloseHandle(stream);
1631  goto end;
1632  }
1633 
1634  CloseHandle(stream);
1635  }
1636 
1637  stream = CreateFileW((destdir + destname + sn).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_NEW, 0, NULL);
1638 
1639  if (stream == INVALID_HANDLE_VALUE) {
1640  if (data) free(data);
1641  goto end;
1642  }
1643 
1644  if (data) {
1645  if (!WriteFile(stream, data, fsd.StreamSize.QuadPart, &bytesret, NULL)) {
1646  free(data);
1647  CloseHandle(stream);
1648  goto end;
1649  }
1650 
1651  free(data);
1652  }
1653 
1654  CloseHandle(stream);
1655  }
1656  } while (FindNextStreamW(h, &fsd));
1657 
1658  FindClose(h);
1659  }
1660  }
1661 
1662  atime.dwLowDateTime = fbi.LastAccessTime.LowPart;
1663  atime.dwHighDateTime = fbi.LastAccessTime.HighPart;
1664  mtime.dwLowDateTime = fbi.LastWriteTime.LowPart;
1665  mtime.dwHighDateTime = fbi.LastWriteTime.HighPart;
1666  SetFileTime(dest, NULL, &atime, &mtime);
1667 
1668  Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_XATTRS, NULL, 0, &bsxa, sizeof(btrfs_set_xattr));
1669 
1670  if (Status == STATUS_BUFFER_OVERFLOW || (NT_SUCCESS(Status) && bsxa.valuelen > 0)) {
1671  ULONG xalen = 0;
1672  btrfs_set_xattr *xa = NULL, *xa2;
1673 
1674  do {
1675  xalen += 1024;
1676 
1677  if (xa) free(xa);
1678  xa = (btrfs_set_xattr*)malloc(xalen);
1679 
1680  Status = NtFsControlFile(source, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_GET_XATTRS, NULL, 0, xa, xalen);
1681  } while (Status == STATUS_BUFFER_OVERFLOW);
1682 
1683  if (!NT_SUCCESS(Status)) {
1684  free(xa);
1685  goto end;
1686  }
1687 
1688  xa2 = xa;
1689  while (xa2->valuelen > 0) {
1690  Status = NtFsControlFile(dest, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_XATTR, xa2,
1691  offsetof(btrfs_set_xattr, data[0]) + xa2->namelen + xa2->valuelen, NULL, 0);
1692  if (!NT_SUCCESS(Status)) {
1693  free(xa);
1694  goto end;
1695  }
1696  xa2 = (btrfs_set_xattr*)&xa2->data[xa2->namelen + xa2->valuelen];
1697  }
1698 
1699  free(xa);
1700  } else if (!NT_SUCCESS(Status))
1701  goto end;
1702 
1703  ret = TRUE;
1704 
1705 end:
1706  if (!ret) {
1707  FILE_DISPOSITION_INFO fdi;
1708 
1709  fdi.DeleteFile = TRUE;
1710  SetFileInformationByHandle(dest, FileDispositionInfo, &fdi, sizeof(FILE_DISPOSITION_INFO));
1711  }
1712 
1713  CloseHandle(dest);
1714  CloseHandle(source);
1715 }
1716 
1717 void CALLBACK ReflinkCopyW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
1718  LPWSTR* args;
1719  int num_args;
1720 
1721  args = CommandLineToArgvW(lpszCmdLine, &num_args);
1722 
1723  if (!args)
1724  return;
1725 
1726  if (num_args >= 2) {
1727  HANDLE destdirh;
1728  BOOL dest_is_dir = FALSE;
1729  std::wstring dest = args[num_args - 1], destdir, destname;
1730  WCHAR volpath2[MAX_PATH];
1731  int i;
1732 
1734  if (destdirh != INVALID_HANDLE_VALUE) {
1736 
1737  if (GetFileInformationByHandle(destdirh, &bhfi) && bhfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1738  dest_is_dir = TRUE;
1739 
1740  destdir = dest;
1741  if (destdir.substr(destdir.length() - 1, 1) != L"\\")
1742  destdir += L"\\";
1743  }
1744  CloseHandle(destdirh);
1745  }
1746 
1747  if (!dest_is_dir) {
1748  size_t found = dest.rfind(L"\\");
1749 
1750  if (found == std::wstring::npos) {
1751  destdir = L"";
1752  destname = dest;
1753  } else {
1754  destdir = dest.substr(0, found);
1755  destname = dest.substr(found + 1);
1756  }
1757  }
1758 
1759  if (!GetVolumePathNameW(dest.c_str(), volpath2, sizeof(volpath2) / sizeof(WCHAR)))
1760  goto end;
1761 
1762  for (i = 0; i < num_args - 1; i++) {
1763  WIN32_FIND_DATAW ffd;
1764  HANDLE h;
1765 
1766  h = FindFirstFileW(args[i], &ffd);
1767  if (h != INVALID_HANDLE_VALUE) {
1768  WCHAR volpath1[MAX_PATH];
1769  std::wstring path = args[i];
1770  size_t found = path.rfind(L"\\");
1771 
1772  if (found == std::wstring::npos)
1773  path = L"";
1774  else
1775  path = path.substr(0, found);
1776 
1777  path += L"\\";
1778 
1779  if (get_volume_path_parent(path.c_str(), volpath1, sizeof(volpath1) / sizeof(WCHAR))) {
1780  if (!wcscmp(volpath1, volpath2)) {
1781  do {
1782  reflink_copy2(path + ffd.cFileName, destdir, dest_is_dir ? ffd.cFileName : destname);
1783  } while (FindNextFileW(h, &ffd));
1784  }
1785  }
1786 
1787  FindClose(h);
1788  }
1789  }
1790  }
1791 
1792 end:
1793  LocalFree(args);
1794 }
#define FSCTL_SET_SPARSE
Definition: winioctl.h:100
HRESULT CreateBitmapFromHICON([in] HICON hIcon, [out] IWICBitmap **ppIBitmap)
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:380
#define HDC
Definition: msvc.h:22
DWORD WINAPI GetModuleFileNameW(HINSTANCE hModule, LPWSTR lpFilename, DWORD nSize)
Definition: loader.c:606
const DOCKBAR PVOID HWND HWND * hwnd
Definition: tooldock.h:22
#define ERROR_FILE_EXISTS
Definition: winerror.h:165
BOOL WINAPI PathRemoveFileSpecW(LPWSTR lpszPath)
Definition: path.c:598
unsigned short WORD
Definition: ntddk_ex.h:93
static UINT64 __inline sector_align(UINT64 n, UINT64 a)
#define REFIID
Definition: guiddef.h:113
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
ULONG __stdcall AddRef()
Definition: contextmenu.h:49
basic_stringstream< wchar_t, char_traits< wchar_t >, allocator< wchar_t > > wstringstream
Definition: _iosfwd.h:145
#define E_NOINTERFACE
Definition: winerror.h:2364
#define IMAGE_ICON
Definition: winuser.h:212
#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
#define HBITMAP
Definition: msvc.h:28
const GUID IID_IUnknown
BITMAPINFOHEADER bmiHeader
Definition: wingdi.h:1453
#define BTRFS_TYPE_SOCKET
Definition: shellext.h:71
void WINAPI PathStripPathW(LPWSTR lpszPath)
Definition: path.c:663
static HMENU hmenu
Definition: win.c:79
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)
Definition: bidi.c:75
#define SEND_VERBW
Definition: contextmenu.cpp:61
void WINAPI ReleaseStgMedium(STGMEDIUM *pmedium)
Definition: ole2.c:2000
USHORT wMonth
Definition: rtltypes.h:1568
HDC WINAPI GetDC(_In_opt_ HWND)
#define NEW_SUBVOL_VERBW
Definition: contextmenu.cpp:53
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)
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define BTRFS_TYPE_BLOCKDEV
Definition: shellext.h:69
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
UINT64 st_rdev
Definition: btrfsioctl.h:232
#define BTRFS_TYPE_FIFO
Definition: shellext.h:70
BOOL WINAPI SHGetPathFromIDListW(LPCITEMIDLIST pidl, LPWSTR pszPath)
Definition: pidl.c:1280
#define CALLBACK
Definition: compat.h:27
static const size_t npos
Definition: _string_npos.h:26
void ShowNtStatusError(HWND hwnd, NTSTATUS Status)
Definition: main.cpp:89
GLdouble GLdouble t
Definition: gl.h:2047
HANDLE HWND
Definition: compat.h:13
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
HRESULT GetData([in, unique] FORMATETC *pformatetcIn, [out] STGMEDIUM *pmedium)
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1056
#define ZeroMemory
Definition: winbase.h:1621
#define SM_CYSMICON
Definition: winuser.h:993
#define RECV_VERBW
Definition: contextmenu.cpp:59
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
LPWSTR dwTypeData
Definition: winuser.h:3201
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:543
wchar_t * STRSAFE_LPWSTR
Definition: ntstrsafe.h:63
GLuint GLuint end
Definition: gl.h:1545
__u16 time
Definition: mkdosfs.c:366
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
void ShowError(HWND hwnd, ULONG err)
Definition: main.cpp:49
#define BTRFS_TYPE_CHARDEV
Definition: shellext.h:68
#define FSCTL_GET_REPARSE_POINT
Definition: winioctl.h:97
char * LPSTR
Definition: xmlstorage.h:182
#define WCHAR
Definition: msvc.h:43
#define E_FAIL
Definition: ddrawi.h:102
GLint namelen
Definition: glext.h:7232
#define DWORD
Definition: msvc.h:34
int WINAPI LoadStringW(_In_opt_ HINSTANCE hInstance, _In_ UINT uID, _Out_writes_to_(cchBufferMax, return+1) LPWSTR lpBuffer, _In_ int cchBufferMax)
#define STRSAFE_E_INSUFFICIENT_BUFFER
Definition: strsafe.h:103
WCHAR path[MAX_PATH]
Definition: contextmenu.h:76
#define IDS_RECV_SUBVOL_HELP
Definition: resource.h:130
#define MIIM_BITMAP
Definition: winuser.h:723
#define SEVERITY_SUCCESS
Definition: winerror.h:64
#define SEND_VERBA
Definition: contextmenu.cpp:60
#define FILE_SHARE_READ
Definition: compat.h:125
#define SNAPSHOT_VERBA
Definition: contextmenu.cpp:54
GLuint GLuint stream
Definition: glext.h:7522
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
virtual HRESULT __stdcall InvokeCommand(LPCMINVOKECOMMANDINFO pici)
STRSAFEAPI StringCchCatW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:325
BOOL WINAPI SetFileTime(IN HANDLE hFile, CONST FILETIME *lpCreationTime OPTIONAL, CONST FILETIME *lpLastAccessTime OPTIONAL, CONST FILETIME *lpLastWriteTime OPTIONAL)
Definition: fileinfo.c:1033
UINT16 namelen
Definition: btrfsioctl.h:233
uint32_t ULONG_PTR
Definition: typedefs.h:64
UINT8 type
Definition: btrfsioctl.h:231
static HMODULE dll
Definition: str.c:188
GLuint const GLchar * name
Definition: glext.h:6031
GLuint n
Definition: s_context.h:57
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
USHORT wYear
Definition: rtltypes.h:1567
GLenum GLclampf GLint i
Definition: glfuncs.h:14
static void reflink_copy2(std::wstring srcfn, std::wstring destdir, std::wstring destname)
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define FILE_ADD_FILE
Definition: nt_native.h:632
#define FALSE
Definition: types.h:117
#define IDS_SEND_SUBVOL_HELP
Definition: resource.h:176
#define FSCTL_BTRFS_CREATE_SNAPSHOT
Definition: btrfsioctl.h:10
HANDLE WINAPI LoadImageW(_In_opt_ HINSTANCE, _In_ LPCWSTR, _In_ UINT, _In_ int, _In_ int, _In_ UINT)
Definition: cursoricon.c:2174
#define BTRFS_INODE_COMPRESS
Definition: propsheet.h:86
long LONG
Definition: pedump.c:60
Definition: main.c:426
#define a
Definition: ke_i.h:78
#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
static const IUnknown void **static void **static RGBQUAD *static HINSTANCE hinst
Definition: imagelist.c:73
int WINAPI ReleaseDC(_In_opt_ HWND, _In_ HDC)
DWORD biCompression
Definition: amvideo.idl:35
PIN_DIRECTION dir
Definition: strmbase.h:226
ULONG Release()
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:570
LPWSTR *WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int *numargs)
Definition: shell32_main.c:75
#define IDS_NEW_SUBVOL_HELP_TEXT
Definition: resource.h:6
#define E_INVALIDARG
Definition: ddrawi.h:101
HDC hdc
Definition: msvc.h:53
const WCHAR * str
smooth NULL
Definition: ftsmooth.c:513
#define offsetof(TYPE, MEMBER)
char ext[3]
Definition: mkdosfs.c:358
#define CF_HDROP
Definition: constants.h:410
LONG cx
Definition: windef.h:347
LPWSTR WINAPI PathFindFileNameW(LPCWSTR lpszPath)
Definition: path.c:371
#define IDS_CREATE_SNAPSHOT
Definition: resource.h:10
UINT8 compression_type
Definition: btrfsioctl.h:79
#define RECV_VERBA
Definition: contextmenu.cpp:58
BOOL WINAPI DECLSPEC_HOTPATCH ShellExecuteExW(LPSHELLEXECUTEINFOW sei)
Definition: shlexec.cpp:2219
VOID WINAPI GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:276
#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:424
#define FILE_ATTRIBUTE_REPARSE_POINT
Definition: ntifs_ex.h:381
#define OPEN_EXISTING
Definition: compat.h:426
USHORT ReparseDataLength
Definition: contextmenu.cpp:65
#define b
Definition: ke_i.h:79
#define FSCTL_BTRFS_CREATE_SUBVOL
Definition: btrfsioctl.h:9
#define MIIM_ID
Definition: winuser.h:717
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define IDS_REFLINK_PASTE_HELP
Definition: resource.h:128
HRESULT GetSize([out] UINT *puiWidth, [out] UINT *puiHeight)
STGMEDIUM stgm
Definition: contextmenu.h:77
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
static HRESULT Create32BitHBITMAP(HDC hdc, const SIZE *psize, void **ppvBits, HBITMAP *phBmp)
LARGE_INTEGER SourceFileOffset
Definition: shellext.h:152
GLsizei stride
Definition: glext.h:5848
unsigned int BOOL
Definition: ntddk_ex.h:94
#define IS_INTRESOURCE(i)
Definition: winuser.h:580
BOOL WINAPI GetFileInformationByHandle(HANDLE hFile, LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
Definition: fileinfo.c:588
int WINAPI MessageBoxW(_In_opt_ HWND, _In_opt_ LPCWSTR, _In_opt_ LPCWSTR, _In_ UINT)
virtual HRESULT __stdcall Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
Definition: contextmenu.cpp:86
LONG HRESULT
Definition: typedefs.h:78
HANDLE HKEY
Definition: registry.h:24
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
#define REFLINK_VERBA
Definition: contextmenu.cpp:56
#define MAX_PATH
Definition: compat.h:26
GLfloat CONST GLvector4f CONST GLfloat GLvector4f * dest
Definition: m_xform.h:122
int WINAPI GetSystemMetrics(_In_ int)
GLuint GLuint num
Definition: glext.h:9618
BOOL WINAPI GetFileInformationByHandleEx(HANDLE handle, FILE_INFO_BY_HANDLE_CLASS class, LPVOID info, DWORD size)
#define FSCTL_BTRFS_GET_XATTRS
Definition: btrfsioctl.h:33
#define __stdcall
Definition: typedefs.h:26
static PIO_STATUS_BLOCK iosb
Definition: file.c:95
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
UINT64 inode
Definition: btrfsioctl.h:230
UINT cchMax
BOOL compression_type_changed
Definition: btrfsioctl.h:92
BOOL WINAPI CloseClipboard(void)
Definition: ntwrapper.h:178
#define SM_CXSMICON
Definition: winuser.h:992
HANDLE HINSTANCE
Definition: typedefs.h:76
static BOOL get_volume_path_parent(const WCHAR *fn, WCHAR *volpath, ULONG volpathlen)
int ret
#define IDS_RECV_SUBVOL
Definition: resource.h:129
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
LPVOID NTAPI GlobalLock(HGLOBAL hMem)
Definition: heapmem.c:755
#define FSCTL_BTRFS_MKNOD
Definition: btrfsioctl.h:31
#define SNAPSHOT_VERBW
Definition: contextmenu.cpp:55
#define MB_ICONERROR
Definition: winuser.h:781
#define FILE_ADD_SUBDIRECTORY
Definition: nt_native.h:635
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define FSCTL_BTRFS_GET_FILE_IDS
Definition: btrfsioctl.h:8
BOOL reflink_copy(HWND hwnd, const WCHAR *fn, const WCHAR *dir)
#define IDS_SEND_SUBVOL
Definition: resource.h:175
#define GENERIC_READ
Definition: compat.h:124
#define FSCTL_BTRFS_SET_INODE_INFO
Definition: btrfsioctl.h:12
#define ERROR_MORE_DATA
Definition: dderror.h:13
unsigned char BYTE
Definition: ntddk_ex.h:96
Status
Definition: gdiplustypes.h:24
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID iid, LPVOID *ppv)
Definition: compobj.c:3185
HRESULT CopyPixels([in] const WICRect *prc, [in] UINT cbStride, [in] UINT cbBufferSize, [out, size_is(cbBufferSize)] BYTE *pbBuffer)
USHORT wDay
Definition: rtltypes.h:1570
#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)
HANDLE WINAPI FindFirstStreamW(IN LPCWSTR lpFileName, IN STREAM_INFO_LEVELS InfoLevel, OUT LPVOID lpFindStreamData, IN DWORD dwFlags)
Definition: find.c:954
STRSAFEAPI StringCchCopyA(STRSAFE_LPSTR pszDest, size_t cchDest, STRSAFE_LPCSTR pszSrc)
Definition: strsafe.h:145
#define NT_SUCCESS(StatCode)
Definition: cmd.c:149
#define NEW_SUBVOL_VERBA
Definition: contextmenu.cpp:52
#define S_OK
Definition: intsafe.h:59
struct IContextMenu::tagCMInvokeCommandInfoEx * LPCMINVOKECOMMANDINFOEX
DWORD *typedef HANDLE
Definition: winlogon.h:52
LONG NTSTATUS
Definition: DriverTester.h:11
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:47
unsigned short USHORT
Definition: pedump.c:61
GLsizei GLsizei GLchar * source
Definition: glext.h:6048
LPCWSTR lpParameters
Definition: shellapi.h:308
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1577
#define FSCTL_BTRFS_GET_INODE_INFO
Definition: btrfsioctl.h:11
#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
STRSAFEAPI StringCchPrintfW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszFormat,...)
Definition: strsafe.h:530
Definition: services.c:311
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:220
unsigned int UINT
Definition: ndis.h:50
BOOL NTAPI GlobalUnlock(HGLOBAL hMem)
Definition: heapmem.c:1190
LARGE_INTEGER TargetFileOffset
Definition: shellext.h:153
void CALLBACK ReflinkCopyW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow)
static void InitBitmapInfo(BITMAPINFO *pbmi, ULONG cbInfo, LONG cx, LONG cy, WORD bpp)
HANDLE WINAPI GetClipboardData(_In_ UINT)
BOOL WINAPI FindNextStreamW(IN HANDLE hFindStream, OUT LPVOID lpFindStreamData)
Definition: find.c:1112
#define CreateFileW
Definition: compat.h:400
#define FSCTL_GET_INTEGRITY_INFORMATION
Definition: shellext.h:173
DWORD UINT uFlags
Definition: wglext.h:734
_Out_opt_ int * cx
Definition: commctrl.h:570
BOOL WINAPI SetFileInformationByHandle(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize)
Definition: reactos.cpp:177
Definition: name.c:23
#define REFLINK_VERBW
Definition: contextmenu.cpp:57
#define FILE_FLAG_BACKUP_SEMANTICS
Definition: disk.h:41
WCHAR name[1]
Definition: btrfsioctl.h:234
#define IDS_NEW_SUBVOL
Definition: resource.h:7
#define FSCTL_BTRFS_SET_XATTR
Definition: btrfsioctl.h:34
unsigned int ULONG
Definition: retypes.h:1
HMODULE WINAPI GetModuleHandleW(LPCWSTR lpModuleName)
Definition: loader.c:844
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define malloc
Definition: debug_ros.c:4
DWORD bpp
Definition: surface.c:174
static HBITMAP bitmap
Definition: clipboard.c:1621
#define FSCTL_SET_INTEGRITY_INFORMATION
Definition: shellext.h:174
HRESULT __stdcall QueryInterface(REFIID riid, void **ppObj)
Definition: contextmenu.cpp:71
#define IDS_NEW_SUBVOL_FILENAME
Definition: resource.h:9
#define CREATE_NEW
Definition: disk.h:69
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
unsigned long long UINT64
GLfloat GLfloat p
Definition: glext.h:8902
#define DIB_RGB_COLORS
Definition: wingdi.h:365
#define ss
Definition: i386-dis.c:432
#define INFINITE
Definition: serial.h:102
#define LR_DEFAULTCOLOR
Definition: winuser.h:1067
BSTR search
BOOL WINAPI ReadFile(IN HANDLE hFile, IN LPVOID lpBuffer, IN DWORD nNumberOfBytesToRead, OUT LPDWORD lpNumberOfBytesRead OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:123
unsigned char UINT8
#define memset(x, y, z)
Definition: compat.h:39
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define args
Definition: format.c:66
static const CLSID *static CLSID *static const GUID VARIANT VARIANT *static IServiceProvider DWORD *static HMENU
Definition: ordinal.c:68
UINT WINAPI DragQueryFileW(HDROP hDrop, UINT lFile, LPWSTR lpszwFile, UINT lLength)
Definition: shellole.c:627
LONG cy
Definition: windef.h:348
#define FILE_OPEN_REPARSE_POINT
Definition: from_kernel.h:46
#define BI_RGB
Definition: precomp.h:35
static BOOL show_reflink_paste(WCHAR *path)
#define IDS_REFLINK_PASTE
Definition: resource.h:127
LARGE_INTEGER ByteCount
Definition: shellext.h:154
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:113
#define FSCTL_DUPLICATE_EXTENTS_TO_FILE
Definition: shellext.h:157
GLintptr offset
Definition: glext.h:5920
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:318
static void create_snapshot(HWND hwnd, WCHAR *fn)
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:29
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:500