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 <iostream> 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 const string EA_NTACL = "security.NTACL"; 38 const string EA_DOSATTRIB = "user.DOSATTRIB"; 39 const string EA_REPARSE = "user.reparse"; 40 const string EA_EA = "user.EA"; 41 const string XATTR_USER = "user."; 42 43 #ifndef __REACTOS__ 44 bool have_sse42 = false; 45 #endif 46 47 static const uint32_t 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) -= (ULONG)sizeof(type), buf += sizeof (type)) { \ 88 (crc) = (uint32_t)op((crc), *(type *) (buf)); \ 89 } \ 90 } while(0) 91 92 #ifndef __REACTOS__ 93 static uint32_t crc32c_hw(const void *input, ULONG len, uint32_t 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_t(!) 112 #pragma warning(disable:4242) 113 #endif 114 CALC_CRC(_mm_crc32_u64, crc, uint64_t, buf, len); 115 #ifdef _MSC_VER 116 #pragma warning(pop) 117 #endif 118 #endif 119 CALC_CRC(_mm_crc32_u32, crc, uint32_t, 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_t, buf, len); 127 CALC_CRC(_mm_crc32_u8, crc, uint8_t, buf, len); 128 #endif 129 130 return crc; 131 } 132 #endif 133 134 static uint32_t calc_crc32c(uint32_t seed, uint8_t* msg, ULONG msglen) { 135 #ifndef __REACTOS__ 136 if (have_sse42) 137 return crc32c_hw(msg, msglen, seed); 138 else { 139 #endif 140 uint32_t 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_t* data, ULONG datalen, uint16_t type, void** value, ULONG* len) { 156 size_t off = 0; 157 158 while (off < datalen) { 159 btrfs_send_tlv* tlv = (btrfs_send_tlv*)(data + off); 160 uint8_t* 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 void BtrfsRecv::cmd_subvol(HWND hwnd, btrfs_send_command* cmd, uint8_t* data, const win_handle& parent) { 178 string name; 179 BTRFS_UUID* uuid; 180 uint64_t* gen; 181 ULONG uuidlen, genlen; 182 btrfs_create_subvol* bcs; 183 NTSTATUS Status; 184 IO_STATUS_BLOCK iosb; 185 186 { 187 char* namebuf; 188 ULONG namelen; 189 190 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&namebuf, &namelen)) 191 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 192 193 name = string(namebuf, namelen); 194 } 195 196 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_UUID, (void**)&uuid, &uuidlen)) 197 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"uuid"); 198 199 if (uuidlen < sizeof(BTRFS_UUID)) 200 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"uuid", uuidlen, sizeof(BTRFS_UUID)); 201 202 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_TRANSID, (void**)&gen, &genlen)) 203 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"transid"); 204 205 if (genlen < sizeof(uint64_t)) 206 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"transid", genlen, sizeof(uint64_t)); 207 208 this->subvol_uuid = *uuid; 209 this->stransid = *gen; 210 211 auto nameu = utf8_to_utf16(name); 212 213 size_t bcslen = offsetof(btrfs_create_subvol, name[0]) + (nameu.length() * sizeof(WCHAR)); 214 bcs = (btrfs_create_subvol*)malloc(bcslen); 215 216 bcs->readonly = true; 217 bcs->posix = true; 218 bcs->namelen = (uint16_t)(nameu.length() * sizeof(WCHAR)); 219 memcpy(bcs->name, nameu.c_str(), bcs->namelen); 220 221 Status = NtFsControlFile(parent, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SUBVOL, bcs, (ULONG)bcslen, nullptr, 0); 222 if (!NT_SUCCESS(Status)) 223 throw string_error(IDS_RECV_CREATE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str()); 224 225 subvolpath = dirpath; 226 subvolpath += L"\\"; 227 subvolpath += nameu; 228 229 if (dir != INVALID_HANDLE_VALUE) 230 CloseHandle(dir); 231 232 if (master != INVALID_HANDLE_VALUE) 233 CloseHandle(master); 234 235 master = CreateFileW(subvolpath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 236 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, nullptr); 237 if (master == INVALID_HANDLE_VALUE) 238 throw string_error(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 239 240 Status = NtFsControlFile(master, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESERVE_SUBVOL, bcs, (ULONG)bcslen, nullptr, 0); 241 if (!NT_SUCCESS(Status)) 242 throw string_error(IDS_RECV_RESERVE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str()); 243 244 dir = CreateFileW(subvolpath.c_str(), FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE, 245 FILE_SHARE_READ | FILE_SHARE_WRITE, 246 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, nullptr); 247 if (dir == INVALID_HANDLE_VALUE) 248 throw string_error(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 249 250 subvolpath += L"\\"; 251 252 add_cache_entry(&this->subvol_uuid, this->stransid, subvolpath); 253 254 num_received++; 255 } 256 257 void BtrfsRecv::add_cache_entry(BTRFS_UUID* uuid, uint64_t transid, const wstring& path) { 258 subvol_cache sc; 259 260 sc.uuid = *uuid; 261 sc.transid = transid; 262 sc.path = path; 263 264 cache.push_back(sc); 265 } 266 267 void BtrfsRecv::cmd_snapshot(HWND hwnd, btrfs_send_command* cmd, uint8_t* data, const win_handle& parent) { 268 string name; 269 BTRFS_UUID *uuid, *parent_uuid; 270 uint64_t *gen, *parent_transid; 271 ULONG uuidlen, genlen, paruuidlen, partransidlen; 272 btrfs_create_snapshot* bcs; 273 NTSTATUS Status; 274 IO_STATUS_BLOCK iosb; 275 wstring parpath; 276 btrfs_find_subvol bfs; 277 WCHAR parpathw[MAX_PATH], volpathw[MAX_PATH]; 278 size_t bcslen; 279 280 { 281 char* namebuf; 282 ULONG namelen; 283 284 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&namebuf, &namelen)) 285 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 286 287 name = string(namebuf, namelen); 288 } 289 290 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_UUID, (void**)&uuid, &uuidlen)) 291 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"uuid"); 292 293 if (uuidlen < sizeof(BTRFS_UUID)) 294 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"uuid", uuidlen, sizeof(BTRFS_UUID)); 295 296 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_TRANSID, (void**)&gen, &genlen)) 297 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"transid"); 298 299 if (genlen < sizeof(uint64_t)) 300 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"transid", genlen, sizeof(uint64_t)); 301 302 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_UUID, (void**)&parent_uuid, &paruuidlen)) 303 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"clone_uuid"); 304 305 if (paruuidlen < sizeof(BTRFS_UUID)) 306 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"clone_uuid", paruuidlen, sizeof(BTRFS_UUID)); 307 308 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_CTRANSID, (void**)&parent_transid, &partransidlen)) 309 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"clone_ctransid"); 310 311 if (partransidlen < sizeof(uint64_t)) 312 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"clone_ctransid", partransidlen, sizeof(uint64_t)); 313 314 this->subvol_uuid = *uuid; 315 this->stransid = *gen; 316 317 auto nameu = utf8_to_utf16(name); 318 319 bfs.uuid = *parent_uuid; 320 bfs.ctransid = *parent_transid; 321 322 Status = NtFsControlFile(parent, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_FIND_SUBVOL, &bfs, sizeof(btrfs_find_subvol), 323 parpathw, sizeof(parpathw)); 324 if (Status == STATUS_NOT_FOUND) 325 throw string_error(IDS_RECV_CANT_FIND_PARENT_SUBVOL); 326 else if (!NT_SUCCESS(Status)) 327 throw string_error(IDS_RECV_FIND_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str()); 328 329 if (!GetVolumePathNameW(dirpath.c_str(), volpathw, (sizeof(volpathw) / sizeof(WCHAR)) - 1)) 330 throw string_error(IDS_RECV_GETVOLUMEPATHNAME_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 331 332 parpath = volpathw; 333 if (parpath.substr(parpath.length() - 1) == L"\\") 334 parpath = parpath.substr(0, parpath.length() - 1); 335 336 parpath += parpathw; 337 338 { 339 win_handle subvol = CreateFileW(parpath.c_str(), FILE_TRAVERSE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 340 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); 341 if (subvol == INVALID_HANDLE_VALUE) 342 throw string_error(IDS_RECV_CANT_OPEN_PATH, parpath.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 343 344 bcslen = offsetof(btrfs_create_snapshot, name[0]) + (nameu.length() * sizeof(WCHAR)); 345 bcs = (btrfs_create_snapshot*)malloc(bcslen); 346 347 bcs->readonly = true; 348 bcs->posix = true; 349 bcs->subvol = subvol; 350 bcs->namelen = (uint16_t)(nameu.length() * sizeof(WCHAR)); 351 memcpy(bcs->name, nameu.c_str(), bcs->namelen); 352 353 Status = NtFsControlFile(parent, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_CREATE_SNAPSHOT, bcs, (ULONG)bcslen, nullptr, 0); 354 if (!NT_SUCCESS(Status)) 355 throw string_error(IDS_RECV_CREATE_SNAPSHOT_FAILED, Status, format_ntstatus(Status).c_str()); 356 } 357 358 subvolpath = dirpath; 359 subvolpath += L"\\"; 360 subvolpath += nameu; 361 362 if (dir != INVALID_HANDLE_VALUE) 363 CloseHandle(dir); 364 365 if (master != INVALID_HANDLE_VALUE) 366 CloseHandle(master); 367 368 master = CreateFileW(subvolpath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 369 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, nullptr); 370 if (master == INVALID_HANDLE_VALUE) 371 throw string_error(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 372 373 Status = NtFsControlFile(master, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RESERVE_SUBVOL, bcs, (ULONG)bcslen, nullptr, 0); 374 if (!NT_SUCCESS(Status)) 375 throw string_error(IDS_RECV_RESERVE_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str()); 376 377 dir = CreateFileW(subvolpath.c_str(), FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE, 378 FILE_SHARE_READ | FILE_SHARE_WRITE, 379 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, nullptr); 380 if (dir == INVALID_HANDLE_VALUE) 381 throw string_error(IDS_RECV_CANT_OPEN_PATH, subvolpath.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 382 383 subvolpath += L"\\"; 384 385 add_cache_entry(&this->subvol_uuid, this->stransid, subvolpath); 386 387 num_received++; 388 } 389 390 void BtrfsRecv::cmd_mkfile(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 391 uint64_t *inode, *rdev = nullptr, *mode = nullptr; 392 ULONG inodelen; 393 NTSTATUS Status; 394 IO_STATUS_BLOCK iosb; 395 btrfs_mknod* bmn; 396 wstring nameu, pathlinku; 397 398 { 399 char* name; 400 ULONG namelen; 401 402 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&name, &namelen)) 403 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 404 405 nameu = utf8_to_utf16(string(name, namelen)); 406 } 407 408 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_INODE, (void**)&inode, &inodelen)) 409 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"inode"); 410 411 if (inodelen < sizeof(uint64_t)) 412 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"inode", inodelen, sizeof(uint64_t)); 413 414 if (cmd->cmd == BTRFS_SEND_CMD_MKNOD || cmd->cmd == BTRFS_SEND_CMD_MKFIFO || cmd->cmd == BTRFS_SEND_CMD_MKSOCK) { 415 ULONG rdevlen, modelen; 416 417 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_RDEV, (void**)&rdev, &rdevlen)) 418 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"rdev"); 419 420 if (rdevlen < sizeof(uint64_t)) 421 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"rdev", rdev, sizeof(uint64_t)); 422 423 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_MODE, (void**)&mode, &modelen)) 424 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"mode"); 425 426 if (modelen < sizeof(uint64_t)) 427 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"mode", modelen, sizeof(uint64_t)); 428 } else if (cmd->cmd == BTRFS_SEND_CMD_SYMLINK) { 429 char* pathlink; 430 ULONG pathlinklen; 431 432 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_LINK, (void**)&pathlink, &pathlinklen)) 433 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path_link"); 434 435 pathlinku = utf8_to_utf16(string(pathlink, pathlinklen)); 436 } 437 438 size_t bmnsize = sizeof(btrfs_mknod) - sizeof(WCHAR) + (nameu.length() * sizeof(WCHAR)); 439 bmn = (btrfs_mknod*)malloc(bmnsize); 440 441 bmn->inode = *inode; 442 443 if (cmd->cmd == BTRFS_SEND_CMD_MKDIR) 444 bmn->type = BTRFS_TYPE_DIRECTORY; 445 else if (cmd->cmd == BTRFS_SEND_CMD_MKNOD) 446 bmn->type = *mode & S_IFCHR ? BTRFS_TYPE_CHARDEV : BTRFS_TYPE_BLOCKDEV; 447 else if (cmd->cmd == BTRFS_SEND_CMD_MKFIFO) 448 bmn->type = BTRFS_TYPE_FIFO; 449 else if (cmd->cmd == BTRFS_SEND_CMD_MKSOCK) 450 bmn->type = BTRFS_TYPE_SOCKET; 451 else 452 bmn->type = BTRFS_TYPE_FILE; 453 454 bmn->st_rdev = rdev ? *rdev : 0; 455 bmn->namelen = (uint16_t)(nameu.length() * sizeof(WCHAR)); 456 memcpy(bmn->name, nameu.c_str(), bmn->namelen); 457 458 Status = NtFsControlFile(dir, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_MKNOD, bmn, (ULONG)bmnsize, nullptr, 0); 459 if (!NT_SUCCESS(Status)) { 460 free(bmn); 461 throw string_error(IDS_RECV_MKNOD_FAILED, Status, format_ntstatus(Status).c_str()); 462 } 463 464 free(bmn); 465 466 if (cmd->cmd == BTRFS_SEND_CMD_SYMLINK) { 467 REPARSE_DATA_BUFFER* rdb; 468 btrfs_set_inode_info bsii; 469 470 size_t rdblen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]) + (2 * pathlinku.length() * sizeof(WCHAR)); 471 472 if (rdblen >= 0x10000) 473 throw string_error(IDS_RECV_PATH_TOO_LONG, funcname); 474 475 rdb = (REPARSE_DATA_BUFFER*)malloc(rdblen); 476 477 rdb->ReparseTag = IO_REPARSE_TAG_SYMLINK; 478 rdb->ReparseDataLength = (uint16_t)(rdblen - offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer)); 479 rdb->Reserved = 0; 480 rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0; 481 rdb->SymbolicLinkReparseBuffer.SubstituteNameLength = (uint16_t)(pathlinku.length() * sizeof(WCHAR)); 482 rdb->SymbolicLinkReparseBuffer.PrintNameOffset = (uint16_t)(pathlinku.length() * sizeof(WCHAR)); 483 rdb->SymbolicLinkReparseBuffer.PrintNameLength = (uint16_t)(pathlinku.length() * sizeof(WCHAR)); 484 rdb->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE; 485 486 memcpy(rdb->SymbolicLinkReparseBuffer.PathBuffer, pathlinku.c_str(), rdb->SymbolicLinkReparseBuffer.SubstituteNameLength); 487 memcpy(rdb->SymbolicLinkReparseBuffer.PathBuffer + (rdb->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR)), 488 pathlinku.c_str(), rdb->SymbolicLinkReparseBuffer.PrintNameLength); 489 490 win_handle h = CreateFileW((subvolpath + nameu).c_str(), GENERIC_WRITE | WRITE_DAC, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 491 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, nullptr); 492 if (h == INVALID_HANDLE_VALUE) { 493 free(rdb); 494 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, nameu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 495 } 496 497 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_SET_REPARSE_POINT, rdb, (ULONG)rdblen, nullptr, 0); 498 if (!NT_SUCCESS(Status)) { 499 free(rdb); 500 throw string_error(IDS_RECV_SET_REPARSE_POINT_FAILED, Status, format_ntstatus(Status).c_str()); 501 } 502 503 free(rdb); 504 505 memset(&bsii, 0, sizeof(btrfs_set_inode_info)); 506 507 bsii.mode_changed = true; 508 bsii.st_mode = 0777; 509 510 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), nullptr, 0); 511 if (!NT_SUCCESS(Status)) 512 throw string_error(IDS_RECV_SETINODEINFO_FAILED, Status, format_ntstatus(Status).c_str()); 513 } else if (cmd->cmd == BTRFS_SEND_CMD_MKNOD || cmd->cmd == BTRFS_SEND_CMD_MKFIFO || cmd->cmd == BTRFS_SEND_CMD_MKSOCK) { 514 uint64_t* mode; 515 ULONG modelen; 516 517 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_MODE, (void**)&mode, &modelen)) { 518 btrfs_set_inode_info bsii; 519 520 if (modelen < sizeof(uint64_t)) 521 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"mode", modelen, sizeof(uint64_t)); 522 523 win_handle h = CreateFileW((subvolpath + nameu).c_str(), WRITE_DAC, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 524 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, nullptr); 525 if (h == INVALID_HANDLE_VALUE) 526 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, nameu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 527 528 memset(&bsii, 0, sizeof(btrfs_set_inode_info)); 529 530 bsii.mode_changed = true; 531 bsii.st_mode = (uint32_t)*mode; 532 533 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), nullptr, 0); 534 if (!NT_SUCCESS(Status)) 535 throw string_error(IDS_RECV_SETINODEINFO_FAILED, Status, format_ntstatus(Status).c_str()); 536 } 537 } 538 } 539 540 void BtrfsRecv::cmd_rename(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 541 wstring pathu, path_tou; 542 543 { 544 char* path; 545 ULONG path_len; 546 547 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &path_len)) 548 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 549 550 pathu = utf8_to_utf16(string(path, path_len)); 551 } 552 553 { 554 char* path_to; 555 ULONG path_to_len; 556 557 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_TO, (void**)&path_to, &path_to_len)) 558 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path_to"); 559 560 path_tou = utf8_to_utf16(string(path_to, path_to_len)); 561 } 562 563 if (!MoveFileW((subvolpath + pathu).c_str(), (subvolpath + path_tou).c_str())) 564 throw string_error(IDS_RECV_MOVEFILE_FAILED, pathu.c_str(), path_tou.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 565 } 566 567 void BtrfsRecv::cmd_link(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 568 wstring pathu, path_linku; 569 570 { 571 char* path; 572 ULONG path_len; 573 574 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &path_len)) 575 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 576 577 pathu = utf8_to_utf16(string(path, path_len)); 578 } 579 580 { 581 char* path_link; 582 ULONG path_link_len; 583 584 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH_LINK, (void**)&path_link, &path_link_len)) 585 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path_link"); 586 587 path_linku = utf8_to_utf16(string(path_link, path_link_len)); 588 } 589 590 if (!CreateHardLinkW((subvolpath + pathu).c_str(), (subvolpath + path_linku).c_str(), nullptr)) 591 throw string_error(IDS_RECV_CREATEHARDLINK_FAILED, pathu.c_str(), path_linku.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 592 } 593 594 void BtrfsRecv::cmd_unlink(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 595 wstring pathu; 596 ULONG att; 597 598 { 599 char* path; 600 ULONG pathlen; 601 602 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) 603 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 604 605 pathu = utf8_to_utf16(string(path, pathlen)); 606 } 607 608 att = GetFileAttributesW((subvolpath + pathu).c_str()); 609 if (att == INVALID_FILE_ATTRIBUTES) 610 throw string_error(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 611 612 if (att & FILE_ATTRIBUTE_READONLY) { 613 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att & ~FILE_ATTRIBUTE_READONLY)) 614 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 615 } 616 617 if (!DeleteFileW((subvolpath + pathu).c_str())) 618 throw string_error(IDS_RECV_DELETEFILE_FAILED, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 619 } 620 621 void BtrfsRecv::cmd_rmdir(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 622 wstring pathu; 623 ULONG att; 624 625 { 626 char* path; 627 ULONG pathlen; 628 629 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) 630 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 631 632 pathu = utf8_to_utf16(string(path, pathlen)); 633 } 634 635 att = GetFileAttributesW((subvolpath + pathu).c_str()); 636 if (att == INVALID_FILE_ATTRIBUTES) 637 throw string_error(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 638 639 if (att & FILE_ATTRIBUTE_READONLY) { 640 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att & ~FILE_ATTRIBUTE_READONLY)) 641 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 642 } 643 644 if (!RemoveDirectoryW((subvolpath + pathu).c_str())) 645 throw string_error(IDS_RECV_REMOVEDIRECTORY_FAILED, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 646 } 647 648 void BtrfsRecv::cmd_setxattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 649 string xattrname; 650 uint8_t* xattrdata; 651 ULONG xattrdatalen; 652 wstring pathu; 653 654 { 655 char* path; 656 ULONG pathlen; 657 658 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) 659 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 660 661 pathu = utf8_to_utf16(string(path, pathlen)); 662 } 663 664 { 665 char* xattrnamebuf; 666 ULONG xattrnamelen; 667 668 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_XATTR_NAME, (void**)&xattrnamebuf, &xattrnamelen)) 669 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"xattr_name"); 670 671 xattrname = string(xattrnamebuf, xattrnamelen); 672 } 673 674 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_XATTR_DATA, (void**)&xattrdata, &xattrdatalen)) 675 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"xattr_data"); 676 677 if (xattrname.length() > XATTR_USER.length() && xattrname.substr(0, XATTR_USER.length()) == XATTR_USER && 678 xattrname != EA_DOSATTRIB && xattrname != EA_EA && xattrname != EA_REPARSE) { 679 ULONG att; 680 681 auto streamname = utf8_to_utf16(xattrname); 682 683 att = GetFileAttributesW((subvolpath + pathu).c_str()); 684 if (att == INVALID_FILE_ATTRIBUTES) 685 throw string_error(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 686 687 if (att & FILE_ATTRIBUTE_READONLY) { 688 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att & ~FILE_ATTRIBUTE_READONLY)) 689 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 690 } 691 692 streamname = streamname.substr(XATTR_USER.length()); 693 694 win_handle h = CreateFileW((subvolpath + pathu + L":" + streamname).c_str(), GENERIC_WRITE, 0, 695 nullptr, CREATE_ALWAYS, FILE_FLAG_POSIX_SEMANTICS, nullptr); 696 if (h == INVALID_HANDLE_VALUE) 697 throw string_error(IDS_RECV_CANT_CREATE_FILE, (pathu + L":" + streamname).c_str(), GetLastError(), format_message(GetLastError()).c_str()); 698 699 if (xattrdatalen > 0) { 700 if (!WriteFile(h, xattrdata, xattrdatalen, nullptr, nullptr)) 701 throw string_error(IDS_RECV_WRITEFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 702 } 703 704 if (att & FILE_ATTRIBUTE_READONLY) { 705 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att)) 706 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 707 } 708 } else { 709 IO_STATUS_BLOCK iosb; 710 NTSTATUS Status; 711 ULONG perms = FILE_WRITE_ATTRIBUTES; 712 btrfs_set_xattr* bsxa; 713 714 if (xattrname == EA_NTACL) 715 perms |= WRITE_DAC | WRITE_OWNER; 716 else if (xattrname == EA_EA) 717 perms |= FILE_WRITE_EA; 718 719 win_handle h = CreateFileW((subvolpath + pathu).c_str(), perms, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 720 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_OPEN_REPARSE_POINT, nullptr); 721 if (h == INVALID_HANDLE_VALUE) 722 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 723 724 size_t bsxalen = offsetof(btrfs_set_xattr, data[0]) + xattrname.length() + xattrdatalen; 725 bsxa = (btrfs_set_xattr*)malloc(bsxalen); 726 if (!bsxa) 727 throw string_error(IDS_OUT_OF_MEMORY); 728 729 bsxa->namelen = (uint16_t)xattrname.length(); 730 bsxa->valuelen = (uint16_t)xattrdatalen; 731 memcpy(bsxa->data, xattrname.c_str(), xattrname.length()); 732 memcpy(&bsxa->data[xattrname.length()], xattrdata, xattrdatalen); 733 734 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, bsxa, (ULONG)bsxalen, nullptr, 0); 735 if (!NT_SUCCESS(Status)) { 736 free(bsxa); 737 throw string_error(IDS_RECV_SETXATTR_FAILED, Status, format_ntstatus(Status).c_str()); 738 } 739 740 free(bsxa); 741 } 742 } 743 744 void BtrfsRecv::cmd_removexattr(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 745 wstring pathu; 746 string xattrname; 747 748 { 749 char* path; 750 ULONG pathlen; 751 752 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) 753 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 754 755 pathu = utf8_to_utf16(string(path, pathlen)); 756 } 757 758 { 759 char* xattrnamebuf; 760 ULONG xattrnamelen; 761 762 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_XATTR_NAME, (void**)&xattrnamebuf, &xattrnamelen)) 763 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"xattr_name"); 764 765 xattrname = string(xattrnamebuf, xattrnamelen); 766 } 767 768 if (xattrname.length() > XATTR_USER.length() && xattrname.substr(0, XATTR_USER.length()) == XATTR_USER && xattrname != EA_DOSATTRIB && xattrname != EA_EA) { // deleting stream 769 ULONG att; 770 771 auto streamname = utf8_to_utf16(xattrname); 772 773 streamname = streamname.substr(XATTR_USER.length()); 774 775 att = GetFileAttributesW((subvolpath + pathu).c_str()); 776 if (att == INVALID_FILE_ATTRIBUTES) 777 throw string_error(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 778 779 if (att & FILE_ATTRIBUTE_READONLY) { 780 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att & ~FILE_ATTRIBUTE_READONLY)) 781 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 782 } 783 784 if (!DeleteFileW((subvolpath + pathu + L":" + streamname).c_str())) 785 throw string_error(IDS_RECV_DELETEFILE_FAILED, (pathu + L":" + streamname).c_str(), GetLastError(), format_message(GetLastError()).c_str()); 786 787 if (att & FILE_ATTRIBUTE_READONLY) { 788 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att)) 789 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 790 } 791 } else { 792 IO_STATUS_BLOCK iosb; 793 NTSTATUS Status; 794 ULONG perms = FILE_WRITE_ATTRIBUTES; 795 btrfs_set_xattr* bsxa; 796 797 if (xattrname == EA_NTACL) 798 perms |= WRITE_DAC | WRITE_OWNER; 799 else if (xattrname == EA_EA) 800 perms |= FILE_WRITE_EA; 801 802 win_handle h = CreateFileW((subvolpath + pathu).c_str(), perms, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 803 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS | FILE_OPEN_REPARSE_POINT, nullptr); 804 if (h == INVALID_HANDLE_VALUE) 805 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 806 807 size_t bsxalen = offsetof(btrfs_set_xattr, data[0]) + xattrname.length(); 808 bsxa = (btrfs_set_xattr*)malloc(bsxalen); 809 if (!bsxa) 810 throw string_error(IDS_OUT_OF_MEMORY); 811 812 bsxa->namelen = (uint16_t)(xattrname.length()); 813 bsxa->valuelen = 0; 814 memcpy(bsxa->data, xattrname.c_str(), xattrname.length()); 815 816 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_XATTR, bsxa, (ULONG)bsxalen, nullptr, 0); 817 if (!NT_SUCCESS(Status)) { 818 free(bsxa); 819 throw string_error(IDS_RECV_SETXATTR_FAILED, Status, format_ntstatus(Status).c_str()); 820 } 821 822 free(bsxa); 823 } 824 } 825 826 void BtrfsRecv::cmd_write(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 827 uint64_t* offset; 828 uint8_t* writedata; 829 ULONG offsetlen, datalen; 830 wstring pathu; 831 HANDLE h; 832 LARGE_INTEGER offli; 833 NTSTATUS Status; 834 IO_STATUS_BLOCK iosb; 835 836 { 837 char* path; 838 ULONG pathlen; 839 840 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) 841 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 842 843 pathu = utf8_to_utf16(string(path, pathlen)); 844 } 845 846 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_OFFSET, (void**)&offset, &offsetlen)) 847 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"offset"); 848 849 if (offsetlen < sizeof(uint64_t)) 850 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"offset", offsetlen, sizeof(uint64_t)); 851 852 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_DATA, (void**)&writedata, &datalen)) 853 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"data"); 854 855 if (lastwritepath != pathu) { 856 FILE_BASIC_INFO fbi; 857 858 if (lastwriteatt & FILE_ATTRIBUTE_READONLY) { 859 if (!SetFileAttributesW((subvolpath + lastwritepath).c_str(), lastwriteatt)) 860 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 861 } 862 863 CloseHandle(lastwritefile); 864 865 lastwriteatt = GetFileAttributesW((subvolpath + pathu).c_str()); 866 if (lastwriteatt == INVALID_FILE_ATTRIBUTES) 867 throw string_error(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 868 869 if (lastwriteatt & FILE_ATTRIBUTE_READONLY) { 870 if (!SetFileAttributesW((subvolpath + pathu).c_str(), lastwriteatt & ~FILE_ATTRIBUTE_READONLY)) 871 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 872 } 873 874 h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES, 0, nullptr, OPEN_EXISTING, 875 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, nullptr); 876 if (h == INVALID_HANDLE_VALUE) 877 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 878 879 lastwritepath = pathu; 880 lastwritefile = h; 881 882 memset(&fbi, 0, sizeof(FILE_BASIC_INFO)); 883 884 fbi.LastWriteTime.QuadPart = -1; 885 886 Status = NtSetInformationFile(h, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation); 887 if (!NT_SUCCESS(Status)) 888 throw ntstatus_error(Status); 889 } else 890 h = lastwritefile; 891 892 offli.QuadPart = *offset; 893 894 if (SetFilePointer(h, offli.LowPart, &offli.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER) 895 throw string_error(IDS_RECV_SETFILEPOINTER_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 896 897 if (!WriteFile(h, writedata, datalen, nullptr, nullptr)) 898 throw string_error(IDS_RECV_WRITEFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 899 } 900 901 void BtrfsRecv::cmd_clone(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 902 uint64_t *offset, *cloneoffset, *clonetransid, *clonelen; 903 BTRFS_UUID* cloneuuid; 904 ULONG i, offsetlen, cloneoffsetlen, cloneuuidlen, clonetransidlen, clonelenlen; 905 wstring pathu, clonepathu, clonepar; 906 btrfs_find_subvol bfs; 907 NTSTATUS Status; 908 IO_STATUS_BLOCK iosb; 909 WCHAR cloneparw[MAX_PATH]; 910 DUPLICATE_EXTENTS_DATA ded; 911 LARGE_INTEGER filesize; 912 bool found = false; 913 914 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_OFFSET, (void**)&offset, &offsetlen)) 915 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"offset"); 916 917 if (offsetlen < sizeof(uint64_t)) 918 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"offset", offsetlen, sizeof(uint64_t)); 919 920 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_LENGTH, (void**)&clonelen, &clonelenlen)) 921 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"clone_len"); 922 923 if (clonelenlen < sizeof(uint64_t)) 924 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"clone_len", clonelenlen, sizeof(uint64_t)); 925 926 { 927 char* path; 928 ULONG pathlen; 929 930 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) 931 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 932 933 pathu = utf8_to_utf16(string(path, pathlen)); 934 } 935 936 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_UUID, (void**)&cloneuuid, &cloneuuidlen)) 937 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"clone_uuid"); 938 939 if (cloneuuidlen < sizeof(BTRFS_UUID)) 940 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"clone_uuid", cloneuuidlen, sizeof(BTRFS_UUID)); 941 942 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_CTRANSID, (void**)&clonetransid, &clonetransidlen)) 943 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"clone_ctransid"); 944 945 if (clonetransidlen < sizeof(uint64_t)) 946 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"clone_ctransid", clonetransidlen, sizeof(uint64_t)); 947 948 { 949 char* clonepath; 950 ULONG clonepathlen; 951 952 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_PATH, (void**)&clonepath, &clonepathlen)) 953 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"clone_path"); 954 955 clonepathu = utf8_to_utf16(string(clonepath, clonepathlen)); 956 } 957 958 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_CLONE_OFFSET, (void**)&cloneoffset, &cloneoffsetlen)) 959 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"clone_offset"); 960 961 if (cloneoffsetlen < sizeof(uint64_t)) 962 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"clone_offset", cloneoffsetlen, sizeof(uint64_t)); 963 964 for (i = 0; i < cache.size(); i++) { 965 if (!memcmp(cloneuuid, &cache[i].uuid, sizeof(BTRFS_UUID)) && *clonetransid == cache[i].transid) { 966 clonepar = cache[i].path; 967 found = true; 968 break; 969 } 970 } 971 972 if (!found) { 973 WCHAR volpathw[MAX_PATH]; 974 975 bfs.uuid = *cloneuuid; 976 bfs.ctransid = *clonetransid; 977 978 Status = NtFsControlFile(dir, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_FIND_SUBVOL, &bfs, sizeof(btrfs_find_subvol), 979 cloneparw, sizeof(cloneparw)); 980 if (Status == STATUS_NOT_FOUND) 981 throw string_error(IDS_RECV_CANT_FIND_CLONE_SUBVOL); 982 else if (!NT_SUCCESS(Status)) 983 throw string_error(IDS_RECV_FIND_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str()); 984 985 if (!GetVolumePathNameW(dirpath.c_str(), volpathw, (sizeof(volpathw) / sizeof(WCHAR)) - 1)) 986 throw string_error(IDS_RECV_GETVOLUMEPATHNAME_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 987 988 clonepar = volpathw; 989 if (clonepar.substr(clonepar.length() - 1) == L"\\") 990 clonepar = clonepar.substr(0, clonepar.length() - 1); 991 992 clonepar += cloneparw; 993 clonepar += L"\\"; 994 995 add_cache_entry(cloneuuid, *clonetransid, clonepar); 996 } 997 998 { 999 win_handle src = CreateFileW((clonepar + clonepathu).c_str(), FILE_READ_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1000 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT | FILE_FLAG_POSIX_SEMANTICS, nullptr); 1001 if (src == INVALID_HANDLE_VALUE) 1002 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, (clonepar + clonepathu).c_str(), GetLastError(), format_message(GetLastError()).c_str()); 1003 1004 win_handle dest = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1005 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT | FILE_FLAG_POSIX_SEMANTICS, nullptr); 1006 if (dest == INVALID_HANDLE_VALUE) 1007 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 1008 1009 if (!GetFileSizeEx(dest, &filesize)) 1010 throw string_error(IDS_RECV_GETFILESIZEEX_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1011 1012 if ((uint64_t)filesize.QuadPart < *offset + *clonelen) { 1013 LARGE_INTEGER sizeli; 1014 1015 sizeli.QuadPart = *offset + *clonelen; 1016 1017 if (SetFilePointer(dest, sizeli.LowPart, &sizeli.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER) 1018 throw string_error(IDS_RECV_SETFILEPOINTER_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1019 1020 if (!SetEndOfFile(dest)) 1021 throw string_error(IDS_RECV_SETENDOFFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1022 } 1023 1024 ded.FileHandle = src; 1025 ded.SourceFileOffset.QuadPart = *cloneoffset; 1026 ded.TargetFileOffset.QuadPart = *offset; 1027 ded.ByteCount.QuadPart = *clonelen; 1028 1029 Status = NtFsControlFile(dest, nullptr, nullptr, nullptr, &iosb, FSCTL_DUPLICATE_EXTENTS_TO_FILE, &ded, sizeof(DUPLICATE_EXTENTS_DATA), 1030 nullptr, 0); 1031 if (!NT_SUCCESS(Status)) 1032 throw string_error(IDS_RECV_DUPLICATE_EXTENTS_FAILED, Status, format_ntstatus(Status).c_str()); 1033 } 1034 } 1035 1036 void BtrfsRecv::cmd_truncate(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 1037 uint64_t* size; 1038 ULONG sizelen; 1039 wstring pathu; 1040 LARGE_INTEGER sizeli; 1041 DWORD att; 1042 1043 { 1044 char* path; 1045 ULONG pathlen; 1046 1047 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) 1048 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 1049 1050 pathu = utf8_to_utf16(string(path, pathlen)); 1051 } 1052 1053 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_SIZE, (void**)&size, &sizelen)) 1054 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"size"); 1055 1056 if (sizelen < sizeof(uint64_t)) 1057 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"size", sizelen, sizeof(uint64_t)); 1058 1059 att = GetFileAttributesW((subvolpath + pathu).c_str()); 1060 if (att == INVALID_FILE_ATTRIBUTES) 1061 throw string_error(IDS_RECV_GETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1062 1063 if (att & FILE_ATTRIBUTE_READONLY) { 1064 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att & ~FILE_ATTRIBUTE_READONLY)) 1065 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1066 } 1067 1068 { 1069 win_handle h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_DATA, 0, nullptr, OPEN_EXISTING, 1070 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, nullptr); 1071 1072 if (h == INVALID_HANDLE_VALUE) 1073 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 1074 1075 sizeli.QuadPart = *size; 1076 1077 if (SetFilePointer(h, sizeli.LowPart, &sizeli.HighPart, FILE_BEGIN) == INVALID_SET_FILE_POINTER) 1078 throw string_error(IDS_RECV_SETFILEPOINTER_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1079 1080 if (!SetEndOfFile(h)) 1081 throw string_error(IDS_RECV_SETENDOFFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1082 } 1083 1084 if (att & FILE_ATTRIBUTE_READONLY) { 1085 if (!SetFileAttributesW((subvolpath + pathu).c_str(), att)) 1086 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1087 } 1088 } 1089 1090 void BtrfsRecv::cmd_chmod(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 1091 win_handle h; 1092 uint32_t* mode; 1093 ULONG modelen; 1094 wstring pathu; 1095 btrfs_set_inode_info bsii; 1096 NTSTATUS Status; 1097 IO_STATUS_BLOCK iosb; 1098 1099 { 1100 char* path; 1101 ULONG pathlen; 1102 1103 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) 1104 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 1105 1106 pathu = utf8_to_utf16(string(path, pathlen)); 1107 } 1108 1109 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_MODE, (void**)&mode, &modelen)) 1110 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"mode"); 1111 1112 if (modelen < sizeof(uint32_t)) 1113 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"mode", modelen, sizeof(uint32_t)); 1114 1115 h = CreateFileW((subvolpath + pathu).c_str(), WRITE_DAC, 0, nullptr, OPEN_EXISTING, 1116 FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT | FILE_FLAG_POSIX_SEMANTICS, nullptr); 1117 if (h == INVALID_HANDLE_VALUE) 1118 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 1119 1120 memset(&bsii, 0, sizeof(btrfs_set_inode_info)); 1121 1122 bsii.mode_changed = true; 1123 bsii.st_mode = *mode; 1124 1125 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), nullptr, 0); 1126 if (!NT_SUCCESS(Status)) 1127 throw string_error(IDS_RECV_SETINODEINFO_FAILED, Status, format_ntstatus(Status).c_str()); 1128 } 1129 1130 void BtrfsRecv::cmd_chown(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 1131 win_handle h; 1132 uint32_t *uid, *gid; 1133 ULONG uidlen, gidlen; 1134 wstring pathu; 1135 btrfs_set_inode_info bsii; 1136 1137 { 1138 char* path; 1139 ULONG pathlen; 1140 1141 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) 1142 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 1143 1144 pathu = utf8_to_utf16(string(path, pathlen)); 1145 } 1146 1147 h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_ATTRIBUTES | WRITE_OWNER | WRITE_DAC, 0, nullptr, OPEN_EXISTING, 1148 FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT | FILE_FLAG_POSIX_SEMANTICS, nullptr); 1149 if (h == INVALID_HANDLE_VALUE) 1150 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 1151 1152 memset(&bsii, 0, sizeof(btrfs_set_inode_info)); 1153 1154 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_UID, (void**)&uid, &uidlen)) { 1155 if (uidlen < sizeof(uint32_t)) 1156 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"uid", uidlen, sizeof(uint32_t)); 1157 1158 bsii.uid_changed = true; 1159 bsii.st_uid = *uid; 1160 } 1161 1162 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_GID, (void**)&gid, &gidlen)) { 1163 if (gidlen < sizeof(uint32_t)) 1164 throw string_error(IDS_RECV_SHORT_PARAM, funcname, L"gid", gidlen, sizeof(uint32_t)); 1165 1166 bsii.gid_changed = true; 1167 bsii.st_gid = *gid; 1168 } 1169 1170 if (bsii.uid_changed || bsii.gid_changed) { 1171 NTSTATUS Status; 1172 IO_STATUS_BLOCK iosb; 1173 1174 Status = NtFsControlFile(h, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_SET_INODE_INFO, &bsii, sizeof(btrfs_set_inode_info), nullptr, 0); 1175 if (!NT_SUCCESS(Status)) 1176 throw string_error(IDS_RECV_SETINODEINFO_FAILED, Status, format_ntstatus(Status).c_str()); 1177 } 1178 } 1179 1180 static __inline uint64_t unix_time_to_win(BTRFS_TIME* t) { 1181 return (t->seconds * 10000000) + (t->nanoseconds / 100) + 116444736000000000; 1182 } 1183 1184 void BtrfsRecv::cmd_utimes(HWND hwnd, btrfs_send_command* cmd, uint8_t* data) { 1185 wstring pathu; 1186 win_handle h; 1187 FILE_BASIC_INFO fbi; 1188 BTRFS_TIME* time; 1189 ULONG timelen; 1190 IO_STATUS_BLOCK iosb; 1191 NTSTATUS Status; 1192 1193 { 1194 char* path; 1195 ULONG pathlen; 1196 1197 if (!find_tlv(data, cmd->length, BTRFS_SEND_TLV_PATH, (void**)&path, &pathlen)) 1198 throw string_error(IDS_RECV_MISSING_PARAM, funcname, L"path"); 1199 1200 pathu = utf8_to_utf16(string(path, pathlen)); 1201 } 1202 1203 h = CreateFileW((subvolpath + pathu).c_str(), FILE_WRITE_ATTRIBUTES, 0, nullptr, OPEN_EXISTING, 1204 FILE_FLAG_BACKUP_SEMANTICS | FILE_OPEN_REPARSE_POINT | FILE_FLAG_POSIX_SEMANTICS, nullptr); 1205 if (h == INVALID_HANDLE_VALUE) 1206 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, pathu.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 1207 1208 memset(&fbi, 0, sizeof(FILE_BASIC_INFO)); 1209 1210 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_OTIME, (void**)&time, &timelen) && timelen >= sizeof(BTRFS_TIME)) 1211 fbi.CreationTime.QuadPart = unix_time_to_win(time); 1212 1213 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_ATIME, (void**)&time, &timelen) && timelen >= sizeof(BTRFS_TIME)) 1214 fbi.LastAccessTime.QuadPart = unix_time_to_win(time); 1215 1216 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_MTIME, (void**)&time, &timelen) && timelen >= sizeof(BTRFS_TIME)) 1217 fbi.LastWriteTime.QuadPart = unix_time_to_win(time); 1218 1219 if (find_tlv(data, cmd->length, BTRFS_SEND_TLV_CTIME, (void**)&time, &timelen) && timelen >= sizeof(BTRFS_TIME)) 1220 fbi.ChangeTime.QuadPart = unix_time_to_win(time); 1221 1222 Status = NtSetInformationFile(h, &iosb, &fbi, sizeof(FILE_BASIC_INFO), FileBasicInformation); 1223 if (!NT_SUCCESS(Status)) 1224 throw ntstatus_error(Status); 1225 } 1226 1227 static void delete_directory(const wstring& dir) { 1228 WIN32_FIND_DATAW fff; 1229 1230 fff_handle h = FindFirstFileW((dir + L"*").c_str(), &fff); 1231 1232 if (h == INVALID_HANDLE_VALUE) 1233 return; 1234 1235 do { 1236 wstring file; 1237 1238 file = fff.cFileName; 1239 1240 if (file != L"." && file != L"..") { 1241 if (fff.dwFileAttributes & FILE_ATTRIBUTE_READONLY) 1242 SetFileAttributesW((dir + file).c_str(), fff.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY); 1243 1244 if (fff.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 1245 if (!(fff.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) 1246 delete_directory(dir + file + L"\\"); 1247 else 1248 RemoveDirectoryW((dir + file).c_str()); 1249 } else 1250 DeleteFileW((dir + file).c_str()); 1251 } 1252 } while (FindNextFileW(h, &fff)); 1253 1254 RemoveDirectoryW(dir.c_str()); 1255 } 1256 1257 static bool check_csum(btrfs_send_command* cmd, uint8_t* data) { 1258 uint32_t crc32 = cmd->csum, calc; 1259 1260 cmd->csum = 0; 1261 1262 calc = calc_crc32c(0, (uint8_t*)cmd, sizeof(btrfs_send_command)); 1263 1264 if (cmd->length > 0) 1265 calc = calc_crc32c(calc, data, cmd->length); 1266 1267 return calc == crc32 ? true : false; 1268 } 1269 1270 void BtrfsRecv::do_recv(const win_handle& f, uint64_t* pos, uint64_t size, const win_handle& parent) { 1271 try { 1272 btrfs_send_header header; 1273 bool ended = false; 1274 1275 if (!ReadFile(f, &header, sizeof(btrfs_send_header), nullptr, nullptr)) 1276 throw string_error(IDS_RECV_READFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1277 1278 *pos += sizeof(btrfs_send_header); 1279 1280 if (memcmp(header.magic, BTRFS_SEND_MAGIC, sizeof(header.magic))) 1281 throw string_error(IDS_RECV_NOT_A_SEND_STREAM); 1282 1283 if (header.version > 1) 1284 throw string_error(IDS_RECV_UNSUPPORTED_VERSION, header.version); 1285 1286 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETRANGE32, 0, (LPARAM)65536); 1287 1288 lastwritefile = INVALID_HANDLE_VALUE; 1289 lastwritepath = L""; 1290 lastwriteatt = 0; 1291 1292 while (true) { 1293 btrfs_send_command cmd; 1294 uint8_t* data = nullptr; 1295 ULONG progress; 1296 1297 if (cancelling) 1298 break; 1299 1300 progress = (ULONG)((float)*pos * 65536.0f / (float)size); 1301 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETPOS, progress, 0); 1302 1303 if (!ReadFile(f, &cmd, sizeof(btrfs_send_command), nullptr, nullptr)) { 1304 if (GetLastError() != ERROR_HANDLE_EOF) 1305 throw string_error(IDS_RECV_READFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1306 1307 break; 1308 } 1309 1310 *pos += sizeof(btrfs_send_command); 1311 1312 if (cmd.length > 0) { 1313 if (*pos + cmd.length > size) 1314 throw string_error(IDS_RECV_FILE_TRUNCATED); 1315 1316 data = (uint8_t*)malloc(cmd.length); 1317 if (!data) 1318 throw string_error(IDS_OUT_OF_MEMORY); 1319 } 1320 1321 try { 1322 if (data) { 1323 if (!ReadFile(f, data, cmd.length, nullptr, nullptr)) 1324 throw string_error(IDS_RECV_READFILE_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1325 1326 *pos += cmd.length; 1327 } 1328 1329 if (!check_csum(&cmd, data)) 1330 throw string_error(IDS_RECV_CSUM_ERROR); 1331 1332 if (cmd.cmd == BTRFS_SEND_CMD_END) { 1333 ended = true; 1334 break; 1335 } 1336 1337 if (lastwritefile != INVALID_HANDLE_VALUE && cmd.cmd != BTRFS_SEND_CMD_WRITE) { 1338 if (lastwriteatt & FILE_ATTRIBUTE_READONLY) { 1339 if (!SetFileAttributesW((subvolpath + lastwritepath).c_str(), lastwriteatt)) 1340 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1341 } 1342 1343 CloseHandle(lastwritefile); 1344 1345 lastwritefile = INVALID_HANDLE_VALUE; 1346 lastwritepath = L""; 1347 lastwriteatt = 0; 1348 } 1349 1350 switch (cmd.cmd) { 1351 case BTRFS_SEND_CMD_SUBVOL: 1352 cmd_subvol(hwnd, &cmd, data, parent); 1353 break; 1354 1355 case BTRFS_SEND_CMD_SNAPSHOT: 1356 cmd_snapshot(hwnd, &cmd, data, parent); 1357 break; 1358 1359 case BTRFS_SEND_CMD_MKFILE: 1360 case BTRFS_SEND_CMD_MKDIR: 1361 case BTRFS_SEND_CMD_MKNOD: 1362 case BTRFS_SEND_CMD_MKFIFO: 1363 case BTRFS_SEND_CMD_MKSOCK: 1364 case BTRFS_SEND_CMD_SYMLINK: 1365 cmd_mkfile(hwnd, &cmd, data); 1366 break; 1367 1368 case BTRFS_SEND_CMD_RENAME: 1369 cmd_rename(hwnd, &cmd, data); 1370 break; 1371 1372 case BTRFS_SEND_CMD_LINK: 1373 cmd_link(hwnd, &cmd, data); 1374 break; 1375 1376 case BTRFS_SEND_CMD_UNLINK: 1377 cmd_unlink(hwnd, &cmd, data); 1378 break; 1379 1380 case BTRFS_SEND_CMD_RMDIR: 1381 cmd_rmdir(hwnd, &cmd, data); 1382 break; 1383 1384 case BTRFS_SEND_CMD_SET_XATTR: 1385 cmd_setxattr(hwnd, &cmd, data); 1386 break; 1387 1388 case BTRFS_SEND_CMD_REMOVE_XATTR: 1389 cmd_removexattr(hwnd, &cmd, data); 1390 break; 1391 1392 case BTRFS_SEND_CMD_WRITE: 1393 cmd_write(hwnd, &cmd, data); 1394 break; 1395 1396 case BTRFS_SEND_CMD_CLONE: 1397 cmd_clone(hwnd, &cmd, data); 1398 break; 1399 1400 case BTRFS_SEND_CMD_TRUNCATE: 1401 cmd_truncate(hwnd, &cmd, data); 1402 break; 1403 1404 case BTRFS_SEND_CMD_CHMOD: 1405 cmd_chmod(hwnd, &cmd, data); 1406 break; 1407 1408 case BTRFS_SEND_CMD_CHOWN: 1409 cmd_chown(hwnd, &cmd, data); 1410 break; 1411 1412 case BTRFS_SEND_CMD_UTIMES: 1413 cmd_utimes(hwnd, &cmd, data); 1414 break; 1415 1416 case BTRFS_SEND_CMD_UPDATE_EXTENT: 1417 // does nothing 1418 break; 1419 1420 default: 1421 throw string_error(IDS_RECV_UNKNOWN_COMMAND, cmd.cmd); 1422 } 1423 } catch (...) { 1424 if (data) free(data); 1425 throw; 1426 } 1427 1428 if (data) free(data); 1429 } 1430 1431 if (lastwritefile != INVALID_HANDLE_VALUE) { 1432 if (lastwriteatt & FILE_ATTRIBUTE_READONLY) { 1433 if (!SetFileAttributesW((subvolpath + lastwritepath).c_str(), lastwriteatt)) 1434 throw string_error(IDS_RECV_SETFILEATTRIBUTES_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1435 } 1436 1437 CloseHandle(lastwritefile); 1438 } 1439 1440 if (!ended && !cancelling) 1441 throw string_error(IDS_RECV_FILE_TRUNCATED); 1442 1443 if (!cancelling) { 1444 NTSTATUS Status; 1445 IO_STATUS_BLOCK iosb; 1446 btrfs_received_subvol brs; 1447 1448 brs.generation = stransid; 1449 brs.uuid = subvol_uuid; 1450 1451 Status = NtFsControlFile(dir, nullptr, nullptr, nullptr, &iosb, FSCTL_BTRFS_RECEIVED_SUBVOL, &brs, sizeof(btrfs_received_subvol), 1452 nullptr, 0); 1453 if (!NT_SUCCESS(Status)) 1454 throw string_error(IDS_RECV_RECEIVED_SUBVOL_FAILED, Status, format_ntstatus(Status).c_str()); 1455 } 1456 1457 CloseHandle(dir); 1458 1459 if (master != INVALID_HANDLE_VALUE) 1460 CloseHandle(master); 1461 } catch (...) { 1462 if (subvolpath != L"") { 1463 ULONG attrib; 1464 1465 attrib = GetFileAttributesW(subvolpath.c_str()); 1466 attrib &= ~FILE_ATTRIBUTE_READONLY; 1467 1468 if (SetFileAttributesW(subvolpath.c_str(), attrib)) 1469 delete_directory(subvolpath); 1470 } 1471 1472 throw; 1473 } 1474 } 1475 1476 DWORD BtrfsRecv::recv_thread() { 1477 LARGE_INTEGER size; 1478 uint64_t pos = 0; 1479 bool b = true; 1480 1481 running = true; 1482 1483 try { 1484 win_handle f = CreateFileW(streamfile.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr); 1485 if (f == INVALID_HANDLE_VALUE) 1486 throw string_error(IDS_RECV_CANT_OPEN_FILE, funcname, streamfile.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 1487 1488 if (!GetFileSizeEx(f, &size)) 1489 throw string_error(IDS_RECV_GETFILESIZEEX_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1490 1491 { 1492 win_handle parent = CreateFileW(dirpath.c_str(), FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 1493 nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_POSIX_SEMANTICS, nullptr); 1494 if (parent == INVALID_HANDLE_VALUE) 1495 throw string_error(IDS_RECV_CANT_OPEN_PATH, dirpath.c_str(), GetLastError(), format_message(GetLastError()).c_str()); 1496 1497 do { 1498 do_recv(f, &pos, size.QuadPart, parent); 1499 } while (pos < (uint64_t)size.QuadPart); 1500 } 1501 } catch (const exception& e) { 1502 auto msg = utf8_to_utf16(e.what()); 1503 1504 SetDlgItemTextW(hwnd, IDC_RECV_MSG, msg.c_str()); 1505 1506 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETSTATE, PBST_ERROR, 0); 1507 1508 b = false; 1509 } 1510 1511 if (b && hwnd) { 1512 wstring s; 1513 1514 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETPOS, 65536, 0); 1515 1516 if (num_received == 1) { 1517 load_string(module, IDS_RECV_SUCCESS, s); 1518 SetDlgItemTextW(hwnd, IDC_RECV_MSG, s.c_str()); 1519 } else { 1520 wstring t; 1521 1522 load_string(module, IDS_RECV_SUCCESS_PLURAL, s); 1523 1524 wstring_sprintf(t, s, num_received); 1525 1526 SetDlgItemTextW(hwnd, IDC_RECV_MSG, t.c_str()); 1527 } 1528 1529 load_string(module, IDS_RECV_BUTTON_OK, s); 1530 1531 SetDlgItemTextW(hwnd, IDCANCEL, s.c_str()); 1532 } 1533 1534 thread = nullptr; 1535 running = false; 1536 1537 return 0; 1538 } 1539 1540 static DWORD WINAPI global_recv_thread(LPVOID lpParameter) { 1541 BtrfsRecv* br = (BtrfsRecv*)lpParameter; 1542 1543 return br->recv_thread(); 1544 } 1545 1546 INT_PTR CALLBACK BtrfsRecv::RecvProgressDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 1547 switch (uMsg) { 1548 case WM_INITDIALOG: 1549 try { 1550 this->hwnd = hwndDlg; 1551 thread = CreateThread(nullptr, 0, global_recv_thread, this, 0, nullptr); 1552 1553 if (!thread) 1554 throw string_error(IDS_RECV_CREATETHREAD_FAILED, GetLastError(), format_message(GetLastError()).c_str()); 1555 } catch (const exception& e) { 1556 auto msg = utf8_to_utf16(e.what()); 1557 1558 SetDlgItemTextW(hwnd, IDC_RECV_MSG, msg.c_str()); 1559 1560 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETSTATE, PBST_ERROR, 0); 1561 } 1562 break; 1563 1564 case WM_COMMAND: 1565 switch (HIWORD(wParam)) { 1566 case BN_CLICKED: 1567 switch (LOWORD(wParam)) { 1568 case IDOK: 1569 case IDCANCEL: 1570 if (running) { 1571 wstring s; 1572 1573 cancelling = true; 1574 1575 if (!load_string(module, IDS_RECV_CANCELLED, s)) 1576 throw last_error(GetLastError()); 1577 1578 SetDlgItemTextW(hwnd, IDC_RECV_MSG, s.c_str()); 1579 SendMessageW(GetDlgItem(hwnd, IDC_RECV_PROGRESS), PBM_SETPOS, 0, 0); 1580 1581 if (!load_string(module, IDS_RECV_BUTTON_OK, s)) 1582 throw last_error(GetLastError()); 1583 1584 SetDlgItemTextW(hwnd, IDCANCEL, s.c_str()); 1585 } else 1586 EndDialog(hwndDlg, 1); 1587 1588 return true; 1589 } 1590 break; 1591 } 1592 break; 1593 } 1594 1595 return false; 1596 } 1597 1598 static INT_PTR CALLBACK stub_RecvProgressDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { 1599 BtrfsRecv* br; 1600 1601 if (uMsg == WM_INITDIALOG) { 1602 SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam); 1603 br = (BtrfsRecv*)lParam; 1604 } else { 1605 br = (BtrfsRecv*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); 1606 } 1607 1608 if (br) 1609 return br->RecvProgressDlgProc(hwndDlg, uMsg, wParam, lParam); 1610 else 1611 return false; 1612 } 1613 1614 void BtrfsRecv::Open(HWND hwnd, const wstring& file, const wstring& path, bool quiet) { 1615 #ifndef __REACTOS__ 1616 uint32_t cpuInfo[4]; 1617 #endif 1618 1619 streamfile = file; 1620 dirpath = path; 1621 subvolpath = L""; 1622 1623 #ifndef __REACTOS__ 1624 #ifndef _MSC_VER 1625 __get_cpuid(1, &cpuInfo[0], &cpuInfo[1], &cpuInfo[2], &cpuInfo[3]); 1626 have_sse42 = cpuInfo[2] & bit_SSE4_2; 1627 #else 1628 __cpuid((int*)cpuInfo, 1); 1629 have_sse42 = cpuInfo[2] & (1 << 20); 1630 #endif 1631 #endif 1632 1633 if (quiet) 1634 recv_thread(); 1635 else { 1636 if (DialogBoxParamW(module, MAKEINTRESOURCEW(IDD_RECV_PROGRESS), hwnd, stub_RecvProgressDlgProc, (LPARAM)this) <= 0) 1637 throw last_error(GetLastError()); 1638 } 1639 } 1640 1641 #ifdef __REACTOS__ 1642 extern "C" { 1643 #endif 1644 1645 void CALLBACK RecvSubvolGUIW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 1646 try { 1647 OPENFILENAMEW ofn; 1648 WCHAR file[MAX_PATH]; 1649 win_handle token; 1650 TOKEN_PRIVILEGES* tp; 1651 LUID luid; 1652 ULONG tplen; 1653 1654 set_dpi_aware(); 1655 1656 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1657 throw last_error(GetLastError()); 1658 1659 tplen = offsetof(TOKEN_PRIVILEGES, Privileges[0]) + (3 * sizeof(LUID_AND_ATTRIBUTES)); 1660 tp = (TOKEN_PRIVILEGES*)malloc(tplen); 1661 if (!tp) 1662 throw string_error(IDS_OUT_OF_MEMORY); 1663 1664 tp->PrivilegeCount = 3; 1665 1666 if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) { 1667 free(tp); 1668 throw last_error(GetLastError()); 1669 } 1670 1671 tp->Privileges[0].Luid = luid; 1672 tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1673 1674 if (!LookupPrivilegeValueW(nullptr, L"SeSecurityPrivilege", &luid)) { 1675 free(tp); 1676 throw last_error(GetLastError()); 1677 } 1678 1679 tp->Privileges[1].Luid = luid; 1680 tp->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED; 1681 1682 if (!LookupPrivilegeValueW(nullptr, L"SeRestorePrivilege", &luid)) { 1683 free(tp); 1684 throw last_error(GetLastError()); 1685 } 1686 1687 tp->Privileges[2].Luid = luid; 1688 tp->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED; 1689 1690 if (!AdjustTokenPrivileges(token, false, tp, tplen, nullptr, nullptr)) { 1691 free(tp); 1692 throw last_error(GetLastError()); 1693 } 1694 1695 file[0] = 0; 1696 1697 memset(&ofn, 0, sizeof(OPENFILENAMEW)); 1698 ofn.lStructSize = sizeof(OPENFILENAMEW); 1699 ofn.hwndOwner = hwnd; 1700 ofn.hInstance = module; 1701 ofn.lpstrFile = file; 1702 ofn.nMaxFile = sizeof(file) / sizeof(WCHAR); 1703 ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; 1704 1705 if (GetOpenFileNameW(&ofn)) { 1706 BtrfsRecv recv; 1707 1708 recv.Open(hwnd, file, lpszCmdLine, false); 1709 } 1710 1711 free(tp); 1712 } catch (const exception& e) { 1713 error_message(hwnd, e.what()); 1714 } 1715 } 1716 1717 void CALLBACK RecvSubvolW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow) { 1718 try { 1719 vector<wstring> args; 1720 1721 command_line_to_args(lpszCmdLine, args); 1722 1723 if (args.size() >= 2) { 1724 win_handle token; 1725 TOKEN_PRIVILEGES* tp; 1726 ULONG tplen; 1727 LUID luid; 1728 1729 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1730 return; 1731 1732 tplen = offsetof(TOKEN_PRIVILEGES, Privileges[0]) + (3 * sizeof(LUID_AND_ATTRIBUTES)); 1733 tp = (TOKEN_PRIVILEGES*)malloc(tplen); 1734 if (!tp) 1735 return; 1736 1737 tp->PrivilegeCount = 3; 1738 1739 if (!LookupPrivilegeValueW(nullptr, L"SeManageVolumePrivilege", &luid)) { 1740 free(tp); 1741 return; 1742 } 1743 1744 tp->Privileges[0].Luid = luid; 1745 tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1746 1747 if (!LookupPrivilegeValueW(nullptr, L"SeSecurityPrivilege", &luid)) { 1748 free(tp); 1749 return; 1750 } 1751 1752 tp->Privileges[1].Luid = luid; 1753 tp->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED; 1754 1755 if (!LookupPrivilegeValueW(nullptr, L"SeRestorePrivilege", &luid)) { 1756 free(tp); 1757 return; 1758 } 1759 1760 tp->Privileges[2].Luid = luid; 1761 tp->Privileges[2].Attributes = SE_PRIVILEGE_ENABLED; 1762 1763 if (!AdjustTokenPrivileges(token, false, tp, tplen, nullptr, nullptr)) { 1764 free(tp); 1765 return; 1766 } 1767 1768 free(tp); 1769 1770 BtrfsRecv br; 1771 br.Open(nullptr, args[0], args[1], true); 1772 } 1773 } catch (const exception& e) { 1774 cerr << "Error: " << e.what() << endl; 1775 } 1776 } 1777 1778 #ifdef __REACTOS__ 1779 } /* extern "C" */ 1780 #endif 1781