1 /* Copyright (c) Mark Harmstone 2017
3 * This file is part of WinBtrfs.
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.
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.
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/>. */
34 #include <smmintrin.h>
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."
44 BOOL have_sse42
= FALSE
;
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,
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) \
87 for (; (len) >= sizeof (type); (len) -= sizeof(type), buf += sizeof (type)) { \
88 (crc) = op((crc), *(type *) (buf)); \
93 static UINT32
crc32c_hw(const void *input
, ULONG len
, UINT32 crc
) {
94 const char* buf
= (const char*)input
;
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!
100 for (; (len
> 0) && ((size_t)buf
& ALIGN_MASK
); len
--, buf
++) {
102 crc
= crctable
[(crc
^ *buf
) & 0xff] ^ (crc
>> 8);
104 crc
= _mm_crc32_u8(crc
, *buf
);
110 #pragma warning(push)
111 #pragma warning(disable:4244) // _mm_crc32_u64 wants to return UINT64(!)
112 #pragma warning(disable:4242)
114 CALC_CRC(_mm_crc32_u64
, crc
, UINT64
, buf
, len
);
119 CALC_CRC(_mm_crc32_u32
, crc
, UINT32
, buf
, len
);
122 for (; len
> 0; len
--, buf
++) {
123 crc
= crctable
[(crc
^ *buf
) & 0xff] ^ (crc
>> 8);
126 CALC_CRC(_mm_crc32_u16
, crc
, UINT16
, buf
, len
);
127 CALC_CRC(_mm_crc32_u8
, crc
, UINT8
, buf
, len
);
134 static UINT32
calc_crc32c(UINT32 seed
, UINT8
* msg
, ULONG msglen
) {
137 return crc32c_hw(msg
, msglen
, seed
);
145 for (i
= 0; i
< msglen
; i
++) {
146 rem
= crctable
[(rem
^ msg
[i
]) & 0xff] ^ (rem
>> 8);
155 BOOL
BtrfsRecv::find_tlv(UINT8
* data
, ULONG datalen
, UINT16 type
, void** value
, ULONG
* len
) {
158 while (off
< datalen
) {
159 btrfs_send_tlv
* tlv
= (btrfs_send_tlv
*)(data
+ off
);
160 UINT8
* payload
= data
+ off
+ sizeof(btrfs_send_tlv
);
162 if (off
+ sizeof(btrfs_send_tlv
) + tlv
->length
> datalen
) // file is truncated
165 if (tlv
->type
== type
) {
171 off
+= sizeof(btrfs_send_tlv
) + tlv
->length
;
177 BOOL
BtrfsRecv::utf8_to_utf16(HWND hwnd
, char* utf8
, ULONG utf8len
, std::wstring
* utf16
) {
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());
188 buf
= (WCHAR
*)malloc(utf16len
+ sizeof(WCHAR
));
191 ShowRecvError(IDS_OUT_OF_MEMORY
);
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());
202 buf
[utf16len
/ sizeof(WCHAR
)] = 0;
211 BOOL
BtrfsRecv::cmd_subvol(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
215 ULONG namelen
, uuidlen
, genlen
, bcslen
;
216 btrfs_create_subvol
* bcs
;
218 IO_STATUS_BLOCK iosb
;
221 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&name
, &namelen
)) {
222 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
226 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_UUID
, (void**)&uuid
, &uuidlen
)) {
227 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"uuid");
231 if (uuidlen
< sizeof(BTRFS_UUID
)) {
232 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"uuid", uuidlen
, sizeof(BTRFS_UUID
));
236 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_TRANSID
, (void**)&gen
, &genlen
)) {
237 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"transid");
241 if (genlen
< sizeof(UINT64
)) {
242 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"transid", genlen
, sizeof(UINT64
));
246 this->subvol_uuid
= *uuid
;
247 this->stransid
= *gen
;
249 if (!utf8_to_utf16(hwnd
, name
, namelen
, &nameu
))
252 bcslen
= offsetof(btrfs_create_subvol
, name
[0]) + (nameu
.length() * sizeof(WCHAR
));
253 bcs
= (btrfs_create_subvol
*)malloc(bcslen
);
255 bcs
->readonly
= TRUE
;
257 bcs
->namelen
= nameu
.length() * sizeof(WCHAR
);
258 memcpy(bcs
->name
, nameu
.c_str(), bcs
->namelen
);
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());
266 subvolpath
= dirpath
;
270 if (dir
!= INVALID_HANDLE_VALUE
)
273 if (master
!= INVALID_HANDLE_VALUE
)
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());
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());
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());
299 add_cache_entry(&this->subvol_uuid
, this->stransid
, subvolpath
);
306 void BtrfsRecv::add_cache_entry(BTRFS_UUID
* uuid
, UINT64 transid
, std::wstring path
) {
310 sc
.transid
= transid
;
316 BOOL
BtrfsRecv::cmd_snapshot(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
318 BTRFS_UUID
*uuid
, *parent_uuid
;
319 UINT64
*gen
, *parent_transid
;
320 ULONG namelen
, uuidlen
, genlen
, paruuidlen
, partransidlen
, bcslen
;
321 btrfs_create_snapshot
* bcs
;
323 IO_STATUS_BLOCK iosb
;
324 std::wstring nameu
, parpath
;
325 btrfs_find_subvol bfs
;
326 WCHAR parpathw
[MAX_PATH
], volpathw
[MAX_PATH
];
329 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&name
, &namelen
)) {
330 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
334 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_UUID
, (void**)&uuid
, &uuidlen
)) {
335 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"uuid");
339 if (uuidlen
< sizeof(BTRFS_UUID
)) {
340 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"uuid", uuidlen
, sizeof(BTRFS_UUID
));
344 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_TRANSID
, (void**)&gen
, &genlen
)) {
345 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"transid");
349 if (genlen
< sizeof(UINT64
)) {
350 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"transid", genlen
, sizeof(UINT64
));
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");
359 if (paruuidlen
< sizeof(BTRFS_UUID
)) {
360 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"clone_uuid", paruuidlen
, sizeof(BTRFS_UUID
));
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");
369 if (partransidlen
< sizeof(UINT64
)) {
370 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"clone_ctransid", partransidlen
, sizeof(UINT64
));
374 this->subvol_uuid
= *uuid
;
375 this->stransid
= *gen
;
377 if (!utf8_to_utf16(hwnd
, name
, namelen
, &nameu
))
380 bfs
.uuid
= *parent_uuid
;
381 bfs
.ctransid
= *parent_transid
;
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
);
388 } else if (!NT_SUCCESS(Status
)) {
389 ShowRecvError(IDS_RECV_FIND_SUBVOL_FAILED
, Status
, format_ntstatus(Status
).c_str());
393 if (!GetVolumePathNameW(dirpath
.c_str(), volpathw
, (sizeof(volpathw
) / sizeof(WCHAR
)) - 1)) {
394 ShowRecvError(IDS_RECV_GETVOLUMEPATHNAME_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
399 if (parpath
.substr(parpath
.length() - 1) == L
"\\")
400 parpath
= parpath
.substr(0, parpath
.length() - 1);
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());
411 bcslen
= offsetof(btrfs_create_snapshot
, name
[0]) + (nameu
.length() * sizeof(WCHAR
));
412 bcs
= (btrfs_create_snapshot
*)malloc(bcslen
);
414 bcs
->readonly
= TRUE
;
416 bcs
->subvol
= subvol
;
417 bcs
->namelen
= nameu
.length() * sizeof(WCHAR
);
418 memcpy(bcs
->name
, nameu
.c_str(), bcs
->namelen
);
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());
426 subvolpath
= dirpath
;
430 if (dir
!= INVALID_HANDLE_VALUE
)
433 if (master
!= INVALID_HANDLE_VALUE
)
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());
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());
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());
459 add_cache_entry(&this->subvol_uuid
, this->stransid
, subvolpath
);
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
;
471 IO_STATUS_BLOCK iosb
;
473 std::wstring nameu
, pathlinku
;
475 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&name
, &namelen
)) {
476 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
480 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_INODE
, (void**)&inode
, &inodelen
)) {
481 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"inode");
485 if (inodelen
< sizeof(UINT64
)) {
486 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"inode", inodelen
, sizeof(UINT64
));
490 if (cmd
->cmd
== BTRFS_SEND_CMD_MKNOD
|| cmd
->cmd
== BTRFS_SEND_CMD_MKFIFO
|| cmd
->cmd
== BTRFS_SEND_CMD_MKSOCK
) {
491 ULONG rdevlen
, modelen
;
493 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_RDEV
, (void**)&rdev
, &rdevlen
)) {
494 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"rdev");
498 if (rdevlen
< sizeof(UINT64
)) {
499 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"rdev", rdev
, sizeof(UINT64
));
503 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_MODE
, (void**)&mode
, &modelen
)) {
504 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"mode");
508 if (modelen
< sizeof(UINT64
)) {
509 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"mode", modelen
, sizeof(UINT64
));
512 } else if (cmd
->cmd
== BTRFS_SEND_CMD_SYMLINK
) {
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");
520 if (!utf8_to_utf16(hwnd
, pathlink
, pathlinklen
, &pathlinku
))
524 if (!utf8_to_utf16(hwnd
, name
, namelen
, &nameu
))
527 bmnsize
= sizeof(btrfs_mknod
) - sizeof(WCHAR
) + (nameu
.length() * sizeof(WCHAR
));
528 bmn
= (btrfs_mknod
*)malloc(bmnsize
);
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
;
541 bmn
->type
= BTRFS_TYPE_FILE
;
543 bmn
->st_rdev
= rdev
? *rdev
: 0;
544 bmn
->namelen
= nameu
.length() * sizeof(WCHAR
);
545 memcpy(bmn
->name
, nameu
.c_str(), bmn
->namelen
);
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());
556 if (cmd
->cmd
== BTRFS_SEND_CMD_SYMLINK
) {
558 REPARSE_DATA_BUFFER
* rdb
;
560 btrfs_set_inode_info bsii
;
562 rdblen
= offsetof(REPARSE_DATA_BUFFER
, SymbolicLinkReparseBuffer
.PathBuffer
[0]) + (2 * pathlinku
.length() * sizeof(WCHAR
));
564 rdb
= (REPARSE_DATA_BUFFER
*)malloc(rdblen
);
566 rdb
->ReparseTag
= IO_REPARSE_TAG_SYMLINK
;
567 rdb
->ReparseDataLength
= rdblen
- offsetof(REPARSE_DATA_BUFFER
, SymbolicLinkReparseBuffer
);
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
;
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
);
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());
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());
597 memset(&bsii
, 0, sizeof(btrfs_set_inode_info
));
599 bsii
.mode_changed
= TRUE
;
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());
610 } else if (cmd
->cmd
== BTRFS_SEND_CMD_MKNOD
|| cmd
->cmd
== BTRFS_SEND_CMD_MKFIFO
|| cmd
->cmd
== BTRFS_SEND_CMD_MKSOCK
) {
614 if (find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_MODE
, (void**)&mode
, &modelen
)) {
616 btrfs_set_inode_info bsii
;
618 if (modelen
< sizeof(UINT64
)) {
619 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"mode", modelen
, sizeof(UINT64
));
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());
630 memset(&bsii
, 0, sizeof(btrfs_set_inode_info
));
632 bsii
.mode_changed
= TRUE
;
633 bsii
.st_mode
= *mode
;
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());
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
;
654 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &path_len
)) {
655 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
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");
664 if (!utf8_to_utf16(hwnd
, path
, path_len
, &pathu
))
667 if (!utf8_to_utf16(hwnd
, path_to
, path_to_len
, &path_tou
))
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());
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
;
683 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &path_len
)) {
684 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
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");
693 if (!utf8_to_utf16(hwnd
, path
, path_len
, &pathu
))
696 if (!utf8_to_utf16(hwnd
, path_link
, path_link_len
, &path_linku
))
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());
707 BOOL
BtrfsRecv::cmd_unlink(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
713 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &pathlen
)) {
714 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
718 if (!utf8_to_utf16(hwnd
, path
, pathlen
, &pathu
))
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());
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());
734 if (!DeleteFileW((subvolpath
+ pathu
).c_str())) {
735 ShowRecvError(IDS_RECV_DELETEFILE_FAILED
, pathu
.c_str(), GetLastError(), format_message(GetLastError()).c_str());
742 BOOL
BtrfsRecv::cmd_rmdir(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
748 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &pathlen
)) {
749 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
753 if (!utf8_to_utf16(hwnd
, path
, pathlen
, &pathu
))
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());
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());
769 if (!RemoveDirectoryW((subvolpath
+ pathu
).c_str())) {
770 ShowRecvError(IDS_RECV_REMOVEDIRECTORY_FAILED
, pathu
.c_str(), GetLastError(), format_message(GetLastError()).c_str());
777 BOOL
BtrfsRecv::cmd_setxattr(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
778 char *path
, *xattrname
;
780 ULONG pathlen
, xattrnamelen
, xattrdatalen
;
783 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &pathlen
)) {
784 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
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");
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");
798 if (!utf8_to_utf16(hwnd
, path
, pathlen
, &pathu
))
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
))) {
806 std::wstring streamname
;
809 if (!utf8_to_utf16(hwnd
, xattrname
, xattrnamelen
, &streamname
))
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());
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());
825 streamname
= streamname
.substr(strlen(XATTR_USER
));
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());
834 if (xattrdatalen
> 0) {
835 if (!WriteFile(h
, xattrdata
, xattrdatalen
, NULL
, NULL
)) {
836 ShowRecvError(IDS_RECV_WRITEFILE_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
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());
852 IO_STATUS_BLOCK iosb
;
854 ULONG bsxalen
, perms
= FILE_WRITE_ATTRIBUTES
;
855 btrfs_set_xattr
* bsxa
;
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
;
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());
869 bsxalen
= offsetof(btrfs_set_xattr
, data
[0]) + xattrnamelen
+ xattrdatalen
;
870 bsxa
= (btrfs_set_xattr
*)malloc(bsxalen
);
872 ShowRecvError(IDS_OUT_OF_MEMORY
);
877 bsxa
->namelen
= xattrnamelen
;
878 bsxa
->valuelen
= xattrdatalen
;
879 memcpy(bsxa
->data
, xattrname
, xattrnamelen
);
880 memcpy(&bsxa
->data
[xattrnamelen
], xattrdata
, xattrdatalen
);
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());
897 BOOL
BtrfsRecv::cmd_removexattr(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
898 char *path
, *xattrname
;
899 ULONG pathlen
, xattrnamelen
;
902 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &pathlen
)) {
903 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
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");
912 if (!utf8_to_utf16(hwnd
, path
, pathlen
, &pathu
))
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
919 std::wstring streamname
;
921 if (!utf8_to_utf16(hwnd
, xattrname
, xattrnamelen
, &streamname
))
924 streamname
= streamname
.substr(strlen(XATTR_USER
));
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());
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());
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());
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());
952 IO_STATUS_BLOCK iosb
;
954 ULONG bsxalen
, perms
= FILE_WRITE_ATTRIBUTES
;
955 btrfs_set_xattr
* bsxa
;
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
;
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());
969 bsxalen
= offsetof(btrfs_set_xattr
, data
[0]) + xattrnamelen
;
970 bsxa
= (btrfs_set_xattr
*)malloc(bsxalen
);
972 ShowRecvError(IDS_OUT_OF_MEMORY
);
977 bsxa
->namelen
= xattrnamelen
;
979 memcpy(bsxa
->data
, xattrname
, xattrnamelen
);
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());
996 BOOL
BtrfsRecv::cmd_write(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
1000 ULONG pathlen
, offsetlen
, datalen
;
1003 LARGE_INTEGER offli
;
1005 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &pathlen
)) {
1006 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
1010 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_OFFSET
, (void**)&offset
, &offsetlen
)) {
1011 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"offset");
1015 if (offsetlen
< sizeof(UINT64
)) {
1016 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"offset", offsetlen
, sizeof(UINT64
));
1020 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_DATA
, (void**)&writedata
, &datalen
)) {
1021 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"data");
1025 if (!utf8_to_utf16(hwnd
, path
, pathlen
, &pathu
))
1028 if (lastwritepath
!= pathu
) {
1029 FILE_BASIC_INFO fbi
;
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());
1038 CloseHandle(lastwritefile
);
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());
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());
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());
1060 lastwritepath
= pathu
;
1063 memset(&fbi
, 0, sizeof(FILE_BASIC_INFO
));
1065 fbi
.LastWriteTime
.QuadPart
= -1;
1067 if (!SetFileInformationByHandle(h
, FileBasicInfo
, &fbi
, sizeof(FILE_BASIC_INFO
))) {
1068 ShowRecvError(IDS_RECV_SETFILEINFO_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
1074 offli
.QuadPart
= *offset
;
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());
1081 if (!WriteFile(h
, writedata
, datalen
, NULL
, NULL
)) {
1082 ShowRecvError(IDS_RECV_WRITEFILE_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
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
;
1097 IO_STATUS_BLOCK iosb
;
1098 WCHAR cloneparw
[MAX_PATH
];
1100 DUPLICATE_EXTENTS_DATA ded
;
1101 LARGE_INTEGER filesize
;
1104 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_OFFSET
, (void**)&offset
, &offsetlen
)) {
1105 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"offset");
1109 if (offsetlen
< sizeof(UINT64
)) {
1110 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"offset", offsetlen
, sizeof(UINT64
));
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");
1119 if (clonelenlen
< sizeof(UINT64
)) {
1120 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"clone_len", clonelenlen
, sizeof(UINT64
));
1124 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &pathlen
)) {
1125 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
1129 if (!utf8_to_utf16(hwnd
, path
, pathlen
, &pathu
))
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");
1137 if (cloneuuidlen
< sizeof(BTRFS_UUID
)) {
1138 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"clone_uuid", cloneuuidlen
, sizeof(BTRFS_UUID
));
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");
1147 if (clonetransidlen
< sizeof(UINT64
)) {
1148 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"clone_ctransid", clonetransidlen
, sizeof(UINT64
));
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");
1157 if (!utf8_to_utf16(hwnd
, clonepath
, clonepathlen
, &clonepathu
))
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");
1165 if (cloneoffsetlen
< sizeof(UINT64
)) {
1166 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"clone_offset", cloneoffsetlen
, sizeof(UINT64
));
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
;
1179 WCHAR volpathw
[MAX_PATH
];
1181 bfs
.uuid
= *cloneuuid
;
1182 bfs
.ctransid
= *clonetransid
;
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
);
1189 } else if (!NT_SUCCESS(Status
)) {
1190 ShowRecvError(IDS_RECV_FIND_SUBVOL_FAILED
, Status
, format_ntstatus(Status
).c_str());
1194 if (!GetVolumePathNameW(dirpath
.c_str(), volpathw
, (sizeof(volpathw
) / sizeof(WCHAR
)) - 1)) {
1195 ShowRecvError(IDS_RECV_GETVOLUMEPATHNAME_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
1199 clonepar
= volpathw
;
1200 if (clonepar
.substr(clonepar
.length() - 1) == L
"\\")
1201 clonepar
= clonepar
.substr(0, clonepar
.length() - 1);
1203 clonepar
+= cloneparw
;
1206 add_cache_entry(cloneuuid
, *clonetransid
, clonepar
);
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());
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());
1224 if (!GetFileSizeEx(dest
, &filesize
)) {
1225 ShowRecvError(IDS_RECV_GETFILESIZEEX_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
1231 if ((UINT64
)filesize
.QuadPart
< *offset
+ *clonelen
) {
1232 LARGE_INTEGER sizeli
;
1234 sizeli
.QuadPart
= *offset
+ *clonelen
;
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());
1243 if (!SetEndOfFile(dest
)) {
1244 ShowRecvError(IDS_RECV_SETENDOFFILE_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
1251 ded
.FileHandle
= src
;
1252 ded
.SourceFileOffset
.QuadPart
= *cloneoffset
;
1253 ded
.TargetFileOffset
.QuadPart
= *offset
;
1254 ded
.ByteCount
.QuadPart
= *clonelen
;
1256 Status
= NtFsControlFile(dest
, NULL
, NULL
, NULL
, &iosb
, FSCTL_DUPLICATE_EXTENTS_TO_FILE
, &ded
, sizeof(DUPLICATE_EXTENTS_DATA
),
1258 if (!NT_SUCCESS(Status
)) {
1259 ShowRecvError(IDS_RECV_DUPLICATE_EXTENTS_FAILED
, Status
, format_ntstatus(Status
).c_str());
1271 BOOL
BtrfsRecv::cmd_truncate(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
1274 ULONG pathlen
, sizelen
;
1277 LARGE_INTEGER sizeli
;
1280 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &pathlen
)) {
1281 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
1285 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_SIZE
, (void**)&size
, &sizelen
)) {
1286 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"size");
1290 if (sizelen
< sizeof(UINT64
)) {
1291 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"size", sizelen
, sizeof(UINT64
));
1295 if (!utf8_to_utf16(hwnd
, path
, pathlen
, &pathu
))
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());
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());
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());
1318 sizeli
.QuadPart
= *size
;
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());
1326 if (!SetEndOfFile(h
)) {
1327 ShowRecvError(IDS_RECV_SETENDOFFILE_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
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());
1344 BOOL
BtrfsRecv::cmd_chmod(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
1348 ULONG pathlen
, modelen
;
1350 btrfs_set_inode_info bsii
;
1352 IO_STATUS_BLOCK iosb
;
1354 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &pathlen
)) {
1355 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
1359 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_MODE
, (void**)&mode
, &modelen
)) {
1360 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"mode");
1364 if (modelen
< sizeof(UINT32
)) {
1365 ShowRecvError(IDS_RECV_SHORT_PARAM
, funcname
, L
"mode", modelen
, sizeof(UINT32
));
1369 if (!utf8_to_utf16(hwnd
, path
, pathlen
, &pathu
))
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());
1379 memset(&bsii
, 0, sizeof(btrfs_set_inode_info
));
1381 bsii
.mode_changed
= TRUE
;
1382 bsii
.st_mode
= *mode
;
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());
1396 BOOL
BtrfsRecv::cmd_chown(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
1400 ULONG pathlen
, uidlen
, gidlen
;
1402 btrfs_set_inode_info bsii
;
1404 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &pathlen
)) {
1405 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
1409 if (!utf8_to_utf16(hwnd
, path
, pathlen
, &pathu
))
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());
1419 memset(&bsii
, 0, sizeof(btrfs_set_inode_info
));
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
));
1428 bsii
.uid_changed
= TRUE
;
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
));
1439 bsii
.gid_changed
= TRUE
;
1443 if (bsii
.uid_changed
|| bsii
.gid_changed
) {
1445 IO_STATUS_BLOCK iosb
;
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());
1460 static __inline UINT64
unix_time_to_win(BTRFS_TIME
* t
) {
1461 return (t
->seconds
* 10000000) + (t
->nanoseconds
/ 100) + 116444736000000000;
1464 BOOL
BtrfsRecv::cmd_utimes(HWND hwnd
, btrfs_send_command
* cmd
, UINT8
* data
) {
1469 FILE_BASIC_INFO fbi
;
1473 if (!find_tlv(data
, cmd
->length
, BTRFS_SEND_TLV_PATH
, (void**)&path
, &pathlen
)) {
1474 ShowRecvError(IDS_RECV_MISSING_PARAM
, funcname
, L
"path");
1478 if (!utf8_to_utf16(hwnd
, path
, pathlen
, &pathu
))
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());
1488 memset(&fbi
, 0, sizeof(FILE_BASIC_INFO
));
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
);
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
);
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
);
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
);
1502 if (!SetFileInformationByHandle(h
, FileBasicInfo
, &fbi
, sizeof(FILE_BASIC_INFO
))) {
1503 ShowRecvError(IDS_RECV_SETFILEINFO_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
1513 void BtrfsRecv::ShowRecvError(int resid
, ...) {
1514 WCHAR s
[1024], t
[1024];
1520 if (!LoadStringW(module
, resid
, s
, sizeof(s
) / sizeof(WCHAR
))) {
1521 ShowError(hwnd
, GetLastError());
1525 va_start(ap
, resid
);
1527 vswprintf(t
, sizeof(t
) / sizeof(WCHAR
), s
, ap
);
1529 vsnwprintf(t
, sizeof(t
) / sizeof(WCHAR
), s
, ap
);
1532 SetDlgItemTextW(hwnd
, IDC_RECV_MSG
, t
);
1536 SendMessageW(GetDlgItem(hwnd
, IDC_RECV_PROGRESS
), PBM_SETSTATE
, PBST_ERROR
, 0);
1539 static void delete_directory(std::wstring dir
) {
1541 WIN32_FIND_DATAW fff
;
1543 h
= FindFirstFileW((dir
+ L
"*").c_str(), &fff
);
1545 if (h
== INVALID_HANDLE_VALUE
)
1551 file
= fff
.cFileName
;
1553 if (file
!= L
"." && file
!= L
"..") {
1554 if (fff
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
1555 SetFileAttributesW((dir
+ file
).c_str(), fff
.dwFileAttributes
& ~FILE_ATTRIBUTE_READONLY
);
1557 if (fff
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
1558 if (!(fff
.dwFileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
))
1559 delete_directory(dir
+ file
+ L
"\\");
1561 RemoveDirectoryW((dir
+ file
).c_str());
1563 DeleteFileW((dir
+ file
).c_str());
1565 } while (FindNextFileW(h
, &fff
));
1569 RemoveDirectoryW(dir
.c_str());
1572 static BOOL
check_csum(btrfs_send_command
* cmd
, UINT8
* data
) {
1573 UINT32 crc32
= cmd
->csum
, calc
;
1577 calc
= calc_crc32c(0, (UINT8
*)cmd
, sizeof(btrfs_send_command
));
1579 if (cmd
->length
> 0)
1580 calc
= calc_crc32c(calc
, data
, cmd
->length
);
1582 return calc
== crc32
? TRUE
: FALSE
;
1585 BOOL
BtrfsRecv::do_recv(HANDLE f
, UINT64
* pos
, UINT64 size
) {
1586 btrfs_send_header header
;
1587 BOOL b
= TRUE
, ended
= FALSE
;
1589 if (!ReadFile(f
, &header
, sizeof(btrfs_send_header
), NULL
, NULL
)) {
1590 ShowRecvError(IDS_RECV_READFILE_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
1594 *pos
+= sizeof(btrfs_send_header
);
1596 if (memcmp(header
.magic
, BTRFS_SEND_MAGIC
, sizeof(header
.magic
))) {
1597 ShowRecvError(IDS_RECV_NOT_A_SEND_STREAM
);
1601 if (header
.version
> 1) {
1602 ShowRecvError(IDS_RECV_UNSUPPORTED_VERSION
, header
.version
);
1606 SendMessageW(GetDlgItem(hwnd
, IDC_RECV_PROGRESS
), PBM_SETRANGE32
, 0, (LPARAM
)65536);
1608 lastwritefile
= INVALID_HANDLE_VALUE
;
1609 lastwritepath
= L
"";
1613 btrfs_send_command cmd
;
1622 progress
= (ULONG
)((float)*pos
* 65536.0f
/ (float)size
);
1623 SendMessageW(GetDlgItem(hwnd
, IDC_RECV_PROGRESS
), PBM_SETPOS
, progress
, 0);
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());
1634 *pos
+= sizeof(btrfs_send_command
);
1636 if (cmd
.length
> 0) {
1637 if (*pos
+ cmd
.length
> size
) {
1638 ShowRecvError(IDS_RECV_FILE_TRUNCATED
);
1643 data
= (UINT8
*)malloc(cmd
.length
);
1645 ShowRecvError(IDS_OUT_OF_MEMORY
);
1650 if (!ReadFile(f
, data
, cmd
.length
, NULL
, NULL
)) {
1651 ShowRecvError(IDS_RECV_READFILE_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
1660 if (!check_csum(&cmd
, data
)) {
1661 ShowRecvError(IDS_RECV_CSUM_ERROR
);
1662 if (data
) free(data
);
1667 if (cmd
.cmd
== BTRFS_SEND_CMD_END
) {
1668 if (data
) free(data
);
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());
1681 CloseHandle(lastwritefile
);
1683 lastwritefile
= INVALID_HANDLE_VALUE
;
1684 lastwritepath
= L
"";
1689 case BTRFS_SEND_CMD_SUBVOL
:
1690 b
= cmd_subvol(hwnd
, &cmd
, data
);
1693 case BTRFS_SEND_CMD_SNAPSHOT
:
1694 b
= cmd_snapshot(hwnd
, &cmd
, data
);
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
);
1706 case BTRFS_SEND_CMD_RENAME
:
1707 b
= cmd_rename(hwnd
, &cmd
, data
);
1710 case BTRFS_SEND_CMD_LINK
:
1711 b
= cmd_link(hwnd
, &cmd
, data
);
1714 case BTRFS_SEND_CMD_UNLINK
:
1715 b
= cmd_unlink(hwnd
, &cmd
, data
);
1718 case BTRFS_SEND_CMD_RMDIR
:
1719 b
= cmd_rmdir(hwnd
, &cmd
, data
);
1722 case BTRFS_SEND_CMD_SET_XATTR
:
1723 b
= cmd_setxattr(hwnd
, &cmd
, data
);
1726 case BTRFS_SEND_CMD_REMOVE_XATTR
:
1727 b
= cmd_removexattr(hwnd
, &cmd
, data
);
1730 case BTRFS_SEND_CMD_WRITE
:
1731 b
= cmd_write(hwnd
, &cmd
, data
);
1734 case BTRFS_SEND_CMD_CLONE
:
1735 b
= cmd_clone(hwnd
, &cmd
, data
);
1738 case BTRFS_SEND_CMD_TRUNCATE
:
1739 b
= cmd_truncate(hwnd
, &cmd
, data
);
1742 case BTRFS_SEND_CMD_CHMOD
:
1743 b
= cmd_chmod(hwnd
, &cmd
, data
);
1746 case BTRFS_SEND_CMD_CHOWN
:
1747 b
= cmd_chown(hwnd
, &cmd
, data
);
1750 case BTRFS_SEND_CMD_UTIMES
:
1751 b
= cmd_utimes(hwnd
, &cmd
, data
);
1754 case BTRFS_SEND_CMD_UPDATE_EXTENT
:
1759 ShowRecvError(IDS_RECV_UNKNOWN_COMMAND
, cmd
.cmd
);
1764 if (data
) free(data
);
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());
1778 CloseHandle(lastwritefile
);
1782 ShowRecvError(IDS_RECV_FILE_TRUNCATED
);
1788 IO_STATUS_BLOCK iosb
;
1789 btrfs_received_subvol brs
;
1791 brs
.generation
= stransid
;
1792 brs
.uuid
= subvol_uuid
;
1794 Status
= NtFsControlFile(dir
, NULL
, NULL
, NULL
, &iosb
, FSCTL_BTRFS_RECEIVED_SUBVOL
, &brs
, sizeof(btrfs_received_subvol
),
1796 if (!NT_SUCCESS(Status
)) {
1797 ShowRecvError(IDS_RECV_RECEIVED_SUBVOL_FAILED
, Status
, format_ntstatus(Status
).c_str());
1804 if (master
!= INVALID_HANDLE_VALUE
)
1805 CloseHandle(master
);
1807 if (!b
&& subvolpath
!= L
"") {
1810 attrib
= GetFileAttributesW(subvolpath
.c_str());
1811 attrib
&= ~FILE_ATTRIBUTE_READONLY
;
1813 if (!SetFileAttributesW(subvolpath
.c_str(), attrib
))
1814 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
1816 delete_directory(subvolpath
);
1822 DWORD
BtrfsRecv::recv_thread() {
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());
1836 if (!GetFileSizeEx(f
, &size
)) {
1837 ShowRecvError(IDS_RECV_GETFILESIZEEX_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
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());
1850 b
= do_recv(f
, &pos
, size
.QuadPart
);
1851 } while (b
&& pos
< (UINT64
)size
.QuadPart
);
1853 CloseHandle(parent
);
1859 SendMessageW(GetDlgItem(hwnd
, IDC_RECV_PROGRESS
), PBM_SETPOS
, 65536, 0);
1861 if (num_received
== 1) {
1862 if (!LoadStringW(module
, IDS_RECV_SUCCESS
, s
, sizeof(s
) / sizeof(WCHAR
)))
1863 ShowError(hwnd
, GetLastError());
1865 SetDlgItemTextW(hwnd
, IDC_RECV_MSG
, s
);
1867 if (!LoadStringW(module
, IDS_RECV_SUCCESS_PLURAL
, s
, sizeof(s
) / sizeof(WCHAR
)))
1868 ShowError(hwnd
, GetLastError());
1872 if (StringCchPrintfW(t
, sizeof(t
) / sizeof(WCHAR
), s
, num_received
) == STRSAFE_E_INSUFFICIENT_BUFFER
)
1873 ShowError(hwnd
, ERROR_INSUFFICIENT_BUFFER
);
1875 SetDlgItemTextW(hwnd
, IDC_RECV_MSG
, t
);
1879 if (!LoadStringW(module
, IDS_RECV_BUTTON_OK
, s
, sizeof(s
) / sizeof(WCHAR
)))
1880 ShowError(hwnd
, GetLastError());
1882 SetDlgItemTextW(hwnd
, IDCANCEL
, s
);
1892 static DWORD WINAPI
global_recv_thread(LPVOID lpParameter
) {
1893 BtrfsRecv
* br
= (BtrfsRecv
*)lpParameter
;
1895 return br
->recv_thread();
1898 INT_PTR CALLBACK
BtrfsRecv::RecvProgressDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
1901 this->hwnd
= hwndDlg
;
1902 thread
= CreateThread(NULL
, 0, global_recv_thread
, this, 0, NULL
);
1905 ShowRecvError(IDS_RECV_CREATETHREAD_FAILED
, GetLastError(), format_message(GetLastError()).c_str());
1909 switch (HIWORD(wParam
)) {
1911 switch (LOWORD(wParam
)) {
1919 if (!LoadStringW(module
, IDS_RECV_CANCELLED
, s
, sizeof(s
) / sizeof(WCHAR
))) {
1920 ShowError(hwndDlg
, GetLastError());
1924 SetDlgItemTextW(hwnd
, IDC_RECV_MSG
, s
);
1925 SendMessageW(GetDlgItem(hwnd
, IDC_RECV_PROGRESS
), PBM_SETPOS
, 0, 0);
1927 if (!LoadStringW(module
, IDS_RECV_BUTTON_OK
, s
, sizeof(s
) / sizeof(WCHAR
))) {
1928 ShowError(hwndDlg
, GetLastError());
1932 SetDlgItemTextW(hwnd
, IDCANCEL
, s
);
1934 EndDialog(hwndDlg
, 1);
1946 static INT_PTR CALLBACK
stub_RecvProgressDlgProc(HWND hwndDlg
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
) {
1949 if (uMsg
== WM_INITDIALOG
) {
1950 SetWindowLongPtr(hwndDlg
, GWLP_USERDATA
, (LONG_PTR
)lParam
);
1951 br
= (BtrfsRecv
*)lParam
;
1953 br
= (BtrfsRecv
*)GetWindowLongPtr(hwndDlg
, GWLP_USERDATA
);
1957 return br
->RecvProgressDlgProc(hwndDlg
, uMsg
, wParam
, lParam
);
1962 void BtrfsRecv::Open(HWND hwnd
, WCHAR
* file
, WCHAR
* path
, BOOL quiet
) {
1973 __get_cpuid(1, &cpuInfo
[0], &cpuInfo
[1], &cpuInfo
[2], &cpuInfo
[3]);
1974 have_sse42
= cpuInfo
[2] & bit_SSE4_2
;
1976 __cpuid((int*)cpuInfo
, 1);
1977 have_sse42
= cpuInfo
[2] & (1 << 20);
1984 if (DialogBoxParamW(module
, MAKEINTRESOURCEW(IDD_RECV_PROGRESS
), hwnd
, stub_RecvProgressDlgProc
, (LPARAM
)this) <= 0)
1985 ShowError(hwnd
, GetLastError());
1989 void CALLBACK
RecvSubvolGUIW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
1991 WCHAR file
[MAX_PATH
];
1994 TOKEN_PRIVILEGES
* tp
;
2000 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
)) {
2001 ShowError(hwnd
, GetLastError());
2005 tplen
= offsetof(TOKEN_PRIVILEGES
, Privileges
[0]) + (3 * sizeof(LUID_AND_ATTRIBUTES
));
2006 tp
= (TOKEN_PRIVILEGES
*)malloc(tplen
);
2008 ShowStringError(hwnd
, IDS_OUT_OF_MEMORY
);
2013 tp
->PrivilegeCount
= 3;
2015 if (!LookupPrivilegeValueW(NULL
, L
"SeManageVolumePrivilege", &luid
)) {
2016 ShowError(hwnd
, GetLastError());
2022 tp
->Privileges
[0].Luid
= luid
;
2023 tp
->Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
2025 if (!LookupPrivilegeValueW(NULL
, L
"SeSecurityPrivilege", &luid
)) {
2026 ShowError(hwnd
, GetLastError());
2032 tp
->Privileges
[1].Luid
= luid
;
2033 tp
->Privileges
[1].Attributes
= SE_PRIVILEGE_ENABLED
;
2035 if (!LookupPrivilegeValueW(NULL
, L
"SeRestorePrivilege", &luid
)) {
2036 ShowError(hwnd
, GetLastError());
2042 tp
->Privileges
[2].Luid
= luid
;
2043 tp
->Privileges
[2].Attributes
= SE_PRIVILEGE_ENABLED
;
2045 if (!AdjustTokenPrivileges(token
, FALSE
, tp
, tplen
, NULL
, NULL
)) {
2046 ShowError(hwnd
, GetLastError());
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
;
2062 if (GetOpenFileNameW(&ofn
)) {
2063 recv
= new BtrfsRecv
;
2065 recv
->Open(hwnd
, file
, lpszCmdLine
, FALSE
);
2074 void CALLBACK
RecvSubvolW(HWND hwnd
, HINSTANCE hinst
, LPWSTR lpszCmdLine
, int nCmdShow
) {
2078 args
= CommandLineToArgvW(lpszCmdLine
, &num_args
);
2083 if (num_args
>= 2) {
2086 TOKEN_PRIVILEGES
* tp
;
2090 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
))
2093 tplen
= offsetof(TOKEN_PRIVILEGES
, Privileges
[0]) + (3 * sizeof(LUID_AND_ATTRIBUTES
));
2094 tp
= (TOKEN_PRIVILEGES
*)malloc(tplen
);
2100 tp
->PrivilegeCount
= 3;
2102 if (!LookupPrivilegeValueW(NULL
, L
"SeManageVolumePrivilege", &luid
)) {
2108 tp
->Privileges
[0].Luid
= luid
;
2109 tp
->Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
2111 if (!LookupPrivilegeValueW(NULL
, L
"SeSecurityPrivilege", &luid
)) {
2117 tp
->Privileges
[1].Luid
= luid
;
2118 tp
->Privileges
[1].Attributes
= SE_PRIVILEGE_ENABLED
;
2120 if (!LookupPrivilegeValueW(NULL
, L
"SeRestorePrivilege", &luid
)) {
2126 tp
->Privileges
[2].Luid
= luid
;
2127 tp
->Privileges
[2].Attributes
= SE_PRIVILEGE_ENABLED
;
2129 if (!AdjustTokenPrivileges(token
, FALSE
, tp
, tplen
, NULL
, NULL
)) {
2139 br
->Open(NULL
, args
[0], args
[1], TRUE
);