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 free(data); 1653 b = FALSE; 1654 break; 1655 } 1656 1657 *pos += cmd.length; 1658 } else 1659 data = NULL; 1660 1661 if (!check_csum(&cmd, data)) { 1662 ShowRecvError(IDS_RECV_CSUM_ERROR); 1663 if (data) free(data); 1664 b = FALSE; 1665 break; 1666 } 1667 1668 if (cmd.cmd == BTRFS_SEND_CMD_END) { 1669 if (data) free(data); 1670 ended = TRUE; 1671 break; 1672 } 1673 1674 if (lastwritefile != INVALID_HANDLE_VALUE && cmd.cmd != BTRFS_SEND_CMD_WRITE) { 1675 if (lastwriteatt & FILE_ATTRIBUTE_READONLY) { 1676 if (!SetFileAttributesW((subvolpath + lastwritepath).c_str(), lastwriteatt)) { 1677 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1678 return FALSE; 1679 } 1680 } 1681 1682 CloseHandle(lastwritefile); 1683 1684 lastwritefile = INVALID_HANDLE_VALUE; 1685 lastwritepath = L""; 1686 lastwriteatt = 0; 1687 } 1688 1689 switch (cmd.cmd) { 1690 case BTRFS_SEND_CMD_SUBVOL: 1691 b = cmd_subvol(hwnd, &cmd, data); 1692 break; 1693 1694 case BTRFS_SEND_CMD_SNAPSHOT: 1695 b = cmd_snapshot(hwnd, &cmd, data); 1696 break; 1697 1698 case BTRFS_SEND_CMD_MKFILE: 1699 case BTRFS_SEND_CMD_MKDIR: 1700 case BTRFS_SEND_CMD_MKNOD: 1701 case BTRFS_SEND_CMD_MKFIFO: 1702 case BTRFS_SEND_CMD_MKSOCK: 1703 case BTRFS_SEND_CMD_SYMLINK: 1704 b = cmd_mkfile(hwnd, &cmd, data); 1705 break; 1706 1707 case BTRFS_SEND_CMD_RENAME: 1708 b = cmd_rename(hwnd, &cmd, data); 1709 break; 1710 1711 case BTRFS_SEND_CMD_LINK: 1712 b = cmd_link(hwnd, &cmd, data); 1713 break; 1714 1715 case BTRFS_SEND_CMD_UNLINK: 1716 b = cmd_unlink(hwnd, &cmd, data); 1717 break; 1718 1719 case BTRFS_SEND_CMD_RMDIR: 1720 b = cmd_rmdir(hwnd, &cmd, data); 1721 break; 1722 1723 case BTRFS_SEND_CMD_SET_XATTR: 1724 b = cmd_setxattr(hwnd, &cmd, data); 1725 break; 1726 1727 case BTRFS_SEND_CMD_REMOVE_XATTR: 1728 b = cmd_removexattr(hwnd, &cmd, data); 1729 break; 1730 1731 case BTRFS_SEND_CMD_WRITE: 1732 b = cmd_write(hwnd, &cmd, data); 1733 break; 1734 1735 case BTRFS_SEND_CMD_CLONE: 1736 b = cmd_clone(hwnd, &cmd, data); 1737 break; 1738 1739 case BTRFS_SEND_CMD_TRUNCATE: 1740 b = cmd_truncate(hwnd, &cmd, data); 1741 break; 1742 1743 case BTRFS_SEND_CMD_CHMOD: 1744 b = cmd_chmod(hwnd, &cmd, data); 1745 break; 1746 1747 case BTRFS_SEND_CMD_CHOWN: 1748 b = cmd_chown(hwnd, &cmd, data); 1749 break; 1750 1751 case BTRFS_SEND_CMD_UTIMES: 1752 b = cmd_utimes(hwnd, &cmd, data); 1753 break; 1754 1755 case BTRFS_SEND_CMD_UPDATE_EXTENT: 1756 // does nothing 1757 break; 1758 1759 default: 1760 ShowRecvError(IDS_RECV_UNKNOWN_COMMAND, cmd.cmd); 1761 b = FALSE; 1762 break; 1763 } 1764 1765 if (data) free(data); 1766 1767 if (!b) 1768 break; 1769 } 1770 1771 if (lastwritefile != INVALID_HANDLE_VALUE) { 1772 if (lastwriteatt & FILE_ATTRIBUTE_READONLY) { 1773 if (!SetFileAttributesW((subvolpath + lastwritepath).c_str(), lastwriteatt)) { 1774 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1775 return FALSE; 1776 } 1777 } 1778 1779 CloseHandle(lastwritefile); 1780 } 1781 1782 if (b && !ended) { 1783 ShowRecvError(IDS_RECV_FILE_TRUNCATED); 1784 b = FALSE; 1785 } 1786 1787 if (b) { 1788 NTSTATUS Status; 1789 IO_STATUS_BLOCK iosb; 1790 btrfs_received_subvol brs; 1791 1792 brs.generation = stransid; 1793 brs.uuid = subvol_uuid; 1794 1795 Status = NtFsControlFile(dir, NULL, NULL, NULL, &iosb, FSCTL_BTRFS_RECEIVED_SUBVOL, &brs, sizeof(btrfs_received_subvol), 1796 NULL, 0); 1797 if (!NT_SUCCESS(Status)) { 1798 ShowRecvError(IDS_RECV_RECEIVED_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str()); 1799 b = FALSE; 1800 } 1801 } 1802 1803 CloseHandle(dir); 1804 1805 if (master != INVALID_HANDLE_VALUE) 1806 CloseHandle(master); 1807 1808 if (!b && subvolpath != L"") { 1809 ULONG attrib; 1810 1811 attrib = GetFileAttributesW(subvolpath.c_str()); 1812 attrib &= ~FILE_ATTRIBUTE_READONLY; 1813 1814 if (!SetFileAttributesW(subvolpath.c_str(), attrib)) 1815 ShowRecvError(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1816 else 1817 delete_directory(subvolpath); 1818 } 1819 1820 return b; 1821 } 1822 1823 DWORD BtrfsRecv::recv_thread() { 1824 HANDLE f; 1825 LARGE_INTEGER size; 1826 UINT64 pos = 0; 1827 BOOL b; 1828 1829 running = TRUE; 1830 1831 f = CreateFileW(streamfile.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); 1832 if (f == INVALID_HANDLE_VALUE) { 1833 ShowRecvError(IDS_RECV_CANT_OPEN_FILE, funcname, streamfile.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 1834 goto end; 1835 } 1836 1837 if (!GetFileSizeEx(f, &size)) { 1838 ShowRecvError(IDS_RECV_GETFILESIZEEX_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1839 goto end; 1840 } 1841 1842 parent = CreateFileW(dirpath.c_str(), FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1843 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, NULL); 1844 if (parent == INVALID_HANDLE_VALUE) { 1845 ShowRecvError(IDS_RECV_CANT_OPEN_PATH, dirpath.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 1846 CloseHandle(f); 1847 goto end; 1848 } 1849 1850 do { 1851 b = do_recv(f, &pos, size.QuadPart); 1852 } while (b && pos < (UINT64)size.QuadPart); 1853 1854 CloseHandle(parent); 1855 CloseHandle(f); 1856 1857 if (b && hwnd) { 1858 WCHAR s[255]; 1859 1860 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETPOS, 65536, 0); 1861 1862 if (num_received == 1) { 1863 if (!LoadStringW(module, IDS_RECV_SUCCESS, s, sizeof(s) / sizeof(WCHAR))) 1864 ShowError(hwnd, GetLastError()); 1865 else 1866 SetDlgItemTextW(hwnd, IDC_RECV_MSG, s); 1867 } else { 1868 if (!LoadStringW(module, IDS_RECV_SUCCESS_PLURAL, s, sizeof(s) / sizeof(WCHAR))) 1869 ShowError(hwnd, GetLastError()); 1870 else { 1871 WCHAR t[255]; 1872 1873 if (StringCchPrintfW(t, sizeof(t) / sizeof(WCHAR), s, num_received) == STRSAFE_E_INSUFFICIENT_BUFFER) 1874 ShowError(hwnd, ERROR_INSUFFICIENT_BUFFER); 1875 else 1876 SetDlgItemTextW(hwnd, IDC_RECV_MSG, t); 1877 } 1878 } 1879 1880 if (!LoadStringW(module, IDS_RECV_BUTTON_OK, s, sizeof(s) / sizeof(WCHAR))) 1881 ShowError(hwnd, GetLastError()); 1882 else 1883 SetDlgItemTextW(hwnd, IDCANCEL, s); 1884 } 1885 1886 end: 1887 thread = NULL; 1888 running = FALSE; 1889 1890 return 0; 1891 } 1892 1893 static DWORD WINAPI global_recv_thread(LPVOID lpParameter) { 1894 BtrfsRecv* br = (BtrfsRecv*)lpParameter; 1895 1896 return br->recv_thread(); 1897 } 1898 1899 INT_PTR CALLBACK BtrfsRecv::RecvProgressDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 1900 switch (uMsg) { 1901 case WM_INITDIALOG: 1902 this->hwnd = hwndDlg; 1903 thread = CreateThread(NULL, 0, global_recv_thread, this, 0, NULL); 1904 1905 if (!thread) 1906 ShowRecvError(IDS_RECV_CREATETHREAD_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1907 break; 1908 1909 case WM_COMMAND: 1910 switch (HIWORD(wParam)) { 1911 case BN_CLICKED: 1912 switch (LOWORD(wParam)) { 1913 case IDOK: 1914 case IDCANCEL: 1915 if (running) { 1916 WCHAR s[255]; 1917 1918 cancelling = TRUE; 1919 1920 if (!LoadStringW(module, IDS_RECV_CANCELLED, s, sizeof(s) / sizeof(WCHAR))) { 1921 ShowError(hwndDlg, GetLastError()); 1922 return FALSE; 1923 } 1924 1925 SetDlgItemTextW(hwnd, IDC_RECV_MSG, s); 1926 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETPOS, 0, 0); 1927 1928 if (!LoadStringW(module, IDS_RECV_BUTTON_OK, s, sizeof(s) / sizeof(WCHAR))) { 1929 ShowError(hwndDlg, GetLastError()); 1930 return FALSE; 1931 } 1932 1933 SetDlgItemTextW(hwnd, IDCANCEL, s); 1934 } else 1935 EndDialog(hwndDlg, 1); 1936 1937 return TRUE; 1938 } 1939 break; 1940 } 1941 break; 1942 } 1943 1944 return FALSE; 1945 } 1946 1947 static INT_PTR CALLBACK stub_RecvProgressDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 1948 BtrfsRecv* br; 1949 1950 if (uMsg == WM_INITDIALOG) { 1951 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); 1952 br = (BtrfsRecv*)lParam; 1953 } else { 1954 br = (BtrfsRecv*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 1955 } 1956 1957 if (br) 1958 return br->RecvProgressDlgProc(hwndDlg, uMsg, wParam, lParam); 1959 else 1960 return FALSE; 1961 } 1962 1963 void BtrfsRecv::Open(HWND hwnd, WCHAR* file, WCHAR* path, BOOL quiet) { 1964 #ifndef __REACTOS__ 1965 UINT32 cpuInfo[4]; 1966 #endif 1967 1968 streamfile = file; 1969 dirpath = path; 1970 subvolpath = L""; 1971 1972 #ifndef __REACTOS__ 1973 #ifndef _MSC_VER 1974 __get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3]); 1975 have_sse42 = cpuInfo[2] & bit_SSE4_2; 1976 #else 1977 __cpuid((int*)cpuInfo, 1); 1978 have_sse42 = cpuInfo[2] & (1 << 20); 1979 #endif 1980 #endif 1981 1982 if (quiet) 1983 recv_thread(); 1984 else { 1985 if (DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_RECV_PROGRESS), hwnd, stub_RecvProgressDlgProc, (LPARAM)this) <= 0) 1986 ShowError(hwnd, GetLastError()); 1987 } 1988 } 1989 1990 void CALLBACK RecvSubvolGUIW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 1991 OPENFILENAMEW ofn; 1992 WCHAR file[MAX_PATH]; 1993 BtrfsRecv* recv; 1994 HANDLE token; 1995 TOKEN_PRIVILEGES* tp; 1996 LUID luid; 1997 ULONG tplen; 1998 1999 set_dpi_aware(); 2000 2001 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { 2002 ShowError(hwnd, GetLastError()); 2003 return; 2004 } 2005 2006 tplen = offsetof(TOKEN_PRIVILEGES, Privileges[0]) + (3 * sizeof(LUID_AND_ATTRIBUTES)); 2007 tp = (TOKEN_PRIVILEGES*)malloc(tplen); 2008 if (!tp) { 2009 ShowStringError(hwnd, IDS_OUT_OF_MEMORY); 2010 CloseHandle(token); 2011 return; 2012 } 2013 2014 tp->PrivilegeCount = 3; 2015 2016 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) { 2017 ShowError(hwnd, GetLastError()); 2018 free(tp); 2019 CloseHandle(token); 2020 return; 2021 } 2022 2023 tp->Privileges[0].Luid = luid; 2024 tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 2025 2026 if (!LookupPrivilegeValueW(NULL, L"SeSecurityPrivilege", &luid)) { 2027 ShowError(hwnd, GetLastError()); 2028 free(tp); 2029 CloseHandle(token); 2030 return; 2031 } 2032 2033 tp->Privileges[1].Luid = luid; 2034 tp->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED; 2035 2036 if (!LookupPrivilegeValueW(NULL, L"SeRestorePrivilege", &luid)) { 2037 ShowError(hwnd, GetLastError()); 2038 free(tp); 2039 CloseHandle(token); 2040 return; 2041 } 2042 2043 tp->Privileges[2].Luid = luid; 2044 tp->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED; 2045 2046 if (!AdjustTokenPrivileges(token, FALSE, tp, tplen, NULL, NULL)) { 2047 ShowError(hwnd, GetLastError()); 2048 free(tp); 2049 CloseHandle(token); 2050 return; 2051 } 2052 2053 file[0] = 0; 2054 2055 memset(&ofn, 0, sizeof(OPENFILENAMEW)); 2056 ofn.lStructSize = sizeof(OPENFILENAMEW); 2057 ofn.hwndOwner = hwnd; 2058 ofn.hInstance = module; 2059 ofn.lpstrFile = file; 2060 ofn.nMaxFile = sizeof(file) / sizeof(WCHAR); 2061 ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; 2062 2063 if (GetOpenFileNameW(&ofn)) { 2064 recv = new BtrfsRecv; 2065 2066 recv->Open(hwnd, file, lpszCmdLine, FALSE); 2067 2068 delete recv; 2069 } 2070 2071 free(tp); 2072 CloseHandle(token); 2073 } 2074 2075 void CALLBACK RecvSubvolW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 2076 LPWSTR* args; 2077 int num_args; 2078 2079 args = CommandLineToArgvW(lpszCmdLine, &num_args); 2080 2081 if (!args) 2082 return; 2083 2084 if (num_args >= 2) { 2085 BtrfsRecv* br; 2086 HANDLE token; 2087 TOKEN_PRIVILEGES* tp; 2088 ULONG tplen; 2089 LUID luid; 2090 2091 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 2092 goto end; 2093 2094 tplen = offsetof(TOKEN_PRIVILEGES, Privileges[0]) + (3 * sizeof(LUID_AND_ATTRIBUTES)); 2095 tp = (TOKEN_PRIVILEGES*)malloc(tplen); 2096 if (!tp) { 2097 CloseHandle(token); 2098 goto end; 2099 } 2100 2101 tp->PrivilegeCount = 3; 2102 2103 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) { 2104 free(tp); 2105 CloseHandle(token); 2106 goto end; 2107 } 2108 2109 tp->Privileges[0].Luid = luid; 2110 tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 2111 2112 if (!LookupPrivilegeValueW(NULL, L"SeSecurityPrivilege", &luid)) { 2113 free(tp); 2114 CloseHandle(token); 2115 goto end; 2116 } 2117 2118 tp->Privileges[1].Luid = luid; 2119 tp->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED; 2120 2121 if (!LookupPrivilegeValueW(NULL, L"SeRestorePrivilege", &luid)) { 2122 free(tp); 2123 CloseHandle(token); 2124 goto end; 2125 } 2126 2127 tp->Privileges[2].Luid = luid; 2128 tp->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED; 2129 2130 if (!AdjustTokenPrivileges(token, FALSE, tp, tplen, NULL, NULL)) { 2131 free(tp); 2132 CloseHandle(token); 2133 goto end; 2134 } 2135 2136 free(tp); 2137 CloseHandle(token); 2138 2139 br = new BtrfsRecv; 2140 br->Open(NULL, args[0], args[1], TRUE); 2141 2142 delete br; 2143 } 2144 2145 end: 2146 LocalFree(args); 2147 } 2148