[NTDLL] Allow shimdata to override the process manifest.
[reactos.git] / dll / shellext / shellbtrfs / recv.cpp
1 /* Copyright (c) Mark Harmstone 2017
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 #include <windows.h>
20 #include <strsafe.h>
21 #include <stddef.h>
22 #include <sys/stat.h>
23 #include <string>
24 #include "recv.h"
25 #include "resource.h"
26
27 #ifndef __REACTOS__
28 #ifndef _MSC_VER
29 #include <cpuid.h>
30 #else
31 #include <intrin.h>
32 #endif
33
34 #include <smmintrin.h>
35 #endif
36
37 #define EA_NTACL "security.NTACL"
38 #define EA_DOSATTRIB "user.DOSATTRIB"
39 #define EA_REPARSE "user.reparse"
40 #define EA_EA "user.EA"
41 #define XATTR_USER "user."
42
43 #ifndef __REACTOS__
44 BOOL have_sse42 = FALSE;
45 #endif
46
47 static const UINT32 crctable[] = {
48 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
49 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
50 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
51 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
52 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
53 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
54 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
55 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
56 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
57 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
58 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
59 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
60 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
61 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
62 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
63 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
64 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
65 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
66 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
67 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
68 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
69 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
70 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
71 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
72 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
73 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
74 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
75 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
76 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
77 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
78 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
79 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
80 };
81
82 // HW code taken from https://github.com/rurban/smhasher/blob/master/crc32_hw.c
83 #define ALIGN_SIZE 0x08UL
84 #define ALIGN_MASK (ALIGN_SIZE - 1)
85 #define CALC_CRC(op, crc, type, buf, len) \
86 do { \
87 for (; (len) >= sizeof (type); (len) -= sizeof(type), buf += sizeof (type)) { \
88 (crc) = op((crc), *(type *) (buf)); \
89 } \
90 } while(0)
91
92 #ifndef __REACTOS__
93 static UINT32 crc32c_hw(const void *input, ULONG len, UINT32 crc) {
94 const char* buf = (const char*)input;
95
96 // Annoyingly, the CRC32 intrinsics don't work properly in modern versions of MSVC -
97 // it compiles _mm_crc32_u8 as if it was _mm_crc32_u32. And because we're apparently
98 // not allowed to use inline asm on amd64, there's no easy way to fix this!
99
100 for (; (len > 0) && ((size_t)buf & ALIGN_MASK); len--, buf++) {
101 #ifdef _MSC_VER
102 crc = crctable[(crc ^ *buf) & 0xff] ^ (crc >> 8);
103 #else
104 crc = _mm_crc32_u8(crc, *buf);
105 #endif
106 }
107
108 #ifdef _AMD64_
109 #ifdef _MSC_VER
110 #pragma warning(push)
111 #pragma warning(disable:4244) // _mm_crc32_u64 wants to return UINT64(!)
112 #pragma warning(disable:4242)
113 #endif
114 CALC_CRC(_mm_crc32_u64, crc, UINT64, buf, len);
115 #ifdef _MSC_VER
116 #pragma warning(pop)
117 #endif
118 #endif
119 CALC_CRC(_mm_crc32_u32, crc, UINT32, buf, len);
120
121 #ifdef _MSC_VER
122 for (; len > 0; len--, buf++) {
123 crc = crctable[(crc ^ *buf) & 0xff] ^ (crc >> 8);
124 }
125 #else
126 CALC_CRC(_mm_crc32_u16, crc, UINT16, buf, len);
127 CALC_CRC(_mm_crc32_u8, crc, UINT8, buf, len);
128 #endif
129
130 return crc;
131 }
132 #endif
133
134 static UINT32 calc_crc32c(UINT32 seed, UINT8* msg, ULONG msglen) {
135 #ifndef __REACTOS__
136 if (have_sse42)
137 return crc32c_hw(msg, msglen, seed);
138 else {
139 #endif
140 UINT32 rem;
141 ULONG i;
142
143 rem = seed;
144
145 for (i = 0; i < msglen; i++) {
146 rem = crctable[(rem ^ msg[i]) & 0xff] ^ (rem >> 8);
147 }
148
149 return rem;
150 #ifndef __REACTOS__
151 }
152 #endif
153 }
154
155 BOOL BtrfsRecv::find_tlv(UINT8* data, ULONG datalen, UINT16 type, void** value, ULONG* len) {
156 ULONG off = 0;
157
158 while (off < datalen) {
159 btrfs_send_tlv* tlv = (btrfs_send_tlv*)(data + off);
160 UINT8* payload = data + off + sizeof(btrfs_send_tlv);
161
162 if (off + sizeof(btrfs_send_tlv) + tlv->length > datalen) // file is truncated
163 return FALSE;
164
165 if (tlv->type == type) {
166 *value = payload;
167 *len = tlv->length;
168 return TRUE;
169 }
170
171 off += sizeof(btrfs_send_tlv) + tlv->length;
172 }
173
174 return FALSE;
175 }
176
177 BOOL BtrfsRecv::utf8_to_utf16(HWND hwnd, char* utf8, ULONG utf8len, std::wstring* utf16) {
178 NTSTATUS Status;
179 ULONG utf16len;
180 WCHAR* buf;
181
182 Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, utf8, utf8len);
183 if (!NT_SUCCESS(Status)) {
184 ShowRecvError(IDS_RECV_RTLUTF8TOUNICODEN_FAILED, Status, format_ntstatus(Status).c_str());
185 return FALSE;
186 }
187
188 buf = (WCHAR*)malloc(utf16len + sizeof(WCHAR));
189
190 if (!buf) {
191 ShowRecvError(IDS_OUT_OF_MEMORY);
192 return FALSE;
193 }
194
195 Status = RtlUTF8ToUnicodeN(buf, utf16len, &utf16len, utf8, utf8len);
196 if (!NT_SUCCESS(Status)) {
197 ShowRecvError(IDS_RECV_RTLUTF8TOUNICODEN_FAILED, Status, format_ntstatus(Status).c_str());
198 free(buf);
199 return FALSE;
200 }
201
202 buf[utf16len / sizeof(WCHAR)] = 0;
203
204 *utf16 = buf;
205
206 free(buf);
207
208 return TRUE;
209 }
210
211 BOOL BtrfsRecv::cmd_subvol(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
212 char* name;
213 BTRFS_UUID* uuid;
214 UINT64* gen;
215 ULONG namelen, uuidlen, genlen, bcslen;
216 btrfs_create_subvol* bcs;
217 NTSTATUS Status;
218 IO_STATUS_BLOCK iosb;
219 std::wstring nameu;
220
221 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&name, &namelen)) {
222 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
223 return FALSE;
224 }
225
226 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_UUID, (void**)&uuid, &uuidlen)) {
227 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"uuid");
228 return FALSE;
229 }
230
231 if (uuidlen < sizeof(BTRFS_UUID)) {
232 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"uuid", uuidlen, sizeof(BTRFS_UUID));
233 return FALSE;
234 }
235
236 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_TRANSID, (void**)&gen, &genlen)) {
237 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"transid");
238 return FALSE;
239 }
240
241 if (genlen < sizeof(UINT64)) {
242 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"transid", genlen, sizeof(UINT64));
243 return FALSE;
244 }
245
246 this->subvol_uuid = *uuid;
247 this->stransid = *gen;
248
249 if (!utf8_to_utf16(hwnd, name, namelen, &nameu))
250 return FALSE;
251
252 bcslen = offsetof(btrfs_create_subvol, name[0]) + (nameu.length() * sizeof(WCHAR));
253 bcs = (btrfs_create_subvol*)malloc(bcslen);
254
255 bcs->readonly = TRUE;
256 bcs->posix = TRUE;
257 bcs->namelen = nameu.length() * sizeof(WCHAR);
258 memcpy(bcs->name, nameu.c_str(), bcs->namelen);
259
260 Status = NtFsControlFile(parent, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, bcslen, NULL, 0);
261 if (!NT_SUCCESS(Status)) {
262 ShowRecvError(IDS_RECV_CREATE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str());
263 return FALSE;
264 }
265
266 subvolpath = dirpath;
267 subvolpath += L"\\";
268 subvolpath += nameu;
269
270 if (dir != INVALID_HANDLE_VALUE)
271 CloseHandle(dir);
272
273 if (master != INVALID_HANDLE_VALUE)
274 CloseHandle(master);
275
276 master = CreateFileW(subvolpath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
277 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL);
278 if (master == INVALID_HANDLE_VALUE) {
279 ShowRecvError(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str());
280 return FALSE;
281 }
282
283 Status = NtFsControlFile(master, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_RESERVE_SUBVOL, bcs, bcslen, NULL, 0);
284 if (!NT_SUCCESS(Status)) {
285 ShowRecvError(IDS_RECV_RESERVE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str());
286 return FALSE;
287 }
288
289 dir = CreateFileW(subvolpath.c_str(), FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE,
290 FILE_SHARE_READ | FILE_SHARE_WRITE,
291 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL);
292 if (dir == INVALID_HANDLE_VALUE) {
293 ShowRecvError(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str());
294 return FALSE;
295 }
296
297 subvolpath += L"\\";
298
299 add_cache_entry(&this->subvol_uuid, this->stransid, subvolpath);
300
301 num_received++;
302
303 return TRUE;
304 }
305
306 void BtrfsRecv::add_cache_entry(BTRFS_UUID* uuid, UINT64 transid, std::wstring path) {
307 subvol_cache sc;
308
309 sc.uuid = *uuid;
310 sc.transid = transid;
311 sc.path = path;
312
313 cache.push_back(sc);
314 }
315
316 BOOL BtrfsRecv::cmd_snapshot(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
317 char* name;
318 BTRFS_UUID *uuid, *parent_uuid;
319 UINT64 *gen, *parent_transid;
320 ULONG namelen, uuidlen, genlen, paruuidlen, partransidlen, bcslen;
321 btrfs_create_snapshot* bcs;
322 NTSTATUS Status;
323 IO_STATUS_BLOCK iosb;
324 std::wstring nameu, parpath;
325 btrfs_find_subvol bfs;
326 WCHAR parpathw[MAX_PATH], volpathw[MAX_PATH];
327 HANDLE subvol;
328
329 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&name, &namelen)) {
330 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
331 return FALSE;
332 }
333
334 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_UUID, (void**)&uuid, &uuidlen)) {
335 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"uuid");
336 return FALSE;
337 }
338
339 if (uuidlen < sizeof(BTRFS_UUID)) {
340 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"uuid", uuidlen, sizeof(BTRFS_UUID));
341 return FALSE;
342 }
343
344 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_TRANSID, (void**)&gen, &genlen)) {
345 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"transid");
346 return FALSE;
347 }
348
349 if (genlen < sizeof(UINT64)) {
350 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"transid", genlen, sizeof(UINT64));
351 return FALSE;
352 }
353
354 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_UUID, (void**)&parent_uuid, &paruuidlen)) {
355 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"clone_uuid");
356 return FALSE;
357 }
358
359 if (paruuidlen < sizeof(BTRFS_UUID)) {
360 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"clone_uuid", paruuidlen, sizeof(BTRFS_UUID));
361 return FALSE;
362 }
363
364 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_CTRANSID, (void**)&parent_transid, &partransidlen)) {
365 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"clone_ctransid");
366 return FALSE;
367 }
368
369 if (partransidlen < sizeof(UINT64)) {
370 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"clone_ctransid", partransidlen, sizeof(UINT64));
371 return FALSE;
372 }
373
374 this->subvol_uuid = *uuid;
375 this->stransid = *gen;
376
377 if (!utf8_to_utf16(hwnd, name, namelen, &nameu))
378 return FALSE;
379
380 bfs.uuid = *parent_uuid;
381 bfs.ctransid = *parent_transid;
382
383 Status = NtFsControlFile(parent, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_FIND_SUBVOL, &bfs, sizeof(btrfs_find_subvol),
384 parpathw, sizeof(parpathw));
385 if (Status == STATUS_NOT_FOUND) {
386 ShowRecvError(IDS_RECV_CANT_FIND_PARENT_SUBVOL);
387 return FALSE;
388 } else if (!NT_SUCCESS(Status)) {
389 ShowRecvError(IDS_RECV_FIND_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str());
390 return FALSE;
391 }
392
393 if (!GetVolumePathNameW(dirpath.c_str(), volpathw, (sizeof(volpathw) / sizeof(WCHAR)) - 1)) {
394 ShowRecvError(IDS_RECV_GETVOLUMEPATHNAME_FAILED, GetLastError(), format_message(GetLastError()).c_str());
395 return FALSE;
396 }
397
398 parpath = volpathw;
399 if (parpath.substr(parpath.length() - 1) == L"\\")
400 parpath = parpath.substr(0, parpath.length() - 1);
401
402 parpath += parpathw;
403
404 subvol = CreateFileW(parpath.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
405 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
406 if (subvol == INVALID_HANDLE_VALUE) {
407 ShowRecvError(IDS_RECV_CANT_OPEN_PATH, parpath.c_str(), GetLastError(), format_message(GetLastError()).c_str());
408 return FALSE;
409 }
410
411 bcslen = offsetof(btrfs_create_snapshot, name[0]) + (nameu.length() * sizeof(WCHAR));
412 bcs = (btrfs_create_snapshot*)malloc(bcslen);
413
414 bcs->readonly = TRUE;
415 bcs->posix = TRUE;
416 bcs->subvol = subvol;
417 bcs->namelen = nameu.length() * sizeof(WCHAR);
418 memcpy(bcs->name, nameu.c_str(), bcs->namelen);
419
420 Status = NtFsControlFile(parent, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, bcslen, NULL, 0);
421 if (!NT_SUCCESS(Status)) {
422 ShowRecvError(IDS_RECV_CREATE_SNAPSHOT_FAILED, Status, format_ntstatus(Status).c_str());
423 return FALSE;
424 }
425
426 subvolpath = dirpath;
427 subvolpath += L"\\";
428 subvolpath += nameu;
429
430 if (dir != INVALID_HANDLE_VALUE)
431 CloseHandle(dir);
432
433 if (master != INVALID_HANDLE_VALUE)
434 CloseHandle(master);
435
436 master = CreateFileW(subvolpath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
437 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL);
438 if (master == INVALID_HANDLE_VALUE) {
439 ShowRecvError(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str());
440 return FALSE;
441 }
442
443 Status = NtFsControlFile(master, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_RESERVE_SUBVOL, bcs, bcslen, NULL, 0);
444 if (!NT_SUCCESS(Status)) {
445 ShowRecvError(IDS_RECV_RESERVE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str());
446 return FALSE;
447 }
448
449 dir = CreateFileW(subvolpath.c_str(), FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE,
450 FILE_SHARE_READ | FILE_SHARE_WRITE,
451 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL);
452 if (dir == INVALID_HANDLE_VALUE) {
453 ShowRecvError(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str());
454 return FALSE;
455 }
456
457 subvolpath += L"\\";
458
459 add_cache_entry(&this->subvol_uuid, this->stransid, subvolpath);
460
461 num_received++;
462
463 return TRUE;
464 }
465
466 BOOL BtrfsRecv::cmd_mkfile(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
467 char *name, *pathlink;
468 UINT64 *inode, *rdev = NULL, *mode = NULL;
469 ULONG namelen, inodelen, bmnsize;
470 NTSTATUS Status;
471 IO_STATUS_BLOCK iosb;
472 btrfs_mknod* bmn;
473 std::wstring nameu, pathlinku;
474
475 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&name, &namelen)) {
476 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
477 return FALSE;
478 }
479
480 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_INODE, (void**)&inode, &inodelen)) {
481 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"inode");
482 return FALSE;
483 }
484
485 if (inodelen < sizeof(UINT64)) {
486 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"inode", inodelen, sizeof(UINT64));
487 return FALSE;
488 }
489
490 if (cmd->cmd == BTRFS_SEND_CMD_MKNOD || cmd->cmd == BTRFS_SEND_CMD_MKFIFO || cmd->cmd == BTRFS_SEND_CMD_MKSOCK) {
491 ULONG rdevlen, modelen;
492
493 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_RDEV, (void**)&rdev, &rdevlen)) {
494 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"rdev");
495 return FALSE;
496 }
497
498 if (rdevlen < sizeof(UINT64)) {
499 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"rdev", rdev, sizeof(UINT64));
500 return FALSE;
501 }
502
503 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_MODE, (void**)&mode, &modelen)) {
504 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"mode");
505 return FALSE;
506 }
507
508 if (modelen < sizeof(UINT64)) {
509 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"mode", modelen, sizeof(UINT64));
510 return FALSE;
511 }
512 } else if (cmd->cmd == BTRFS_SEND_CMD_SYMLINK) {
513 ULONG pathlinklen;
514
515 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_LINK, (void**)&pathlink, &pathlinklen)) {
516 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path_link");
517 return FALSE;
518 }
519
520 if (!utf8_to_utf16(hwnd, pathlink, pathlinklen, &pathlinku))
521 return FALSE;
522 }
523
524 if (!utf8_to_utf16(hwnd, name, namelen, &nameu))
525 return FALSE;
526
527 bmnsize = sizeof(btrfs_mknod) - sizeof(WCHAR) + (nameu.length() * sizeof(WCHAR));
528 bmn = (btrfs_mknod*)malloc(bmnsize);
529
530 bmn->inode = *inode;
531
532 if (cmd->cmd == BTRFS_SEND_CMD_MKDIR)
533 bmn->type = BTRFS_TYPE_DIRECTORY;
534 else if (cmd->cmd == BTRFS_SEND_CMD_MKNOD)
535 bmn->type = *mode & S_IFCHR ? BTRFS_TYPE_CHARDEV : BTRFS_TYPE_BLOCKDEV;
536 else if (cmd->cmd == BTRFS_SEND_CMD_MKFIFO)
537 bmn->type = BTRFS_TYPE_FIFO;
538 else if (cmd->cmd == BTRFS_SEND_CMD_MKSOCK)
539 bmn->type = BTRFS_TYPE_SOCKET;
540 else
541 bmn->type = BTRFS_TYPE_FILE;
542
543 bmn->st_rdev = rdev ? *rdev : 0;
544 bmn->namelen = nameu.length() * sizeof(WCHAR);
545 memcpy(bmn->name, nameu.c_str(), bmn->namelen);
546
547 Status = NtFsControlFile(dir, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_MKNOD, bmn, bmnsize, NULL, 0);
548 if (!NT_SUCCESS(Status)) {
549 ShowRecvError(IDS_RECV_MKNOD_FAILED, Status, format_ntstatus(Status).c_str());
550 free(bmn);
551 return FALSE;
552 }
553
554 free(bmn);
555
556 if (cmd->cmd == BTRFS_SEND_CMD_SYMLINK) {
557 HANDLE h;
558 REPARSE_DATA_BUFFER* rdb;
559 ULONG rdblen;
560 btrfs_set_inode_info bsii;
561
562 rdblen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]) + (2 * pathlinku.length() * sizeof(WCHAR));
563
564 rdb = (REPARSE_DATA_BUFFER*)malloc(rdblen);
565
566 rdb->ReparseTag = IO_REPARSE_TAG_SYMLINK;
567 rdb->ReparseDataLength = rdblen - offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer);
568 rdb->Reserved = 0;
569 rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
570 rdb->SymbolicLinkReparseBuffer.SubstituteNameLength = pathlinku.length() * sizeof(WCHAR);
571 rdb->SymbolicLinkReparseBuffer.PrintNameOffset = pathlinku.length() * sizeof(WCHAR);
572 rdb->SymbolicLinkReparseBuffer.PrintNameLength = pathlinku.length() * sizeof(WCHAR);
573 rdb->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
574
575 memcpy(rdb->SymbolicLinkReparseBuffer.PathBuffer, pathlinku.c_str(), rdb->SymbolicLinkReparseBuffer.SubstituteNameLength);
576 memcpy(rdb->SymbolicLinkReparseBuffer.PathBuffer + (rdb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR)),
577 pathlinku.c_str(), rdb->SymbolicLinkReparseBuffer.PrintNameLength);
578
579 h = CreateFileW((subvolpath + nameu).c_str(), GENERIC_WRITE | WRITE_DAC, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
580 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL);
581 if (h == INVALID_HANDLE_VALUE) {
582 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, nameu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
583 free(rdb);
584 return FALSE;
585 }
586
587 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_SET_REPARSE_POINT, rdb, rdblen, NULL, 0);
588 if (!NT_SUCCESS(Status)) {
589 ShowRecvError(IDS_RECV_SET_REPARSE_POINT_FAILED, Status, format_ntstatus(Status).c_str());
590 free(rdb);
591 CloseHandle(h);
592 return FALSE;
593 }
594
595 free(rdb);
596
597 memset(&bsii, 0, sizeof(btrfs_set_inode_info));
598
599 bsii.mode_changed = TRUE;
600 bsii.st_mode = 0777;
601
602 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), NULL, 0);
603 if (!NT_SUCCESS(Status)) {
604 ShowRecvError(IDS_RECV_SETINODEINFO_FAILED, Status, format_ntstatus(Status).c_str());
605 CloseHandle(h);
606 return FALSE;
607 }
608
609 CloseHandle(h);
610 } else if (cmd->cmd == BTRFS_SEND_CMD_MKNOD || cmd->cmd == BTRFS_SEND_CMD_MKFIFO || cmd->cmd == BTRFS_SEND_CMD_MKSOCK) {
611 UINT64* mode;
612 ULONG modelen;
613
614 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_MODE, (void**)&mode, &modelen)) {
615 HANDLE h;
616 btrfs_set_inode_info bsii;
617
618 if (modelen < sizeof(UINT64)) {
619 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"mode", modelen, sizeof(UINT64));
620 return FALSE;
621 }
622
623 h = CreateFileW((subvolpath + nameu).c_str(), WRITE_DAC, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
624 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL);
625 if (h == INVALID_HANDLE_VALUE) {
626 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, nameu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
627 return FALSE;
628 }
629
630 memset(&bsii, 0, sizeof(btrfs_set_inode_info));
631
632 bsii.mode_changed = TRUE;
633 bsii.st_mode = *mode;
634
635 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), NULL, 0);
636 if (!NT_SUCCESS(Status)) {
637 ShowRecvError(IDS_RECV_SETINODEINFO_FAILED, Status, format_ntstatus(Status).c_str());
638 CloseHandle(h);
639 return FALSE;
640 }
641
642 CloseHandle(h);
643 }
644 }
645
646 return TRUE;
647 }
648
649 BOOL BtrfsRecv::cmd_rename(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
650 char *path, *path_to;
651 ULONG path_len, path_to_len;
652 std::wstring pathu, path_tou;
653
654 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &path_len)) {
655 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
656 return FALSE;
657 }
658
659 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_TO, (void**)&path_to, &path_to_len)) {
660 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path_to");
661 return FALSE;
662 }
663
664 if (!utf8_to_utf16(hwnd, path, path_len, &pathu))
665 return FALSE;
666
667 if (!utf8_to_utf16(hwnd, path_to, path_to_len, &path_tou))
668 return FALSE;
669
670 if (!MoveFileW((subvolpath + pathu).c_str(), (subvolpath + path_tou).c_str())) {
671 ShowRecvError(IDS_RECV_MOVEFILE_FAILED, pathu.c_str(), path_tou.c_str(), GetLastError(), format_message(GetLastError()).c_str());
672 return FALSE;
673 }
674
675 return TRUE;
676 }
677
678 BOOL BtrfsRecv::cmd_link(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
679 char *path, *path_link;
680 ULONG path_len, path_link_len;
681 std::wstring pathu, path_linku;
682
683 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &path_len)) {
684 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
685 return FALSE;
686 }
687
688 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_LINK, (void**)&path_link, &path_link_len)) {
689 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path_link");
690 return FALSE;
691 }
692
693 if (!utf8_to_utf16(hwnd, path, path_len, &pathu))
694 return FALSE;
695
696 if (!utf8_to_utf16(hwnd, path_link, path_link_len, &path_linku))
697 return FALSE;
698
699 if (!CreateHardLinkW((subvolpath + pathu).c_str(), (subvolpath + path_linku).c_str(), NULL)) {
700 ShowRecvError(IDS_RECV_CREATEHARDLINK_FAILED, pathu.c_str(), path_linku.c_str(), GetLastError(), format_message(GetLastError()).c_str());
701 return FALSE;
702 }
703
704 return TRUE;
705 }
706
707 BOOL BtrfsRecv::cmd_unlink(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
708 char* path;
709 ULONG pathlen;
710 std::wstring pathu;
711 ULONG att;
712
713 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) {
714 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
715 return FALSE;
716 }
717
718 if (!utf8_to_utf16(hwnd, path, pathlen, &pathu))
719 return FALSE;
720
721 att = GetFileAttributesW((subvolpath + pathu).c_str());
722 if (att == INVALID_FILE_ATTRIBUTES) {
723 ShowRecvError(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
724 return FALSE;
725 }
726
727 if (att & FILE_ATTRIBUTE_READONLY) {
728 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att & ~FILE_ATTRIBUTE_READONLY)) {
729 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
730 return FALSE;
731 }
732 }
733
734 if (!DeleteFileW((subvolpath + pathu).c_str())) {
735 ShowRecvError(IDS_RECV_DELETEFILE_FAILED, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
736 return FALSE;
737 }
738
739 return TRUE;
740 }
741
742 BOOL BtrfsRecv::cmd_rmdir(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
743 char* path;
744 ULONG pathlen;
745 std::wstring pathu;
746 ULONG att;
747
748 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) {
749 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
750 return FALSE;
751 }
752
753 if (!utf8_to_utf16(hwnd, path, pathlen, &pathu))
754 return FALSE;
755
756 att = GetFileAttributesW((subvolpath + pathu).c_str());
757 if (att == INVALID_FILE_ATTRIBUTES) {
758 ShowRecvError(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
759 return FALSE;
760 }
761
762 if (att & FILE_ATTRIBUTE_READONLY) {
763 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att & ~FILE_ATTRIBUTE_READONLY)) {
764 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
765 return FALSE;
766 }
767 }
768
769 if (!RemoveDirectoryW((subvolpath + pathu).c_str())) {
770 ShowRecvError(IDS_RECV_REMOVEDIRECTORY_FAILED, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
771 return FALSE;
772 }
773
774 return TRUE;
775 }
776
777 BOOL BtrfsRecv::cmd_setxattr(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
778 char *path, *xattrname;
779 UINT8* xattrdata;
780 ULONG pathlen, xattrnamelen, xattrdatalen;
781 std::wstring pathu;
782
783 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) {
784 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
785 return FALSE;
786 }
787
788 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_XATTR_NAME, (void**)&xattrname, &xattrnamelen)) {
789 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"xattr_name");
790 return FALSE;
791 }
792
793 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_XATTR_DATA, (void**)&xattrdata, &xattrdatalen)) {
794 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"xattr_data");
795 return FALSE;
796 }
797
798 if (!utf8_to_utf16(hwnd, path, pathlen, &pathu))
799 return FALSE;
800
801 if (xattrnamelen > strlen(XATTR_USER) && !memcmp(xattrname, XATTR_USER, strlen(XATTR_USER)) &&
802 (xattrnamelen != strlen(EA_DOSATTRIB) || memcmp(xattrname, EA_DOSATTRIB, xattrnamelen)) &&
803 (xattrnamelen != strlen(EA_EA) || memcmp(xattrname, EA_EA, xattrnamelen)) &&
804 (xattrnamelen != strlen(EA_REPARSE) || memcmp(xattrname, EA_REPARSE, xattrnamelen))) {
805 HANDLE h;
806 std::wstring streamname;
807 ULONG att;
808
809 if (!utf8_to_utf16(hwnd, xattrname, xattrnamelen, &streamname))
810 return FALSE;
811
812 att = GetFileAttributesW((subvolpath + pathu).c_str());
813 if (att == INVALID_FILE_ATTRIBUTES) {
814 ShowRecvError(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
815 return FALSE;
816 }
817
818 if (att & FILE_ATTRIBUTE_READONLY) {
819 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att & ~FILE_ATTRIBUTE_READONLY)) {
820 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
821 return FALSE;
822 }
823 }
824
825 streamname = streamname.substr(strlen(XATTR_USER));
826
827 h = CreateFileW((subvolpath + pathu + L":" + streamname).c_str(), GENERIC_WRITE, 0,
828 NULL, CREATE_ALWAYS, FILE_FLAG_POSIX_SEMANTICS, NULL);
829 if (h == INVALID_HANDLE_VALUE) {
830 ShowRecvError(IDS_RECV_CANT_CREATE_FILE, (pathu + L":" + streamname).c_str(), GetLastError(), format_message(GetLastError()).c_str());
831 return FALSE;
832 }
833
834 if (xattrdatalen > 0) {
835 if (!WriteFile(h, xattrdata, xattrdatalen, NULL, NULL)) {
836 ShowRecvError(IDS_RECV_WRITEFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str());
837 CloseHandle(h);
838 return FALSE;
839 }
840 }
841
842 CloseHandle(h);
843
844 if (att & FILE_ATTRIBUTE_READONLY) {
845 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att)) {
846 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
847 return FALSE;
848 }
849 }
850 } else {
851 HANDLE h;
852 IO_STATUS_BLOCK iosb;
853 NTSTATUS Status;
854 ULONG bsxalen, perms = FILE_WRITE_ATTRIBUTES;
855 btrfs_set_xattr* bsxa;
856
857 if (xattrnamelen == strlen(EA_NTACL) && !memcmp(xattrname, EA_NTACL, xattrnamelen))
858 perms |= WRITE_DAC | WRITE_OWNER;
859 else if (xattrnamelen == strlen(EA_EA) && !memcmp(xattrname, EA_EA, xattrnamelen))
860 perms |= FILE_WRITE_EA;
861
862 h = CreateFileW((subvolpath + pathu).c_str(), perms, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
863 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_OPEN_REPARSE_POINT, NULL);
864 if (h == INVALID_HANDLE_VALUE) {
865 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
866 return FALSE;
867 }
868
869 bsxalen = offsetof(btrfs_set_xattr, data[0]) + xattrnamelen + xattrdatalen;
870 bsxa = (btrfs_set_xattr*)malloc(bsxalen);
871 if (!bsxa) {
872 ShowRecvError(IDS_OUT_OF_MEMORY);
873 CloseHandle(h);
874 return FALSE;
875 }
876
877 bsxa->namelen = xattrnamelen;
878 bsxa->valuelen = xattrdatalen;
879 memcpy(bsxa->data, xattrname, xattrnamelen);
880 memcpy(&bsxa->data[xattrnamelen], xattrdata, xattrdatalen);
881
882 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_XATTR, bsxa, bsxalen, NULL, 0);
883 if (!NT_SUCCESS(Status)) {
884 ShowRecvError(IDS_RECV_SETXATTR_FAILED, Status, format_ntstatus(Status).c_str());
885 free(bsxa);
886 CloseHandle(h);
887 return FALSE;
888 }
889
890 free(bsxa);
891 CloseHandle(h);
892 }
893
894 return TRUE;
895 }
896
897 BOOL BtrfsRecv::cmd_removexattr(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
898 char *path, *xattrname;
899 ULONG pathlen, xattrnamelen;
900 std::wstring pathu;
901
902 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) {
903 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
904 return FALSE;
905 }
906
907 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_XATTR_NAME, (void**)&xattrname, &xattrnamelen)) {
908 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"xattr_name");
909 return FALSE;
910 }
911
912 if (!utf8_to_utf16(hwnd, path, pathlen, &pathu))
913 return FALSE;
914
915 if (xattrnamelen > strlen(XATTR_USER) && !memcmp(xattrname, XATTR_USER, strlen(XATTR_USER)) &&
916 (xattrnamelen != strlen(EA_DOSATTRIB) || memcmp(xattrname, EA_DOSATTRIB, xattrnamelen)) &&
917 (xattrnamelen != strlen(EA_EA) || memcmp(xattrname, EA_EA, xattrnamelen))) { // deleting stream
918 ULONG att;
919 std::wstring streamname;
920
921 if (!utf8_to_utf16(hwnd, xattrname, xattrnamelen, &streamname))
922 return FALSE;
923
924 streamname = streamname.substr(strlen(XATTR_USER));
925
926 att = GetFileAttributesW((subvolpath + pathu).c_str());
927 if (att == INVALID_FILE_ATTRIBUTES) {
928 ShowRecvError(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
929 return FALSE;
930 }
931
932 if (att & FILE_ATTRIBUTE_READONLY) {
933 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att & ~FILE_ATTRIBUTE_READONLY)) {
934 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
935 return FALSE;
936 }
937 }
938
939 if (!DeleteFileW((subvolpath + pathu + L":" + streamname).c_str())) {
940 ShowRecvError(IDS_RECV_DELETEFILE_FAILED, (pathu + L":" + streamname).c_str(), GetLastError(), format_message(GetLastError()).c_str());
941 return FALSE;
942 }
943
944 if (att & FILE_ATTRIBUTE_READONLY) {
945 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att)) {
946 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
947 return FALSE;
948 }
949 }
950 } else {
951 HANDLE h;
952 IO_STATUS_BLOCK iosb;
953 NTSTATUS Status;
954 ULONG bsxalen, perms = FILE_WRITE_ATTRIBUTES;
955 btrfs_set_xattr* bsxa;
956
957 if (xattrnamelen == strlen(EA_NTACL) && !memcmp(xattrname, EA_NTACL, xattrnamelen))
958 perms |= WRITE_DAC | WRITE_OWNER;
959 else if (xattrnamelen == strlen(EA_EA) && !memcmp(xattrname, EA_EA, xattrnamelen))
960 perms |= FILE_WRITE_EA;
961
962 h = CreateFileW((subvolpath + pathu).c_str(), perms, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
963 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_OPEN_REPARSE_POINT, NULL);
964 if (h == INVALID_HANDLE_VALUE) {
965 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
966 return FALSE;
967 }
968
969 bsxalen = offsetof(btrfs_set_xattr, data[0]) + xattrnamelen;
970 bsxa = (btrfs_set_xattr*)malloc(bsxalen);
971 if (!bsxa) {
972 ShowRecvError(IDS_OUT_OF_MEMORY);
973 CloseHandle(h);
974 return FALSE;
975 }
976
977 bsxa->namelen = xattrnamelen;
978 bsxa->valuelen = 0;
979 memcpy(bsxa->data, xattrname, xattrnamelen);
980
981 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_XATTR, bsxa, bsxalen, NULL, 0);
982 if (!NT_SUCCESS(Status)) {
983 ShowRecvError(IDS_RECV_SETXATTR_FAILED, Status, format_ntstatus(Status).c_str());
984 free(bsxa);
985 CloseHandle(h);
986 return FALSE;
987 }
988
989 free(bsxa);
990 CloseHandle(h);
991 }
992
993 return TRUE;
994 }
995
996 BOOL BtrfsRecv::cmd_write(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
997 char* path;
998 UINT64* offset;
999 UINT8* writedata;
1000 ULONG pathlen, offsetlen, datalen;
1001 std::wstring pathu;
1002 HANDLE h;
1003 LARGE_INTEGER offli;
1004
1005 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) {
1006 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
1007 return FALSE;
1008 }
1009
1010 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_OFFSET, (void**)&offset, &offsetlen)) {
1011 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"offset");
1012 return FALSE;
1013 }
1014
1015 if (offsetlen < sizeof(UINT64)) {
1016 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"offset", offsetlen, sizeof(UINT64));
1017 return FALSE;
1018 }
1019
1020 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_DATA, (void**)&writedata, &datalen)) {
1021 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"data");
1022 return FALSE;
1023 }
1024
1025 if (!utf8_to_utf16(hwnd, path, pathlen, &pathu))
1026 return FALSE;
1027
1028 if (lastwritepath != pathu) {
1029 FILE_BASIC_INFO fbi;
1030
1031 if (lastwriteatt & FILE_ATTRIBUTE_READONLY) {
1032 if (!SetFileAttributesW((subvolpath + lastwritepath).c_str(), lastwriteatt)) {
1033 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1034 return FALSE;
1035 }
1036 }
1037
1038 CloseHandle(lastwritefile);
1039
1040 lastwriteatt = GetFileAttributesW((subvolpath + pathu).c_str());
1041 if (lastwriteatt == INVALID_FILE_ATTRIBUTES) {
1042 ShowRecvError(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1043 return FALSE;
1044 }
1045
1046 if (lastwriteatt & FILE_ATTRIBUTE_READONLY) {
1047 if (!SetFileAttributesW((subvolpath + pathu).c_str(), lastwriteatt & ~FILE_ATTRIBUTE_READONLY)) {
1048 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1049 return FALSE;
1050 }
1051 }
1052
1053 h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
1054 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL);
1055 if (h == INVALID_HANDLE_VALUE) {
1056 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
1057 return FALSE;
1058 }
1059
1060 lastwritepath = pathu;
1061 lastwritefile = h;
1062
1063 memset(&fbi, 0, sizeof(FILE_BASIC_INFO));
1064
1065 fbi.LastWriteTime.QuadPart = -1;
1066
1067 if (!SetFileInformationByHandle(h, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO))) {
1068 ShowRecvError(IDS_RECV_SETFILEINFO_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1069 return FALSE;
1070 }
1071 } else
1072 h = lastwritefile;
1073
1074 offli.QuadPart = *offset;
1075
1076 if (SetFilePointer(h, offli.LowPart, &offli.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1077 ShowRecvError(IDS_RECV_SETFILEPOINTER_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1078 return FALSE;
1079 }
1080
1081 if (!WriteFile(h, writedata, datalen, NULL, NULL)) {
1082 ShowRecvError(IDS_RECV_WRITEFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1083 return FALSE;
1084 }
1085
1086 return TRUE;
1087 }
1088
1089 BOOL BtrfsRecv::cmd_clone(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
1090 char *path, *clonepath;
1091 UINT64 *offset, *cloneoffset, *clonetransid, *clonelen;
1092 BTRFS_UUID* cloneuuid;
1093 ULONG i, offsetlen, pathlen, clonepathlen, cloneoffsetlen, cloneuuidlen, clonetransidlen, clonelenlen;
1094 std::wstring pathu, clonepathu, clonepar;
1095 btrfs_find_subvol bfs;
1096 NTSTATUS Status;
1097 IO_STATUS_BLOCK iosb;
1098 WCHAR cloneparw[MAX_PATH];
1099 HANDLE src, dest;
1100 DUPLICATE_EXTENTS_DATA ded;
1101 LARGE_INTEGER filesize;
1102 BOOL found = FALSE;
1103
1104 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_OFFSET, (void**)&offset, &offsetlen)) {
1105 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"offset");
1106 return FALSE;
1107 }
1108
1109 if (offsetlen < sizeof(UINT64)) {
1110 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"offset", offsetlen, sizeof(UINT64));
1111 return FALSE;
1112 }
1113
1114 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_LENGTH, (void**)&clonelen, &clonelenlen)) {
1115 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"clone_len");
1116 return FALSE;
1117 }
1118
1119 if (clonelenlen < sizeof(UINT64)) {
1120 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"clone_len", clonelenlen, sizeof(UINT64));
1121 return FALSE;
1122 }
1123
1124 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) {
1125 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
1126 return FALSE;
1127 }
1128
1129 if (!utf8_to_utf16(hwnd, path, pathlen, &pathu))
1130 return FALSE;
1131
1132 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_UUID, (void**)&cloneuuid, &cloneuuidlen)) {
1133 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"clone_uuid");
1134 return FALSE;
1135 }
1136
1137 if (cloneuuidlen < sizeof(BTRFS_UUID)) {
1138 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"clone_uuid", cloneuuidlen, sizeof(BTRFS_UUID));
1139 return FALSE;
1140 }
1141
1142 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_CTRANSID, (void**)&clonetransid, &clonetransidlen)) {
1143 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"clone_ctransid");
1144 return FALSE;
1145 }
1146
1147 if (clonetransidlen < sizeof(UINT64)) {
1148 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"clone_ctransid", clonetransidlen, sizeof(UINT64));
1149 return FALSE;
1150 }
1151
1152 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_PATH, (void**)&clonepath, &clonepathlen)) {
1153 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"clone_path");
1154 return FALSE;
1155 }
1156
1157 if (!utf8_to_utf16(hwnd, clonepath, clonepathlen, &clonepathu))
1158 return FALSE;
1159
1160 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_OFFSET, (void**)&cloneoffset, &cloneoffsetlen)) {
1161 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"clone_offset");
1162 return FALSE;
1163 }
1164
1165 if (cloneoffsetlen < sizeof(UINT64)) {
1166 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"clone_offset", cloneoffsetlen, sizeof(UINT64));
1167 return FALSE;
1168 }
1169
1170 for (i = 0; i < cache.size(); i++) {
1171 if (!memcmp(cloneuuid, &cache[i].uuid, sizeof(BTRFS_UUID)) && *clonetransid == cache[i].transid) {
1172 clonepar = cache[i].path;
1173 found = TRUE;
1174 break;
1175 }
1176 }
1177
1178 if (!found) {
1179 WCHAR volpathw[MAX_PATH];
1180
1181 bfs.uuid = *cloneuuid;
1182 bfs.ctransid = *clonetransid;
1183
1184 Status = NtFsControlFile(dir, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_FIND_SUBVOL, &bfs, sizeof(btrfs_find_subvol),
1185 cloneparw, sizeof(cloneparw));
1186 if (Status == STATUS_NOT_FOUND) {
1187 ShowRecvError(IDS_RECV_CANT_FIND_CLONE_SUBVOL);
1188 return FALSE;
1189 } else if (!NT_SUCCESS(Status)) {
1190 ShowRecvError(IDS_RECV_FIND_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str());
1191 return FALSE;
1192 }
1193
1194 if (!GetVolumePathNameW(dirpath.c_str(), volpathw, (sizeof(volpathw) / sizeof(WCHAR)) - 1)) {
1195 ShowRecvError(IDS_RECV_GETVOLUMEPATHNAME_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1196 return FALSE;
1197 }
1198
1199 clonepar = volpathw;
1200 if (clonepar.substr(clonepar.length() - 1) == L"\\")
1201 clonepar = clonepar.substr(0, clonepar.length() - 1);
1202
1203 clonepar += cloneparw;
1204 clonepar += L"\\";
1205
1206 add_cache_entry(cloneuuid, *clonetransid, clonepar);
1207 }
1208
1209 src = CreateFileW((clonepar + clonepathu).c_str(), FILE_READ_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1210 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT | FILE_FLAG_POSIX_SEMANTICS, NULL);
1211 if (src == INVALID_HANDLE_VALUE) {
1212 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, (clonepar + clonepathu).c_str(), GetLastError(), format_message(GetLastError()).c_str());
1213 return FALSE;
1214 }
1215
1216 dest = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1217 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT | FILE_FLAG_POSIX_SEMANTICS, NULL);
1218 if (dest == INVALID_HANDLE_VALUE) {
1219 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
1220 CloseHandle(src);
1221 return FALSE;
1222 }
1223
1224 if (!GetFileSizeEx(dest, &filesize)) {
1225 ShowRecvError(IDS_RECV_GETFILESIZEEX_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1226 CloseHandle(dest);
1227 CloseHandle(src);
1228 return FALSE;
1229 }
1230
1231 if ((UINT64)filesize.QuadPart < *offset + *clonelen) {
1232 LARGE_INTEGER sizeli;
1233
1234 sizeli.QuadPart = *offset + *clonelen;
1235
1236 if (SetFilePointer(dest, sizeli.LowPart, &sizeli.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1237 ShowRecvError(IDS_RECV_SETFILEPOINTER_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1238 CloseHandle(dest);
1239 CloseHandle(src);
1240 return FALSE;
1241 }
1242
1243 if (!SetEndOfFile(dest)) {
1244 ShowRecvError(IDS_RECV_SETENDOFFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1245 CloseHandle(dest);
1246 CloseHandle(src);
1247 return FALSE;
1248 }
1249 }
1250
1251 ded.FileHandle = src;
1252 ded.SourceFileOffset.QuadPart = *cloneoffset;
1253 ded.TargetFileOffset.QuadPart = *offset;
1254 ded.ByteCount.QuadPart = *clonelen;
1255
1256 Status = NtFsControlFile(dest, NULL, NULL, NULL, &iosb, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &ded, sizeof(DUPLICATE_EXTENTS_DATA),
1257 NULL, 0);
1258 if (!NT_SUCCESS(Status)) {
1259 ShowRecvError(IDS_RECV_DUPLICATE_EXTENTS_FAILED, Status, format_ntstatus(Status).c_str());
1260 CloseHandle(dest);
1261 CloseHandle(src);
1262 return FALSE;
1263 }
1264
1265 CloseHandle(dest);
1266 CloseHandle(src);
1267
1268 return TRUE;
1269 }
1270
1271 BOOL BtrfsRecv::cmd_truncate(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
1272 char* path;
1273 UINT64* size;
1274 ULONG pathlen, sizelen;
1275 std::wstring pathu;
1276 HANDLE h;
1277 LARGE_INTEGER sizeli;
1278 DWORD att;
1279
1280 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) {
1281 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
1282 return FALSE;
1283 }
1284
1285 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_SIZE, (void**)&size, &sizelen)) {
1286 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"size");
1287 return FALSE;
1288 }
1289
1290 if (sizelen < sizeof(UINT64)) {
1291 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"size", sizelen, sizeof(UINT64));
1292 return FALSE;
1293 }
1294
1295 if (!utf8_to_utf16(hwnd, path, pathlen, &pathu))
1296 return FALSE;
1297
1298 att = GetFileAttributesW((subvolpath + pathu).c_str());
1299 if (att == INVALID_FILE_ATTRIBUTES) {
1300 ShowRecvError(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1301 return FALSE;
1302 }
1303
1304 if (att & FILE_ATTRIBUTE_READONLY) {
1305 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att & ~FILE_ATTRIBUTE_READONLY)) {
1306 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1307 return FALSE;
1308 }
1309 }
1310
1311 h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_DATA, 0, NULL, OPEN_EXISTING,
1312 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL);
1313 if (h == INVALID_HANDLE_VALUE) {
1314 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
1315 return FALSE;
1316 }
1317
1318 sizeli.QuadPart = *size;
1319
1320 if (SetFilePointer(h, sizeli.LowPart, &sizeli.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
1321 ShowRecvError(IDS_RECV_SETFILEPOINTER_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1322 CloseHandle(h);
1323 return FALSE;
1324 }
1325
1326 if (!SetEndOfFile(h)) {
1327 ShowRecvError(IDS_RECV_SETENDOFFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1328 CloseHandle(h);
1329 return FALSE;
1330 }
1331
1332 CloseHandle(h);
1333
1334 if (att & FILE_ATTRIBUTE_READONLY) {
1335 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att)) {
1336 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1337 return FALSE;
1338 }
1339 }
1340
1341 return TRUE;
1342 }
1343
1344 BOOL BtrfsRecv::cmd_chmod(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
1345 HANDLE h;
1346 char* path;
1347 UINT32* mode;
1348 ULONG pathlen, modelen;
1349 std::wstring pathu;
1350 btrfs_set_inode_info bsii;
1351 NTSTATUS Status;
1352 IO_STATUS_BLOCK iosb;
1353
1354 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) {
1355 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
1356 return FALSE;
1357 }
1358
1359 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_MODE, (void**)&mode, &modelen)) {
1360 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"mode");
1361 return FALSE;
1362 }
1363
1364 if (modelen < sizeof(UINT32)) {
1365 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"mode", modelen, sizeof(UINT32));
1366 return FALSE;
1367 }
1368
1369 if (!utf8_to_utf16(hwnd, path, pathlen, &pathu))
1370 return FALSE;
1371
1372 h = CreateFileW((subvolpath + pathu).c_str(), WRITE_DAC, 0, NULL, OPEN_EXISTING,
1373 FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT | FILE_FLAG_POSIX_SEMANTICS, NULL);
1374 if (h == INVALID_HANDLE_VALUE) {
1375 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
1376 return FALSE;
1377 }
1378
1379 memset(&bsii, 0, sizeof(btrfs_set_inode_info));
1380
1381 bsii.mode_changed = TRUE;
1382 bsii.st_mode = *mode;
1383
1384 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), NULL, 0);
1385 if (!NT_SUCCESS(Status)) {
1386 ShowRecvError(IDS_RECV_SETINODEINFO_FAILED, Status, format_ntstatus(Status).c_str());
1387 CloseHandle(h);
1388 return FALSE;
1389 }
1390
1391 CloseHandle(h);
1392
1393 return TRUE;
1394 }
1395
1396 BOOL BtrfsRecv::cmd_chown(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
1397 HANDLE h;
1398 char* path;
1399 UINT32 *uid, *gid;
1400 ULONG pathlen, uidlen, gidlen;
1401 std::wstring pathu;
1402 btrfs_set_inode_info bsii;
1403
1404 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) {
1405 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
1406 return FALSE;
1407 }
1408
1409 if (!utf8_to_utf16(hwnd, path, pathlen, &pathu))
1410 return FALSE;
1411
1412 h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_ATTRIBUTES | WRITE_OWNER | WRITE_DAC, 0, NULL, OPEN_EXISTING,
1413 FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT | FILE_FLAG_POSIX_SEMANTICS, NULL);
1414 if (h == INVALID_HANDLE_VALUE) {
1415 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
1416 return FALSE;
1417 }
1418
1419 memset(&bsii, 0, sizeof(btrfs_set_inode_info));
1420
1421 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_UID, (void**)&uid, &uidlen)) {
1422 if (uidlen < sizeof(UINT32)) {
1423 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"uid", uidlen, sizeof(UINT32));
1424 CloseHandle(h);
1425 return FALSE;
1426 }
1427
1428 bsii.uid_changed = TRUE;
1429 bsii.st_uid = *uid;
1430 }
1431
1432 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_GID, (void**)&gid, &gidlen)) {
1433 if (gidlen < sizeof(UINT32)) {
1434 ShowRecvError(IDS_RECV_SHORT_PARAM, funcname, L"gid", gidlen, sizeof(UINT32));
1435 CloseHandle(h);
1436 return FALSE;
1437 }
1438
1439 bsii.gid_changed = TRUE;
1440 bsii.st_gid = *gid;
1441 }
1442
1443 if (bsii.uid_changed || bsii.gid_changed) {
1444 NTSTATUS Status;
1445 IO_STATUS_BLOCK iosb;
1446
1447 Status = NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), NULL, 0);
1448 if (!NT_SUCCESS(Status)) {
1449 ShowRecvError(IDS_RECV_SETINODEINFO_FAILED, Status, format_ntstatus(Status).c_str());
1450 CloseHandle(h);
1451 return FALSE;
1452 }
1453 }
1454
1455 CloseHandle(h);
1456
1457 return TRUE;
1458 }
1459
1460 static __inline UINT64 unix_time_to_win(BTRFS_TIME* t) {
1461 return (t->seconds * 10000000) + (t->nanoseconds / 100) + 116444736000000000;
1462 }
1463
1464 BOOL BtrfsRecv::cmd_utimes(HWND hwnd, btrfs_send_command* cmd, UINT8* data) {
1465 char* path;
1466 ULONG pathlen;
1467 std::wstring pathu;
1468 HANDLE h;
1469 FILE_BASIC_INFO fbi;
1470 BTRFS_TIME* time;
1471 ULONG timelen;
1472
1473 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) {
1474 ShowRecvError(IDS_RECV_MISSING_PARAM, funcname, L"path");
1475 return FALSE;
1476 }
1477
1478 if (!utf8_to_utf16(hwnd, path, pathlen, &pathu))
1479 return FALSE;
1480
1481 h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
1482 FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT | FILE_FLAG_POSIX_SEMANTICS, NULL);
1483 if (h == INVALID_HANDLE_VALUE) {
1484 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str());
1485 return FALSE;
1486 }
1487
1488 memset(&fbi, 0, sizeof(FILE_BASIC_INFO));
1489
1490 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_OTIME, (void**)&time, &timelen) && timelen >= sizeof(BTRFS_TIME))
1491 fbi.CreationTime.QuadPart = unix_time_to_win(time);
1492
1493 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_ATIME, (void**)&time, &timelen) && timelen >= sizeof(BTRFS_TIME))
1494 fbi.LastAccessTime.QuadPart = unix_time_to_win(time);
1495
1496 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_MTIME, (void**)&time, &timelen) && timelen >= sizeof(BTRFS_TIME))
1497 fbi.LastWriteTime.QuadPart = unix_time_to_win(time);
1498
1499 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_CTIME, (void**)&time, &timelen) && timelen >= sizeof(BTRFS_TIME))
1500 fbi.ChangeTime.QuadPart = unix_time_to_win(time);
1501
1502 if (!SetFileInformationByHandle(h, FileBasicInfo, &fbi, sizeof(FILE_BASIC_INFO))) {
1503 ShowRecvError(IDS_RECV_SETFILEINFO_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1504 CloseHandle(h);
1505 return FALSE;
1506 }
1507
1508 CloseHandle(h);
1509
1510 return TRUE;
1511 }
1512
1513 void BtrfsRecv::ShowRecvError(int resid, ...) {
1514 WCHAR s[1024], t[1024];
1515 va_list ap;
1516
1517 if (!hwnd)
1518 return;
1519
1520 if (!LoadStringW(module, resid, s, sizeof(s) / sizeof(WCHAR))) {
1521 ShowError(hwnd, GetLastError());
1522 return;
1523 }
1524
1525 va_start(ap, resid);
1526 #ifndef __REACTOS__
1527 vswprintf(t, sizeof(t) / sizeof(WCHAR), s, ap);
1528 #else
1529 vsnwprintf(t, sizeof(t) / sizeof(WCHAR), s, ap);
1530 #endif
1531
1532 SetDlgItemTextW(hwnd, IDC_RECV_MSG, t);
1533
1534 va_end(ap);
1535
1536 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETSTATE, PBST_ERROR, 0);
1537 }
1538
1539 static void delete_directory(std::wstring dir) {
1540 HANDLE h;
1541 WIN32_FIND_DATAW fff;
1542
1543 h = FindFirstFileW((dir + L"*").c_str(), &fff);
1544
1545 if (h == INVALID_HANDLE_VALUE)
1546 return;
1547
1548 do {
1549 std::wstring file;
1550
1551 file = fff.cFileName;
1552
1553 if (file != L"." && file != L"..") {
1554 if (fff.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
1555 SetFileAttributesW((dir + file).c_str(), fff.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
1556
1557 if (fff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1558 if (!(fff.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
1559 delete_directory(dir + file + L"\\");
1560 else
1561 RemoveDirectoryW((dir + file).c_str());
1562 } else
1563 DeleteFileW((dir + file).c_str());
1564 }
1565 } while (FindNextFileW(h, &fff));
1566
1567 FindClose(h);
1568
1569 RemoveDirectoryW(dir.c_str());
1570 }
1571
1572 static BOOL check_csum(btrfs_send_command* cmd, UINT8* data) {
1573 UINT32 crc32 = cmd->csum, calc;
1574
1575 cmd->csum = 0;
1576
1577 calc = calc_crc32c(0, (UINT8*)cmd, sizeof(btrfs_send_command));
1578
1579 if (cmd->length > 0)
1580 calc = calc_crc32c(calc, data, cmd->length);
1581
1582 return calc == crc32 ? TRUE : FALSE;
1583 }
1584
1585 BOOL BtrfsRecv::do_recv(HANDLE f, UINT64* pos, UINT64 size) {
1586 btrfs_send_header header;
1587 BOOL b = TRUE, ended = FALSE;
1588
1589 if (!ReadFile(f, &header, sizeof(btrfs_send_header), NULL, NULL)) {
1590 ShowRecvError(IDS_RECV_READFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1591 return FALSE;
1592 }
1593
1594 *pos += sizeof(btrfs_send_header);
1595
1596 if (memcmp(header.magic, BTRFS_SEND_MAGIC, sizeof(header.magic))) {
1597 ShowRecvError(IDS_RECV_NOT_A_SEND_STREAM);
1598 return FALSE;
1599 }
1600
1601 if (header.version > 1) {
1602 ShowRecvError(IDS_RECV_UNSUPPORTED_VERSION, header.version);
1603 return FALSE;
1604 }
1605
1606 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETRANGE32, 0, (LPARAM)65536);
1607
1608 lastwritefile = INVALID_HANDLE_VALUE;
1609 lastwritepath = L"";
1610 lastwriteatt = 0;
1611
1612 while (TRUE) {
1613 btrfs_send_command cmd;
1614 UINT8* data;
1615 ULONG progress;
1616
1617 if (cancelling) {
1618 b = FALSE;
1619 break;
1620 }
1621
1622 progress = (ULONG)((float)*pos * 65536.0f / (float)size);
1623 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETPOS, progress, 0);
1624
1625 if (!ReadFile(f, &cmd, sizeof(btrfs_send_command), NULL, NULL)) {
1626 if (GetLastError() != ERROR_HANDLE_EOF) {
1627 ShowRecvError(IDS_RECV_READFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1628 break;
1629 }
1630
1631 break;
1632 }
1633
1634 *pos += sizeof(btrfs_send_command);
1635
1636 if (cmd.length > 0) {
1637 if (*pos + cmd.length > size) {
1638 ShowRecvError(IDS_RECV_FILE_TRUNCATED);
1639 b = FALSE;
1640 break;
1641 }
1642
1643 data = (UINT8*)malloc(cmd.length);
1644 if (!data) {
1645 ShowRecvError(IDS_OUT_OF_MEMORY);
1646 b = FALSE;
1647 break;
1648 }
1649
1650 if (!ReadFile(f, data, cmd.length, NULL, NULL)) {
1651 ShowRecvError(IDS_RECV_READFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1652 b = FALSE;
1653 break;
1654 }
1655
1656 *pos += cmd.length;
1657 } else
1658 data = NULL;
1659
1660 if (!check_csum(&cmd, data)) {
1661 ShowRecvError(IDS_RECV_CSUM_ERROR);
1662 if (data) free(data);
1663 b = FALSE;
1664 break;
1665 }
1666
1667 if (cmd.cmd == BTRFS_SEND_CMD_END) {
1668 if (data) free(data);
1669 ended = TRUE;
1670 break;
1671 }
1672
1673 if (lastwritefile != INVALID_HANDLE_VALUE && cmd.cmd != BTRFS_SEND_CMD_WRITE) {
1674 if (lastwriteatt & FILE_ATTRIBUTE_READONLY) {
1675 if (!SetFileAttributesW((subvolpath + lastwritepath).c_str(), lastwriteatt)) {
1676 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1677 return FALSE;
1678 }
1679 }
1680
1681 CloseHandle(lastwritefile);
1682
1683 lastwritefile = INVALID_HANDLE_VALUE;
1684 lastwritepath = L"";
1685 lastwriteatt = 0;
1686 }
1687
1688 switch (cmd.cmd) {
1689 case BTRFS_SEND_CMD_SUBVOL:
1690 b = cmd_subvol(hwnd, &cmd, data);
1691 break;
1692
1693 case BTRFS_SEND_CMD_SNAPSHOT:
1694 b = cmd_snapshot(hwnd, &cmd, data);
1695 break;
1696
1697 case BTRFS_SEND_CMD_MKFILE:
1698 case BTRFS_SEND_CMD_MKDIR:
1699 case BTRFS_SEND_CMD_MKNOD:
1700 case BTRFS_SEND_CMD_MKFIFO:
1701 case BTRFS_SEND_CMD_MKSOCK:
1702 case BTRFS_SEND_CMD_SYMLINK:
1703 b = cmd_mkfile(hwnd, &cmd, data);
1704 break;
1705
1706 case BTRFS_SEND_CMD_RENAME:
1707 b = cmd_rename(hwnd, &cmd, data);
1708 break;
1709
1710 case BTRFS_SEND_CMD_LINK:
1711 b = cmd_link(hwnd, &cmd, data);
1712 break;
1713
1714 case BTRFS_SEND_CMD_UNLINK:
1715 b = cmd_unlink(hwnd, &cmd, data);
1716 break;
1717
1718 case BTRFS_SEND_CMD_RMDIR:
1719 b = cmd_rmdir(hwnd, &cmd, data);
1720 break;
1721
1722 case BTRFS_SEND_CMD_SET_XATTR:
1723 b = cmd_setxattr(hwnd, &cmd, data);
1724 break;
1725
1726 case BTRFS_SEND_CMD_REMOVE_XATTR:
1727 b = cmd_removexattr(hwnd, &cmd, data);
1728 break;
1729
1730 case BTRFS_SEND_CMD_WRITE:
1731 b = cmd_write(hwnd, &cmd, data);
1732 break;
1733
1734 case BTRFS_SEND_CMD_CLONE:
1735 b = cmd_clone(hwnd, &cmd, data);
1736 break;
1737
1738 case BTRFS_SEND_CMD_TRUNCATE:
1739 b = cmd_truncate(hwnd, &cmd, data);
1740 break;
1741
1742 case BTRFS_SEND_CMD_CHMOD:
1743 b = cmd_chmod(hwnd, &cmd, data);
1744 break;
1745
1746 case BTRFS_SEND_CMD_CHOWN:
1747 b = cmd_chown(hwnd, &cmd, data);
1748 break;
1749
1750 case BTRFS_SEND_CMD_UTIMES:
1751 b = cmd_utimes(hwnd, &cmd, data);
1752 break;
1753
1754 case BTRFS_SEND_CMD_UPDATE_EXTENT:
1755 // does nothing
1756 break;
1757
1758 default:
1759 ShowRecvError(IDS_RECV_UNKNOWN_COMMAND, cmd.cmd);
1760 b = FALSE;
1761 break;
1762 }
1763
1764 if (data) free(data);
1765
1766 if (!b)
1767 break;
1768 }
1769
1770 if (lastwritefile != INVALID_HANDLE_VALUE) {
1771 if (lastwriteatt & FILE_ATTRIBUTE_READONLY) {
1772 if (!SetFileAttributesW((subvolpath + lastwritepath).c_str(), lastwriteatt)) {
1773 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1774 return FALSE;
1775 }
1776 }
1777
1778 CloseHandle(lastwritefile);
1779 }
1780
1781 if (b && !ended) {
1782 ShowRecvError(IDS_RECV_FILE_TRUNCATED);
1783 b = FALSE;
1784 }
1785
1786 if (b) {
1787 NTSTATUS Status;
1788 IO_STATUS_BLOCK iosb;
1789 btrfs_received_subvol brs;
1790
1791 brs.generation = stransid;
1792 brs.uuid = subvol_uuid;
1793
1794 Status = NtFsControlFile(dir, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_RECEIVED_SUBVOL, &brs, sizeof(btrfs_received_subvol),
1795 NULL, 0);
1796 if (!NT_SUCCESS(Status)) {
1797 ShowRecvError(IDS_RECV_RECEIVED_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str());
1798 b = FALSE;
1799 }
1800 }
1801
1802 CloseHandle(dir);
1803
1804 if (master != INVALID_HANDLE_VALUE)
1805 CloseHandle(master);
1806
1807 if (!b && subvolpath != L"") {
1808 ULONG attrib;
1809
1810 attrib = GetFileAttributesW(subvolpath.c_str());
1811 attrib &= ~FILE_ATTRIBUTE_READONLY;
1812
1813 if (!SetFileAttributesW(subvolpath.c_str(), attrib))
1814 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1815 else
1816 delete_directory(subvolpath);
1817 }
1818
1819 return b;
1820 }
1821
1822 DWORD BtrfsRecv::recv_thread() {
1823 HANDLE f;
1824 LARGE_INTEGER size;
1825 UINT64 pos = 0;
1826 BOOL b;
1827
1828 running = TRUE;
1829
1830 f = CreateFileW(streamfile.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
1831 if (f == INVALID_HANDLE_VALUE) {
1832 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, streamfile.c_str(), GetLastError(), format_message(GetLastError()).c_str());
1833 goto end;
1834 }
1835
1836 if (!GetFileSizeEx(f, &size)) {
1837 ShowRecvError(IDS_RECV_GETFILESIZEEX_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1838 goto end;
1839 }
1840
1841 parent = CreateFileW(dirpath.c_str(), FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1842 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL);
1843 if (parent == INVALID_HANDLE_VALUE) {
1844 ShowRecvError(IDS_RECV_CANT_OPEN_PATH, dirpath.c_str(), GetLastError(), format_message(GetLastError()).c_str());
1845 CloseHandle(f);
1846 goto end;
1847 }
1848
1849 do {
1850 b = do_recv(f, &pos, size.QuadPart);
1851 } while (b && pos < (UINT64)size.QuadPart);
1852
1853 CloseHandle(parent);
1854 CloseHandle(f);
1855
1856 if (b && hwnd) {
1857 WCHAR s[255];
1858
1859 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETPOS, 65536, 0);
1860
1861 if (num_received == 1) {
1862 if (!LoadStringW(module, IDS_RECV_SUCCESS, s, sizeof(s) / sizeof(WCHAR)))
1863 ShowError(hwnd, GetLastError());
1864 else
1865 SetDlgItemTextW(hwnd, IDC_RECV_MSG, s);
1866 } else {
1867 if (!LoadStringW(module, IDS_RECV_SUCCESS_PLURAL, s, sizeof(s) / sizeof(WCHAR)))
1868 ShowError(hwnd, GetLastError());
1869 else {
1870 WCHAR t[255];
1871
1872 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), s, num_received) == STRSAFE_E_INSUFFICIENT_BUFFER)
1873 ShowError(hwnd, ERROR_INSUFFICIENT_BUFFER);
1874 else
1875 SetDlgItemTextW(hwnd, IDC_RECV_MSG, t);
1876 }
1877 }
1878
1879 if (!LoadStringW(module, IDS_RECV_BUTTON_OK, s, sizeof(s) / sizeof(WCHAR)))
1880 ShowError(hwnd, GetLastError());
1881 else
1882 SetDlgItemTextW(hwnd, IDCANCEL, s);
1883 }
1884
1885 end:
1886 thread = NULL;
1887 running = FALSE;
1888
1889 return 0;
1890 }
1891
1892 static DWORD WINAPI global_recv_thread(LPVOID lpParameter) {
1893 BtrfsRecv* br = (BtrfsRecv*)lpParameter;
1894
1895 return br->recv_thread();
1896 }
1897
1898 INT_PTR CALLBACK BtrfsRecv::RecvProgressDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
1899 switch (uMsg) {
1900 case WM_INITDIALOG:
1901 this->hwnd = hwndDlg;
1902 thread = CreateThread(NULL, 0, global_recv_thread, this, 0, NULL);
1903
1904 if (!thread)
1905 ShowRecvError(IDS_RECV_CREATETHREAD_FAILED, GetLastError(), format_message(GetLastError()).c_str());
1906 break;
1907
1908 case WM_COMMAND:
1909 switch (HIWORD(wParam)) {
1910 case BN_CLICKED:
1911 switch (LOWORD(wParam)) {
1912 case IDOK:
1913 case IDCANCEL:
1914 if (running) {
1915 WCHAR s[255];
1916
1917 cancelling = TRUE;
1918
1919 if (!LoadStringW(module, IDS_RECV_CANCELLED, s, sizeof(s) / sizeof(WCHAR))) {
1920 ShowError(hwndDlg, GetLastError());
1921 return FALSE;
1922 }
1923
1924 SetDlgItemTextW(hwnd, IDC_RECV_MSG, s);
1925 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETPOS, 0, 0);
1926
1927 if (!LoadStringW(module, IDS_RECV_BUTTON_OK, s, sizeof(s) / sizeof(WCHAR))) {
1928 ShowError(hwndDlg, GetLastError());
1929 return FALSE;
1930 }
1931
1932 SetDlgItemTextW(hwnd, IDCANCEL, s);
1933 } else
1934 EndDialog(hwndDlg, 1);
1935
1936 return TRUE;
1937 }
1938 break;
1939 }
1940 break;
1941 }
1942
1943 return FALSE;
1944 }
1945
1946 static INT_PTR CALLBACK stub_RecvProgressDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
1947 BtrfsRecv* br;
1948
1949 if (uMsg == WM_INITDIALOG) {
1950 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
1951 br = (BtrfsRecv*)lParam;
1952 } else {
1953 br = (BtrfsRecv*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
1954 }
1955
1956 if (br)
1957 return br->RecvProgressDlgProc(hwndDlg, uMsg, wParam, lParam);
1958 else
1959 return FALSE;
1960 }
1961
1962 void BtrfsRecv::Open(HWND hwnd, WCHAR* file, WCHAR* path, BOOL quiet) {
1963 #ifndef __REACTOS__
1964 UINT32 cpuInfo[4];
1965 #endif
1966
1967 streamfile = file;
1968 dirpath = path;
1969 subvolpath = L"";
1970
1971 #ifndef __REACTOS__
1972 #ifndef _MSC_VER
1973 __get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3]);
1974 have_sse42 = cpuInfo[2] & bit_SSE4_2;
1975 #else
1976 __cpuid((int*)cpuInfo, 1);
1977 have_sse42 = cpuInfo[2] & (1 << 20);
1978 #endif
1979 #endif
1980
1981 if (quiet)
1982 recv_thread();
1983 else {
1984 if (DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_RECV_PROGRESS), hwnd, stub_RecvProgressDlgProc, (LPARAM)this) <= 0)
1985 ShowError(hwnd, GetLastError());
1986 }
1987 }
1988
1989 void CALLBACK RecvSubvolGUIW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
1990 OPENFILENAMEW ofn;
1991 WCHAR file[MAX_PATH];
1992 BtrfsRecv* recv;
1993 HANDLE token;
1994 TOKEN_PRIVILEGES* tp;
1995 LUID luid;
1996 ULONG tplen;
1997
1998 set_dpi_aware();
1999
2000 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
2001 ShowError(hwnd, GetLastError());
2002 return;
2003 }
2004
2005 tplen = offsetof(TOKEN_PRIVILEGES, Privileges[0]) + (3 * sizeof(LUID_AND_ATTRIBUTES));
2006 tp = (TOKEN_PRIVILEGES*)malloc(tplen);
2007 if (!tp) {
2008 ShowStringError(hwnd, IDS_OUT_OF_MEMORY);
2009 CloseHandle(token);
2010 return;
2011 }
2012
2013 tp->PrivilegeCount = 3;
2014
2015 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) {
2016 ShowError(hwnd, GetLastError());
2017 free(tp);
2018 CloseHandle(token);
2019 return;
2020 }
2021
2022 tp->Privileges[0].Luid = luid;
2023 tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
2024
2025 if (!LookupPrivilegeValueW(NULL, L"SeSecurityPrivilege", &luid)) {
2026 ShowError(hwnd, GetLastError());
2027 free(tp);
2028 CloseHandle(token);
2029 return;
2030 }
2031
2032 tp->Privileges[1].Luid = luid;
2033 tp->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
2034
2035 if (!LookupPrivilegeValueW(NULL, L"SeRestorePrivilege", &luid)) {
2036 ShowError(hwnd, GetLastError());
2037 free(tp);
2038 CloseHandle(token);
2039 return;
2040 }
2041
2042 tp->Privileges[2].Luid = luid;
2043 tp->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED;
2044
2045 if (!AdjustTokenPrivileges(token, FALSE, tp, tplen, NULL, NULL)) {
2046 ShowError(hwnd, GetLastError());
2047 free(tp);
2048 CloseHandle(token);
2049 return;
2050 }
2051
2052 file[0] = 0;
2053
2054 memset(&ofn, 0, sizeof(OPENFILENAMEW));
2055 ofn.lStructSize = sizeof(OPENFILENAMEW);
2056 ofn.hwndOwner = hwnd;
2057 ofn.hInstance = module;
2058 ofn.lpstrFile = file;
2059 ofn.nMaxFile = sizeof(file) / sizeof(WCHAR);
2060 ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
2061
2062 if (GetOpenFileNameW(&ofn)) {
2063 recv = new BtrfsRecv;
2064
2065 recv->Open(hwnd, file, lpszCmdLine, FALSE);
2066
2067 delete recv;
2068 }
2069
2070 free(tp);
2071 CloseHandle(token);
2072 }
2073
2074 void CALLBACK RecvSubvolW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) {
2075 LPWSTR* args;
2076 int num_args;
2077
2078 args = CommandLineToArgvW(lpszCmdLine, &num_args);
2079
2080 if (!args)
2081 return;
2082
2083 if (num_args >= 2) {
2084 BtrfsRecv* br;
2085 HANDLE token;
2086 TOKEN_PRIVILEGES* tp;
2087 ULONG tplen;
2088 LUID luid;
2089
2090 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
2091 goto end;
2092
2093 tplen = offsetof(TOKEN_PRIVILEGES, Privileges[0]) + (3 * sizeof(LUID_AND_ATTRIBUTES));
2094 tp = (TOKEN_PRIVILEGES*)malloc(tplen);
2095 if (!tp) {
2096 CloseHandle(token);
2097 goto end;
2098 }
2099
2100 tp->PrivilegeCount = 3;
2101
2102 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) {
2103 free(tp);
2104 CloseHandle(token);
2105 goto end;
2106 }
2107
2108 tp->Privileges[0].Luid = luid;
2109 tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
2110
2111 if (!LookupPrivilegeValueW(NULL, L"SeSecurityPrivilege", &luid)) {
2112 free(tp);
2113 CloseHandle(token);
2114 goto end;
2115 }
2116
2117 tp->Privileges[1].Luid = luid;
2118 tp->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
2119
2120 if (!LookupPrivilegeValueW(NULL, L"SeRestorePrivilege", &luid)) {
2121 free(tp);
2122 CloseHandle(token);
2123 goto end;
2124 }
2125
2126 tp->Privileges[2].Luid = luid;
2127 tp->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED;
2128
2129 if (!AdjustTokenPrivileges(token, FALSE, tp, tplen, NULL, NULL)) {
2130 free(tp);
2131 CloseHandle(token);
2132 goto end;
2133 }
2134
2135 free(tp);
2136 CloseHandle(token);
2137
2138 br = new BtrfsRecv;
2139 br->Open(NULL, args[0], args[1], TRUE);
2140
2141 delete br;
2142 }
2143
2144 end:
2145 LocalFree(args);
2146 }