1 /* Copyright (c) Mark Harmstone 2016-17 2 * 3 * This file is part of WinBtrfs. 4 * 5 * WinBtrfs is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU Lesser General Public Licence as published by 7 * the Free Software Foundation, either version 3 of the Licence, or 8 * (at your option) any later version. 9 * 10 * WinBtrfs is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public Licence for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public Licence 16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include <stdlib.h> 19 #include <stddef.h> 20 #include <time.h> 21 #include <ntstatus.h> 22 #define WIN32_NO_STATUS 23 #include <windef.h> 24 #include <winbase.h> 25 #ifndef __REACTOS__ 26 #include <winternl.h> 27 #include <devioctl.h> 28 #include <ntdddisk.h> 29 #else 30 #include <ndk/iofuncs.h> 31 #include <ndk/obfuncs.h> 32 #include <ndk/rtlfuncs.h> 33 #endif 34 #include <ntddscsi.h> 35 #include <ntddstor.h> 36 #include <ata.h> 37 #include <mountmgr.h> 38 #ifdef __REACTOS__ 39 #include <winnls.h> 40 #include "btrfs.h" 41 #include "btrfsioctl.h" 42 #else 43 #include <stringapiset.h> 44 #include "../btrfs.h" 45 #include "../btrfsioctl.h" 46 #endif 47 48 #ifndef __REACTOS__ 49 #define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) 50 #define FSCTL_UNLOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) 51 #define FSCTL_DISMOUNT_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) 52 53 #ifndef _MSC_VER // not in mingw yet 54 #define DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED 0x80000000 55 #endif 56 57 #ifdef __cplusplus 58 extern "C" { 59 #endif 60 NTSYSCALLAPI NTSTATUS NTAPI NtFsControlFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG FsControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength); 61 62 NTSTATUS NTAPI NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, 63 ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); 64 65 NTSTATUS NTAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, 66 ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key); 67 #ifdef __cplusplus 68 } 69 #endif 70 #endif 71 72 // These are undocumented, and what comes from format.exe 73 typedef struct { 74 void* table; 75 void* unk1; 76 WCHAR* string; 77 } DSTRING; 78 79 typedef struct { 80 void* table; 81 } STREAM_MESSAGE; 82 83 #define FORMAT_FLAG_QUICK_FORMAT 0x00000001 84 #define FORMAT_FLAG_UNKNOWN1 0x00000002 85 #define FORMAT_FLAG_DISMOUNT_FIRST 0x00000004 86 #define FORMAT_FLAG_UNKNOWN2 0x00000040 87 #define FORMAT_FLAG_LARGE_RECORDS 0x00000100 88 #define FORMAT_FLAG_INTEGRITY_DISABLE 0x00000100 89 90 typedef struct { 91 uint16_t unk1; 92 uint16_t unk2; 93 uint32_t flags; 94 DSTRING* label; 95 } options; 96 97 #ifndef __REACTOS__ 98 FORCEINLINE VOID InitializeListHead(PLIST_ENTRY ListHead) { 99 ListHead->Flink = ListHead->Blink = ListHead; 100 } 101 102 FORCEINLINE VOID InsertTailList(PLIST_ENTRY ListHead, PLIST_ENTRY Entry) { 103 PLIST_ENTRY Blink; 104 105 Blink = ListHead->Blink; 106 Entry->Flink = ListHead; 107 Entry->Blink = Blink; 108 Blink->Flink = Entry; 109 ListHead->Blink = Entry; 110 } 111 #endif 112 113 #ifdef __REACTOS__ 114 ULONG NTAPI NtGetTickCount(VOID); 115 #endif 116 117 typedef struct { 118 KEY key; 119 uint16_t size; 120 void* data; 121 LIST_ENTRY list_entry; 122 } btrfs_item; 123 124 typedef struct { 125 uint64_t offset; 126 CHUNK_ITEM* chunk_item; 127 uint64_t lastoff; 128 uint64_t used; 129 LIST_ENTRY list_entry; 130 } btrfs_chunk; 131 132 typedef struct { 133 uint64_t id; 134 tree_header header; 135 btrfs_chunk* c; 136 LIST_ENTRY items; 137 LIST_ENTRY list_entry; 138 } btrfs_root; 139 140 typedef struct { 141 DEV_ITEM dev_item; 142 uint64_t last_alloc; 143 } btrfs_dev; 144 145 #define keycmp(key1, key2)\ 146 ((key1.obj_id < key2.obj_id) ? -1 :\ 147 ((key1.obj_id > key2.obj_id) ? 1 :\ 148 ((key1.obj_type < key2.obj_type) ? -1 :\ 149 ((key1.obj_type > key2.obj_type) ? 1 :\ 150 ((key1.offset < key2.offset) ? -1 :\ 151 ((key1.offset > key2.offset) ? 1 :\ 152 0)))))) 153 154 HMODULE module; 155 ULONG def_sector_size = 0, def_node_size = 0; 156 uint64_t def_incompat_flags = BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA; 157 158 // the following definitions come from fmifs.h in ReactOS 159 160 typedef struct { 161 ULONG Lines; 162 PCHAR Output; 163 } TEXTOUTPUT, *PTEXTOUTPUT; 164 165 typedef enum { 166 FMIFS_UNKNOWN0, 167 FMIFS_UNKNOWN1, 168 FMIFS_UNKNOWN2, 169 FMIFS_UNKNOWN3, 170 FMIFS_UNKNOWN4, 171 FMIFS_UNKNOWN5, 172 FMIFS_UNKNOWN6, 173 FMIFS_UNKNOWN7, 174 FMIFS_FLOPPY, 175 FMIFS_UNKNOWN9, 176 FMIFS_UNKNOWN10, 177 FMIFS_REMOVABLE, 178 FMIFS_HARDDISK, 179 FMIFS_UNKNOWN13, 180 FMIFS_UNKNOWN14, 181 FMIFS_UNKNOWN15, 182 FMIFS_UNKNOWN16, 183 FMIFS_UNKNOWN17, 184 FMIFS_UNKNOWN18, 185 FMIFS_UNKNOWN19, 186 FMIFS_UNKNOWN20, 187 FMIFS_UNKNOWN21, 188 FMIFS_UNKNOWN22, 189 FMIFS_UNKNOWN23, 190 } FMIFS_MEDIA_FLAG; 191 192 typedef enum { 193 PROGRESS, 194 DONEWITHSTRUCTURE, 195 UNKNOWN2, 196 UNKNOWN3, 197 UNKNOWN4, 198 UNKNOWN5, 199 INSUFFICIENTRIGHTS, 200 FSNOTSUPPORTED, 201 VOLUMEINUSE, 202 UNKNOWN9, 203 UNKNOWNA, 204 DONE, 205 UNKNOWNC, 206 UNKNOWND, 207 OUTPUT, 208 STRUCTUREPROGRESS, 209 CLUSTERSIZETOOSMALL, 210 } CALLBACKCOMMAND; 211 212 typedef BOOLEAN (NTAPI* PFMIFSCALLBACK)(CALLBACKCOMMAND Command, ULONG SubAction, PVOID ActionInfo); 213 214 static const uint32_t crctable[] = { 215 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, 216 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 217 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, 218 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, 219 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 220 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, 221 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, 222 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 223 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, 224 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, 225 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 226 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, 227 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, 228 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 229 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, 230 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, 231 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 232 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, 233 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, 234 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 235 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, 236 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, 237 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 238 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, 239 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, 240 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 241 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, 242 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, 243 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 244 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, 245 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, 246 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351, 247 }; 248 249 static uint32_t calc_crc32c(uint32_t seed, uint8_t* msg, ULONG msglen) { 250 uint32_t rem; 251 ULONG i; 252 253 rem = seed; 254 255 for (i = 0; i < msglen; i++) { 256 rem = crctable[(rem ^ msg[i]) & 0xff] ^ (rem >> 8); 257 } 258 259 return rem; 260 } 261 262 #ifndef __REACTOS__ 263 NTSTATUS WINAPI ChkdskEx(PUNICODE_STRING DriveRoot, BOOLEAN FixErrors, BOOLEAN Verbose, BOOLEAN CheckOnlyIfDirty, 264 #else 265 NTSTATUS NTAPI BtrfsChkdskEx(PUNICODE_STRING DriveRoot, BOOLEAN FixErrors, BOOLEAN Verbose, BOOLEAN CheckOnlyIfDirty, 266 #endif 267 BOOLEAN ScanDrive, PFMIFSCALLBACK Callback) { 268 // STUB 269 270 if (Callback) { 271 TEXTOUTPUT TextOut; 272 273 TextOut.Lines = 1; 274 TextOut.Output = "stub, not implemented"; 275 276 Callback(OUTPUT, 0, &TextOut); 277 } 278 279 return STATUS_SUCCESS; 280 } 281 282 static btrfs_root* add_root(LIST_ENTRY* roots, uint64_t id) { 283 btrfs_root* root; 284 285 #ifdef __REACTOS__ 286 root = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(btrfs_root)); 287 #else 288 root = malloc(sizeof(btrfs_root)); 289 #endif 290 291 root->id = id; 292 #ifndef __REACTOS__ 293 RtlZeroMemory(&root->header, sizeof(tree_header)); 294 #endif 295 InitializeListHead(&root->items); 296 InsertTailList(roots, &root->list_entry); 297 298 return root; 299 } 300 301 static void free_roots(LIST_ENTRY* roots) { 302 LIST_ENTRY* le; 303 304 le = roots->Flink; 305 while (le != roots) { 306 LIST_ENTRY *le2 = le->Flink, *le3; 307 btrfs_root* r = CONTAINING_RECORD(le, btrfs_root, list_entry); 308 309 le3 = r->items.Flink; 310 while (le3 != &r->items) { 311 LIST_ENTRY* le4 = le3->Flink; 312 btrfs_item* item = CONTAINING_RECORD(le3, btrfs_item, list_entry); 313 314 if (item->data) 315 #ifdef __REACTOS__ 316 RtlFreeHeap(RtlGetProcessHeap(), 0, item->data); 317 318 RtlFreeHeap(RtlGetProcessHeap(), 0, item); 319 #else 320 free(item->data); 321 322 free(item); 323 #endif 324 325 le3 = le4; 326 } 327 328 #ifdef __REACTOS__ 329 RtlFreeHeap(RtlGetProcessHeap(), 0, r); 330 #else 331 free(r); 332 #endif 333 334 le = le2; 335 } 336 } 337 338 static void free_chunks(LIST_ENTRY* chunks) { 339 LIST_ENTRY* le; 340 341 le = chunks->Flink; 342 while (le != chunks) { 343 LIST_ENTRY *le2 = le->Flink; 344 btrfs_chunk* c = CONTAINING_RECORD(le, btrfs_chunk, list_entry); 345 346 #ifndef __REACTOS__ 347 free(c->chunk_item); 348 free(c); 349 #else 350 RtlFreeHeap(RtlGetProcessHeap(), 0, c->chunk_item); 351 RtlFreeHeap(RtlGetProcessHeap(), 0, c); 352 #endif 353 354 le = le2; 355 } 356 } 357 358 static void add_item(btrfs_root* r, uint64_t obj_id, uint8_t obj_type, uint64_t offset, void* data, uint16_t size) { 359 LIST_ENTRY* le; 360 btrfs_item* item; 361 362 #ifndef __REACTOS__ 363 item = malloc(sizeof(btrfs_item)); 364 #else 365 item = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(btrfs_item)); 366 #endif 367 368 item->key.obj_id = obj_id; 369 item->key.obj_type = obj_type; 370 item->key.offset = offset; 371 item->size = size; 372 373 if (size == 0) 374 item->data = NULL; 375 else { 376 #ifndef __REACTOS__ 377 item->data = malloc(size); 378 #else 379 item->data = RtlAllocateHeap(RtlGetProcessHeap(), 0, size); 380 #endif 381 memcpy(item->data, data, size); 382 } 383 384 le = r->items.Flink; 385 while (le != &r->items) { 386 btrfs_item* i2 = CONTAINING_RECORD(le, btrfs_item, list_entry); 387 388 if (keycmp(item->key, i2->key) != 1) { 389 InsertTailList(le, &item->list_entry); 390 return; 391 } 392 393 le = le->Flink; 394 } 395 396 InsertTailList(&r->items, &item->list_entry); 397 } 398 399 static uint64_t find_chunk_offset(uint64_t size, uint64_t offset, btrfs_dev* dev, btrfs_root* dev_root, BTRFS_UUID* chunkuuid) { 400 uint64_t off; 401 DEV_EXTENT de; 402 403 off = dev->last_alloc; 404 dev->last_alloc += size; 405 406 dev->dev_item.bytes_used += size; 407 408 de.chunktree = BTRFS_ROOT_CHUNK; 409 de.objid = 0x100; 410 de.address = offset; 411 de.length = size; 412 de.chunktree_uuid = *chunkuuid; 413 414 add_item(dev_root, dev->dev_item.dev_id, TYPE_DEV_EXTENT, off, &de, sizeof(DEV_EXTENT)); 415 416 return off; 417 } 418 419 static btrfs_chunk* add_chunk(LIST_ENTRY* chunks, uint64_t flags, btrfs_root* chunk_root, btrfs_dev* dev, btrfs_root* dev_root, BTRFS_UUID* chunkuuid, uint32_t sector_size) { 420 uint64_t off, size; 421 uint16_t stripes, i; 422 btrfs_chunk* c; 423 LIST_ENTRY* le; 424 CHUNK_ITEM_STRIPE* cis; 425 426 off = 0xc00000; 427 le = chunks->Flink; 428 while (le != chunks) { 429 c = CONTAINING_RECORD(le, btrfs_chunk, list_entry); 430 431 if (c->offset + c->chunk_item->size > off) 432 off = c->offset + c->chunk_item->size; 433 434 le = le->Flink; 435 } 436 437 if (flags & BLOCK_FLAG_METADATA) { 438 if (dev->dev_item.num_bytes > 0xC80000000) // 50 GB 439 size = 0x40000000; // 1 GB 440 else 441 size = 0x10000000; // 256 MB 442 } else if (flags & BLOCK_FLAG_SYSTEM) 443 size = 0x800000; 444 445 size = min(size, dev->dev_item.num_bytes / 10); // cap at 10% 446 size &= ~(sector_size - 1); 447 448 stripes = flags & BLOCK_FLAG_DUPLICATE ? 2 : 1; 449 450 if (dev->dev_item.num_bytes - dev->dev_item.bytes_used < stripes * size) // not enough space 451 return NULL; 452 453 #ifndef __REACTOS__ 454 c = malloc(sizeof(btrfs_chunk)); 455 #else 456 c = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(btrfs_chunk)); 457 #endif 458 c->offset = off; 459 c->lastoff = off; 460 c->used = 0; 461 462 #ifndef __REACTOS__ 463 c->chunk_item = malloc(sizeof(CHUNK_ITEM) + (stripes * sizeof(CHUNK_ITEM_STRIPE))); 464 #else 465 c->chunk_item = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(CHUNK_ITEM) + (stripes * sizeof(CHUNK_ITEM_STRIPE))); 466 #endif 467 468 c->chunk_item->size = size; 469 c->chunk_item->root_id = BTRFS_ROOT_EXTENT; 470 c->chunk_item->stripe_length = max(sector_size, 0x10000); 471 c->chunk_item->type = flags; 472 c->chunk_item->opt_io_alignment = max(sector_size, 0x10000); 473 c->chunk_item->opt_io_width = max(sector_size, 0x10000); 474 c->chunk_item->sector_size = sector_size; 475 c->chunk_item->num_stripes = stripes; 476 c->chunk_item->sub_stripes = 0; 477 478 cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1]; 479 480 for (i = 0; i < stripes; i++) { 481 cis[i].dev_id = dev->dev_item.dev_id; 482 cis[i].offset = find_chunk_offset(size, c->offset, dev, dev_root, chunkuuid); 483 cis[i].dev_uuid = dev->dev_item.device_uuid; 484 } 485 486 add_item(chunk_root, 0x100, TYPE_CHUNK_ITEM, c->offset, c->chunk_item, sizeof(CHUNK_ITEM) + (stripes * sizeof(CHUNK_ITEM_STRIPE))); 487 488 InsertTailList(chunks, &c->list_entry); 489 490 return c; 491 } 492 493 static BOOL superblock_collision(btrfs_chunk* c, uint64_t address) { 494 CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1]; 495 uint64_t stripe = (address - c->offset) / c->chunk_item->stripe_length; 496 uint16_t i, j; 497 498 for (i = 0; i < c->chunk_item->num_stripes; i++) { 499 j = 0; 500 while (superblock_addrs[j] != 0) { 501 if (superblock_addrs[j] >= cis[i].offset) { 502 uint64_t stripe2 = (superblock_addrs[j] - cis[i].offset) / c->chunk_item->stripe_length; 503 504 if (stripe2 == stripe) 505 return TRUE; 506 } 507 j++; 508 } 509 } 510 511 return FALSE; 512 } 513 514 static uint64_t get_next_address(btrfs_chunk* c) { 515 uint64_t addr; 516 517 addr = c->lastoff; 518 519 while (superblock_collision(c, addr)) { 520 addr = addr - ((addr - c->offset) % c->chunk_item->stripe_length) + c->chunk_item->stripe_length; 521 522 if (addr >= c->offset + c->chunk_item->size) // chunk has been exhausted 523 return 0; 524 } 525 526 return addr; 527 } 528 529 typedef struct { 530 EXTENT_ITEM ei; 531 uint8_t type; 532 TREE_BLOCK_REF tbr; 533 } EXTENT_ITEM_METADATA; 534 535 typedef struct { 536 EXTENT_ITEM ei; 537 EXTENT_ITEM2 ei2; 538 uint8_t type; 539 TREE_BLOCK_REF tbr; 540 } EXTENT_ITEM_METADATA2; 541 542 static void assign_addresses(LIST_ENTRY* roots, btrfs_chunk* sys_chunk, btrfs_chunk* metadata_chunk, uint32_t node_size, 543 btrfs_root* root_root, btrfs_root* extent_root, BOOL skinny) { 544 LIST_ENTRY* le; 545 546 le = roots->Flink; 547 while (le != roots) { 548 btrfs_root* r = CONTAINING_RECORD(le, btrfs_root, list_entry); 549 btrfs_chunk* c = r->id == BTRFS_ROOT_CHUNK ? sys_chunk : metadata_chunk; 550 551 r->header.address = get_next_address(c); 552 r->c = c; 553 c->lastoff = r->header.address + node_size; 554 c->used += node_size; 555 556 if (skinny) { 557 EXTENT_ITEM_METADATA eim; 558 559 eim.ei.refcount = 1; 560 eim.ei.generation = 1; 561 eim.ei.flags = EXTENT_ITEM_TREE_BLOCK; 562 eim.type = TYPE_TREE_BLOCK_REF; 563 eim.tbr.offset = r->id; 564 565 add_item(extent_root, r->header.address, TYPE_METADATA_ITEM, 0, &eim, sizeof(EXTENT_ITEM_METADATA)); 566 } else { 567 EXTENT_ITEM_METADATA2 eim2; 568 KEY firstitem; 569 570 if (r->items.Flink == &r->items) { 571 firstitem.obj_id = 0; 572 firstitem.obj_type = 0; 573 firstitem.offset = 0; 574 } else { 575 btrfs_item* bi = CONTAINING_RECORD(r->items.Flink, btrfs_item, list_entry); 576 577 firstitem = bi->key; 578 } 579 580 eim2.ei.refcount = 1; 581 eim2.ei.generation = 1; 582 eim2.ei.flags = EXTENT_ITEM_TREE_BLOCK; 583 eim2.ei2.firstitem = firstitem; 584 eim2.ei2.level = 0; 585 eim2.type = TYPE_TREE_BLOCK_REF; 586 eim2.tbr.offset = r->id; 587 588 add_item(extent_root, r->header.address, TYPE_EXTENT_ITEM, node_size, &eim2, sizeof(EXTENT_ITEM_METADATA2)); 589 } 590 591 if (r->id != BTRFS_ROOT_ROOT && r->id != BTRFS_ROOT_CHUNK) { 592 ROOT_ITEM ri; 593 594 memset(&ri, 0, sizeof(ROOT_ITEM)); 595 596 ri.inode.generation = 1; 597 ri.inode.st_size = 3; 598 ri.inode.st_blocks = node_size; 599 ri.inode.st_nlink = 1; 600 ri.inode.st_mode = 040755; 601 ri.generation = 1; 602 ri.objid = r->id == 5 || r->id >= 0x100 ? SUBVOL_ROOT_INODE : 0; 603 ri.block_number = r->header.address; 604 ri.bytes_used = node_size; 605 ri.num_references = 1; 606 ri.generation2 = ri.generation; 607 608 add_item(root_root, r->id, TYPE_ROOT_ITEM, 0, &ri, sizeof(ROOT_ITEM)); 609 } 610 611 le = le->Flink; 612 } 613 } 614 615 static NTSTATUS write_data(HANDLE h, uint64_t address, btrfs_chunk* c, void* data, ULONG size) { 616 NTSTATUS Status; 617 uint16_t i; 618 IO_STATUS_BLOCK iosb; 619 LARGE_INTEGER off; 620 CHUNK_ITEM_STRIPE* cis; 621 622 cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1]; 623 624 for (i = 0; i < c->chunk_item->num_stripes; i++) { 625 off.QuadPart = cis[i].offset + address - c->offset; 626 627 Status = NtWriteFile(h, NULL, NULL, NULL, &iosb, data, size, &off, NULL); 628 if (!NT_SUCCESS(Status)) 629 return Status; 630 } 631 632 return STATUS_SUCCESS; 633 } 634 635 static NTSTATUS write_roots(HANDLE h, LIST_ENTRY* roots, uint32_t node_size, BTRFS_UUID* fsuuid, BTRFS_UUID* chunkuuid) { 636 LIST_ENTRY *le, *le2; 637 NTSTATUS Status; 638 uint8_t* tree; 639 640 #ifndef __REACTOS__ 641 tree = malloc(node_size); 642 #else 643 tree = RtlAllocateHeap(RtlGetProcessHeap(), 0, node_size); 644 #endif 645 646 le = roots->Flink; 647 while (le != roots) { 648 btrfs_root* r = CONTAINING_RECORD(le, btrfs_root, list_entry); 649 uint8_t* dp; 650 leaf_node* ln; 651 uint32_t crc32; 652 653 memset(tree, 0, node_size); 654 655 r->header.num_items = 0; 656 r->header.fs_uuid = *fsuuid; 657 r->header.flags = HEADER_FLAG_MIXED_BACKREF | HEADER_FLAG_WRITTEN; 658 r->header.chunk_tree_uuid = *chunkuuid; 659 r->header.generation = 1; 660 r->header.tree_id = r->id; 661 662 ln = (leaf_node*)(tree + sizeof(tree_header)); 663 664 dp = tree + node_size; 665 666 le2 = r->items.Flink; 667 while (le2 != &r->items) { 668 btrfs_item* item = CONTAINING_RECORD(le2, btrfs_item, list_entry); 669 670 ln->key = item->key; 671 ln->size = item->size; 672 673 if (item->size > 0) { 674 dp -= item->size; 675 memcpy(dp, item->data, item->size); 676 677 ln->offset = dp - tree - sizeof(tree_header); 678 } else 679 ln->offset = 0; 680 681 ln = &ln[1]; 682 683 r->header.num_items++; 684 685 le2 = le2->Flink; 686 } 687 688 memcpy(tree, &r->header, sizeof(tree_header)); 689 690 crc32 = ~calc_crc32c(0xffffffff, (uint8_t*)&((tree_header*)tree)->fs_uuid, node_size - sizeof(((tree_header*)tree)->csum)); 691 memcpy(tree, &crc32, sizeof(uint32_t)); 692 693 Status = write_data(h, r->header.address, r->c, tree, node_size); 694 if (!NT_SUCCESS(Status)) { 695 #ifndef __REACTOS__ 696 free(tree); 697 #else 698 RtlFreeHeap(RtlGetProcessHeap(), 0, tree); 699 #endif 700 return Status; 701 } 702 703 le = le->Flink; 704 } 705 706 #ifndef __REACTOS__ 707 free(tree); 708 #else 709 RtlFreeHeap(RtlGetProcessHeap(), 0, tree); 710 #endif 711 712 return STATUS_SUCCESS; 713 } 714 715 #ifndef __REACTOS__ 716 static void get_uuid(BTRFS_UUID* uuid) { 717 #else 718 static void get_uuid(BTRFS_UUID* uuid, ULONG* seed) { 719 #endif 720 uint8_t i; 721 722 for (i = 0; i < 16; i+=2) { 723 #ifndef __REACTOS__ 724 ULONG r = rand(); 725 #else 726 ULONG r = RtlRandom(seed); 727 #endif 728 729 uuid->uuid[i] = (r & 0xff00) >> 8; 730 uuid->uuid[i+1] = r & 0xff; 731 } 732 } 733 734 #ifndef __REACTOS__ 735 static void init_device(btrfs_dev* dev, uint64_t id, uint64_t size, BTRFS_UUID* fsuuid, uint32_t sector_size) { 736 #else 737 static void init_device(btrfs_dev* dev, uint64_t id, uint64_t size, BTRFS_UUID* fsuuid, uint32_t sector_size, ULONG* seed) { 738 #endif 739 dev->dev_item.dev_id = id; 740 dev->dev_item.num_bytes = size; 741 dev->dev_item.bytes_used = 0; 742 dev->dev_item.optimal_io_align = sector_size; 743 dev->dev_item.optimal_io_width = sector_size; 744 dev->dev_item.minimal_io_size = sector_size; 745 dev->dev_item.type = 0; 746 dev->dev_item.generation = 0; 747 dev->dev_item.start_offset = 0; 748 dev->dev_item.dev_group = 0; 749 dev->dev_item.seek_speed = 0; 750 dev->dev_item.bandwidth = 0; 751 #ifndef __REACTOS__ 752 get_uuid(&dev->dev_item.device_uuid); 753 #else 754 get_uuid(&dev->dev_item.device_uuid, seed); 755 #endif 756 dev->dev_item.fs_uuid = *fsuuid; 757 758 dev->last_alloc = 0x100000; // skip first megabyte 759 } 760 761 static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_root, btrfs_root* root_root, btrfs_root* extent_root, 762 btrfs_chunk* sys_chunk, uint32_t node_size, BTRFS_UUID* fsuuid, uint32_t sector_size, PUNICODE_STRING label, uint64_t incompat_flags) { 763 NTSTATUS Status; 764 IO_STATUS_BLOCK iosb; 765 ULONG sblen; 766 int i; 767 uint32_t crc32; 768 superblock* sb; 769 KEY* key; 770 uint64_t bytes_used; 771 LIST_ENTRY* le; 772 773 sblen = sizeof(*sb); 774 if (sblen & (sector_size - 1)) 775 sblen = (sblen & sector_size) + sector_size; 776 777 bytes_used = 0; 778 779 le = extent_root->items.Flink; 780 while (le != &extent_root->items) { 781 btrfs_item* item = CONTAINING_RECORD(le, btrfs_item, list_entry); 782 783 if (item->key.obj_type == TYPE_EXTENT_ITEM) 784 bytes_used += item->key.offset; 785 else if (item->key.obj_type == TYPE_METADATA_ITEM) 786 bytes_used += node_size; 787 788 le = le->Flink; 789 } 790 791 #ifndef __REACTOS__ 792 sb = malloc(sblen); 793 memset(sb, 0, sblen); 794 #else 795 sb = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sblen); 796 #endif 797 798 sb->uuid = *fsuuid; 799 sb->flags = 1; 800 sb->magic = BTRFS_MAGIC; 801 sb->generation = 1; 802 sb->root_tree_addr = root_root->header.address; 803 sb->chunk_tree_addr = chunk_root->header.address; 804 sb->total_bytes = dev->dev_item.num_bytes; 805 sb->bytes_used = bytes_used; 806 sb->root_dir_objectid = BTRFS_ROOT_TREEDIR; 807 sb->num_devices = 1; 808 sb->sector_size = sector_size; 809 sb->node_size = node_size; 810 sb->leaf_size = node_size; 811 sb->stripe_size = sector_size; 812 sb->n = sizeof(KEY) + sizeof(CHUNK_ITEM) + (sys_chunk->chunk_item->num_stripes * sizeof(CHUNK_ITEM_STRIPE)); 813 sb->chunk_root_generation = 1; 814 sb->incompat_flags = incompat_flags; 815 memcpy(&sb->dev_item, &dev->dev_item, sizeof(DEV_ITEM)); 816 817 if (label->Length > 0) { 818 #ifdef __REACTOS__ 819 ANSI_STRING as; 820 unsigned int i; 821 822 for (i = 0; i < label->Length / sizeof(WCHAR); i++) { 823 #else 824 ULONG utf8len; 825 826 for (unsigned int i = 0; i < label->Length / sizeof(WCHAR); i++) { 827 #endif 828 if (label->Buffer[i] == '/' || label->Buffer[i] == '\\') { 829 #ifndef __REACTOS__ 830 free(sb); 831 #else 832 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 833 #endif 834 return STATUS_INVALID_VOLUME_LABEL; 835 } 836 } 837 838 #ifndef __REACTOS__ 839 utf8len = WideCharToMultiByte(CP_UTF8, 0, label->Buffer, label->Length / sizeof(WCHAR), NULL, 0, NULL, NULL); 840 841 if (utf8len == 0 || utf8len > MAX_LABEL_SIZE) { 842 free(sb); 843 return STATUS_INVALID_VOLUME_LABEL; 844 } 845 846 if (WideCharToMultiByte(CP_UTF8, 0, label->Buffer, label->Length / sizeof(WCHAR), sb->label, utf8len, NULL, NULL) == 0) { 847 free(sb); 848 return STATUS_INVALID_VOLUME_LABEL; 849 } 850 #else 851 as.Buffer = sb->label; 852 as.Length = 0; 853 as.MaximumLength = MAX_LABEL_SIZE; 854 855 if (!NT_SUCCESS(RtlUnicodeStringToAnsiString(&as, label, FALSE))) 856 { 857 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 858 return STATUS_INVALID_VOLUME_LABEL; 859 } 860 #endif 861 } 862 sb->cache_generation = 0xffffffffffffffff; 863 864 key = (KEY*)sb->sys_chunk_array; 865 key->obj_id = 0x100; 866 key->obj_type = TYPE_CHUNK_ITEM; 867 key->offset = sys_chunk->offset; 868 memcpy(&key[1], sys_chunk->chunk_item, sizeof(CHUNK_ITEM) + (sys_chunk->chunk_item->num_stripes * sizeof(CHUNK_ITEM_STRIPE))); 869 870 i = 0; 871 while (superblock_addrs[i] != 0) { 872 LARGE_INTEGER off; 873 874 if (superblock_addrs[i] > dev->dev_item.num_bytes) 875 break; 876 877 sb->sb_phys_addr = superblock_addrs[i]; 878 879 crc32 = ~calc_crc32c(0xffffffff, (uint8_t*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 880 memcpy(&sb->checksum, &crc32, sizeof(uint32_t)); 881 882 off.QuadPart = superblock_addrs[i]; 883 884 Status = NtWriteFile(h, NULL, NULL, NULL, &iosb, sb, sblen, &off, NULL); 885 if (!NT_SUCCESS(Status)) { 886 #ifndef __REACTOS__ 887 free(sb); 888 #else 889 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 890 #endif 891 return Status; 892 } 893 894 i++; 895 } 896 897 #ifndef __REACTOS__ 898 free(sb); 899 #else 900 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 901 #endif 902 903 return STATUS_SUCCESS; 904 } 905 906 static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME* out) { 907 ULONGLONG l = t.QuadPart - 116444736000000000; 908 909 out->seconds = l / 10000000; 910 out->nanoseconds = (l % 10000000) * 100; 911 } 912 913 #ifdef __REACTOS__ 914 VOID 915 WINAPI 916 GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime) 917 { 918 LARGE_INTEGER SystemTime; 919 920 do 921 { 922 SystemTime.HighPart = SharedUserData->SystemTime.High1Time; 923 SystemTime.LowPart = SharedUserData->SystemTime.LowPart; 924 } 925 while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time); 926 927 lpFileTime->dwLowDateTime = SystemTime.LowPart; 928 lpFileTime->dwHighDateTime = SystemTime.HighPart; 929 } 930 #endif 931 932 static void add_inode_ref(btrfs_root* r, uint64_t inode, uint64_t parent, uint64_t index, const char* name) { 933 uint16_t name_len = (uint16_t)strlen(name); 934 #ifndef __REACTOS__ 935 INODE_REF* ir = malloc(offsetof(INODE_REF, name[0]) + name_len); 936 #else 937 INODE_REF* ir = RtlAllocateHeap(RtlGetProcessHeap(), 0, offsetof(INODE_REF, name[0]) + name_len); 938 #endif 939 940 ir->index = 0; 941 ir->n = name_len; 942 memcpy(ir->name, name, name_len); 943 944 add_item(r, inode, TYPE_INODE_REF, parent, ir, (uint16_t)offsetof(INODE_REF, name[0]) + ir->n); 945 946 #ifndef __REACTOS__ 947 free(ir); 948 #else 949 RtlFreeHeap(RtlGetProcessHeap(), 0, ir); 950 #endif 951 } 952 953 static void init_fs_tree(btrfs_root* r, uint32_t node_size) { 954 INODE_ITEM ii; 955 FILETIME filetime; 956 LARGE_INTEGER time; 957 958 memset(&ii, 0, sizeof(INODE_ITEM)); 959 960 ii.generation = 1; 961 ii.st_blocks = node_size; 962 ii.st_nlink = 1; 963 ii.st_mode = 040755; 964 965 GetSystemTimeAsFileTime(&filetime); 966 time.LowPart = filetime.dwLowDateTime; 967 time.HighPart = filetime.dwHighDateTime; 968 969 win_time_to_unix(time, &ii.st_atime); 970 ii.st_ctime = ii.st_mtime = ii.st_atime; 971 972 add_item(r, SUBVOL_ROOT_INODE, TYPE_INODE_ITEM, 0, &ii, sizeof(INODE_ITEM)); 973 974 add_inode_ref(r, SUBVOL_ROOT_INODE, SUBVOL_ROOT_INODE, 0, ".."); 975 } 976 977 static void add_block_group_items(LIST_ENTRY* chunks, btrfs_root* extent_root) { 978 LIST_ENTRY* le; 979 980 le = chunks->Flink; 981 while (le != chunks) { 982 btrfs_chunk* c = CONTAINING_RECORD(le, btrfs_chunk, list_entry); 983 BLOCK_GROUP_ITEM bgi; 984 985 bgi.used = c->used; 986 bgi.chunk_tree = 0x100; 987 bgi.flags = c->chunk_item->type; 988 add_item(extent_root, c->offset, TYPE_BLOCK_GROUP_ITEM, c->chunk_item->size, &bgi, sizeof(BLOCK_GROUP_ITEM)); 989 990 le = le->Flink; 991 } 992 } 993 994 static NTSTATUS clear_first_megabyte(HANDLE h) { 995 NTSTATUS Status; 996 IO_STATUS_BLOCK iosb; 997 LARGE_INTEGER zero; 998 uint8_t* mb; 999 1000 #ifndef __REACTOS__ 1001 mb = malloc(0x100000); 1002 memset(mb, 0, 0x100000); 1003 #else 1004 mb = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x100000); 1005 #endif 1006 1007 zero.QuadPart = 0; 1008 1009 Status = NtWriteFile(h, NULL, NULL, NULL, &iosb, mb, 0x100000, &zero, NULL); 1010 1011 #ifndef __REACTOS__ 1012 free(mb); 1013 #else 1014 RtlFreeHeap(RtlGetProcessHeap(), 0, mb); 1015 #endif 1016 1017 return Status; 1018 } 1019 1020 static BOOL is_ssd(HANDLE h) { 1021 ULONG aptelen; 1022 ATA_PASS_THROUGH_EX* apte; 1023 IO_STATUS_BLOCK iosb; 1024 NTSTATUS Status; 1025 IDENTIFY_DEVICE_DATA* idd; 1026 1027 aptelen = sizeof(ATA_PASS_THROUGH_EX) + 512; 1028 #ifndef __REACTOS__ 1029 apte = malloc(aptelen); 1030 1031 RtlZeroMemory(apte, aptelen); 1032 #else 1033 apte = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, aptelen); 1034 #endif 1035 1036 apte->Length = sizeof(ATA_PASS_THROUGH_EX); 1037 apte->AtaFlags = ATA_FLAGS_DATA_IN; 1038 apte->DataTransferLength = aptelen - sizeof(ATA_PASS_THROUGH_EX); 1039 apte->TimeOutValue = 3; 1040 apte->DataBufferOffset = apte->Length; 1041 apte->CurrentTaskFile[6] = IDE_COMMAND_IDENTIFY; 1042 1043 Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_ATA_PASS_THROUGH, apte, aptelen, apte, aptelen); 1044 1045 if (NT_SUCCESS(Status)) { 1046 idd = (IDENTIFY_DEVICE_DATA*)((uint8_t*)apte + sizeof(ATA_PASS_THROUGH_EX)); 1047 1048 if (idd->NominalMediaRotationRate == 1) { 1049 #ifndef __REACTOS__ 1050 free(apte); 1051 #else 1052 RtlFreeHeap(RtlGetProcessHeap(), 0, apte); 1053 #endif 1054 return TRUE; 1055 } 1056 } 1057 1058 #ifndef __REACTOS__ 1059 free(apte); 1060 #else 1061 RtlFreeHeap(RtlGetProcessHeap(), 0, apte); 1062 #endif 1063 1064 return FALSE; 1065 } 1066 1067 static void add_dir_item(btrfs_root* root, uint64_t inode, uint32_t hash, uint64_t key_objid, uint8_t key_type, 1068 uint64_t key_offset, uint64_t transid, uint8_t type, const char* name) { 1069 uint16_t name_len = (uint16_t)strlen(name); 1070 #ifndef __REACTOS__ 1071 DIR_ITEM* di = malloc(offsetof(DIR_ITEM, name[0]) + name_len); 1072 #else 1073 DIR_ITEM* di = RtlAllocateHeap(RtlGetProcessHeap(), 0, offsetof(DIR_ITEM, name[0]) + name_len); 1074 #endif 1075 1076 di->key.obj_id = key_objid; 1077 di->key.obj_type = key_type; 1078 di->key.offset = key_offset; 1079 di->transid = transid; 1080 di->m = 0; 1081 di->n = name_len; 1082 di->type = type; 1083 memcpy(di->name, name, name_len); 1084 1085 add_item(root, inode, TYPE_DIR_ITEM, hash, di, (uint16_t)(offsetof(DIR_ITEM, name[0]) + di->m + di->n)); 1086 1087 #ifndef __REACTOS__ 1088 free(di); 1089 #else 1090 RtlFreeHeap(RtlGetProcessHeap(), 0, di); 1091 #endif 1092 } 1093 1094 static void set_default_subvol(btrfs_root* root_root, uint32_t node_size) { 1095 INODE_ITEM ii; 1096 FILETIME filetime; 1097 LARGE_INTEGER time; 1098 1099 static const char default_subvol[] = "default"; 1100 static const uint32_t default_hash = 0x8dbfc2d2; 1101 1102 add_inode_ref(root_root, BTRFS_ROOT_FSTREE, BTRFS_ROOT_TREEDIR, 0, default_subvol); 1103 1104 memset(&ii, 0, sizeof(INODE_ITEM)); 1105 1106 ii.generation = 1; 1107 ii.st_blocks = node_size; 1108 ii.st_nlink = 1; 1109 ii.st_mode = 040755; 1110 1111 GetSystemTimeAsFileTime(&filetime); 1112 time.LowPart = filetime.dwLowDateTime; 1113 time.HighPart = filetime.dwHighDateTime; 1114 1115 win_time_to_unix(time, &ii.st_atime); 1116 ii.st_ctime = ii.st_mtime = ii.otime = ii.st_atime; 1117 1118 add_item(root_root, BTRFS_ROOT_TREEDIR, TYPE_INODE_ITEM, 0, &ii, sizeof(INODE_ITEM)); 1119 1120 add_inode_ref(root_root, BTRFS_ROOT_TREEDIR, BTRFS_ROOT_TREEDIR, 0, ".."); 1121 1122 add_dir_item(root_root, BTRFS_ROOT_TREEDIR, default_hash, BTRFS_ROOT_FSTREE, TYPE_ROOT_ITEM, 1123 0xffffffffffffffff, 0, BTRFS_TYPE_DIRECTORY, default_subvol); 1124 } 1125 1126 static NTSTATUS write_btrfs(HANDLE h, uint64_t size, PUNICODE_STRING label, uint32_t sector_size, uint32_t node_size, uint64_t incompat_flags) { 1127 NTSTATUS Status; 1128 LIST_ENTRY roots, chunks; 1129 btrfs_root *root_root, *chunk_root, *extent_root, *dev_root, *fs_root, *reloc_root; 1130 btrfs_chunk *sys_chunk, *metadata_chunk; 1131 btrfs_dev dev; 1132 BTRFS_UUID fsuuid, chunkuuid; 1133 BOOL ssd; 1134 uint64_t metadata_flags; 1135 #ifdef __REACTOS__ 1136 ULONG seed; 1137 #endif 1138 1139 #ifndef __REACTOS__ 1140 srand((unsigned int)time(0)); 1141 get_uuid(&fsuuid); 1142 get_uuid(&chunkuuid); 1143 #else 1144 seed = NtGetTickCount(); 1145 get_uuid(&fsuuid, &seed); 1146 get_uuid(&chunkuuid, &seed); 1147 #endif 1148 1149 InitializeListHead(&roots); 1150 InitializeListHead(&chunks); 1151 1152 root_root = add_root(&roots, BTRFS_ROOT_ROOT); 1153 chunk_root = add_root(&roots, BTRFS_ROOT_CHUNK); 1154 extent_root = add_root(&roots, BTRFS_ROOT_EXTENT); 1155 dev_root = add_root(&roots, BTRFS_ROOT_DEVTREE); 1156 add_root(&roots, BTRFS_ROOT_CHECKSUM); 1157 fs_root = add_root(&roots, BTRFS_ROOT_FSTREE); 1158 reloc_root = add_root(&roots, BTRFS_ROOT_DATA_RELOC); 1159 1160 #ifndef __REACTOS__ 1161 init_device(&dev, 1, size, &fsuuid, sector_size); 1162 #else 1163 init_device(&dev, 1, size, &fsuuid, sector_size, &seed); 1164 #endif 1165 1166 ssd = is_ssd(h); 1167 1168 sys_chunk = add_chunk(&chunks, BLOCK_FLAG_SYSTEM | (ssd ? 0 : BLOCK_FLAG_DUPLICATE), chunk_root, &dev, dev_root, &chunkuuid, sector_size); 1169 if (!sys_chunk) 1170 return STATUS_INTERNAL_ERROR; 1171 1172 metadata_flags = BLOCK_FLAG_METADATA; 1173 1174 if (!ssd && !(incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS)) 1175 metadata_flags |= BLOCK_FLAG_DUPLICATE; 1176 1177 if (incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS) 1178 metadata_flags |= BLOCK_FLAG_DATA; 1179 1180 metadata_chunk = add_chunk(&chunks, metadata_flags, chunk_root, &dev, dev_root, &chunkuuid, sector_size); 1181 if (!metadata_chunk) 1182 return STATUS_INTERNAL_ERROR; 1183 1184 add_item(chunk_root, 1, TYPE_DEV_ITEM, dev.dev_item.dev_id, &dev.dev_item, sizeof(DEV_ITEM)); 1185 1186 set_default_subvol(root_root, node_size); 1187 1188 init_fs_tree(fs_root, node_size); 1189 init_fs_tree(reloc_root, node_size); 1190 1191 assign_addresses(&roots, sys_chunk, metadata_chunk, node_size, root_root, extent_root, incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA); 1192 1193 add_block_group_items(&chunks, extent_root); 1194 1195 Status = write_roots(h, &roots, node_size, &fsuuid, &chunkuuid); 1196 if (!NT_SUCCESS(Status)) 1197 return Status; 1198 1199 Status = clear_first_megabyte(h); 1200 if (!NT_SUCCESS(Status)) 1201 return Status; 1202 1203 Status = write_superblocks(h, &dev, chunk_root, root_root, extent_root, sys_chunk, node_size, &fsuuid, sector_size, label, incompat_flags); 1204 if (!NT_SUCCESS(Status)) 1205 return Status; 1206 1207 free_roots(&roots); 1208 free_chunks(&chunks); 1209 1210 return STATUS_SUCCESS; 1211 } 1212 1213 static BOOL look_for_device(btrfs_filesystem* bfs, BTRFS_UUID* devuuid) { 1214 uint32_t i; 1215 btrfs_filesystem_device* dev; 1216 1217 for (i = 0; i < bfs->num_devices; i++) { 1218 if (i == 0) 1219 dev = &bfs->device; 1220 else 1221 dev = (btrfs_filesystem_device*)((uint8_t*)dev + offsetof(btrfs_filesystem_device, name[0]) + dev->name_length); 1222 1223 if (RtlCompareMemory(&dev->uuid, devuuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) 1224 return TRUE; 1225 } 1226 1227 return FALSE; 1228 } 1229 1230 static BOOL is_mounted_multi_device(HANDLE h, uint32_t sector_size) { 1231 NTSTATUS Status; 1232 superblock* sb; 1233 ULONG sblen; 1234 IO_STATUS_BLOCK iosb; 1235 LARGE_INTEGER off; 1236 BTRFS_UUID fsuuid, devuuid; 1237 uint32_t crc32; 1238 UNICODE_STRING us; 1239 OBJECT_ATTRIBUTES atts; 1240 HANDLE h2; 1241 btrfs_filesystem *bfs = NULL, *bfs2; 1242 ULONG bfssize; 1243 BOOL ret = FALSE; 1244 1245 static WCHAR btrfs[] = L"\\Btrfs"; 1246 1247 sblen = sizeof(*sb); 1248 if (sblen & (sector_size - 1)) 1249 sblen = (sblen & sector_size) + sector_size; 1250 1251 #ifndef __REACTOS__ 1252 sb = malloc(sblen); 1253 #else 1254 sb = RtlAllocateHeap(RtlGetProcessHeap(), 0, sblen); 1255 #endif 1256 1257 off.QuadPart = superblock_addrs[0]; 1258 1259 Status = NtReadFile(h, NULL, NULL, NULL, &iosb, sb, sblen, &off, NULL); 1260 if (!NT_SUCCESS(Status)) { 1261 #ifndef __REACTOS__ 1262 free(sb); 1263 #else 1264 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 1265 #endif 1266 return FALSE; 1267 } 1268 1269 if (sb->magic != BTRFS_MAGIC) { 1270 #ifndef __REACTOS__ 1271 free(sb); 1272 #else 1273 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 1274 #endif 1275 return FALSE; 1276 } 1277 1278 crc32 = ~calc_crc32c(0xffffffff, (uint8_t*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 1279 if (crc32 != *((uint32_t*)sb)) { 1280 #ifndef __REACTOS__ 1281 free(sb); 1282 #else 1283 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 1284 #endif 1285 return FALSE; 1286 } 1287 1288 fsuuid = sb->uuid; 1289 devuuid = sb->dev_item.device_uuid; 1290 1291 #ifndef __REACTOS__ 1292 free(sb); 1293 #else 1294 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 1295 #endif 1296 1297 us.Length = us.MaximumLength = (USHORT)(wcslen(btrfs) * sizeof(WCHAR)); 1298 us.Buffer = btrfs; 1299 1300 InitializeObjectAttributes(&atts, &us, 0, NULL, NULL); 1301 1302 Status = NtOpenFile(&h2, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &atts, &iosb, 1303 FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT); 1304 if (!NT_SUCCESS(Status)) // not a problem, it usually just means the driver isn't loaded 1305 return FALSE; 1306 1307 bfssize = 0; 1308 1309 do { 1310 bfssize += 1024; 1311 1312 #ifndef __REACTOS__ 1313 if (bfs) free(bfs); 1314 bfs = malloc(bfssize); 1315 #else 1316 if (bfs) RtlFreeHeap(RtlGetProcessHeap(), 0, bfs); 1317 bfs = RtlAllocateHeap(RtlGetProcessHeap(), 0, bfssize); 1318 #endif 1319 1320 Status = NtDeviceIoControlFile(h2, NULL, NULL, NULL, &iosb, IOCTL_BTRFS_QUERY_FILESYSTEMS, NULL, 0, bfs, bfssize); 1321 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { 1322 NtClose(h2); 1323 return FALSE; 1324 } 1325 } while (Status == STATUS_BUFFER_OVERFLOW); 1326 1327 if (!NT_SUCCESS(Status)) 1328 goto end; 1329 1330 if (bfs->num_devices != 0) { 1331 bfs2 = bfs; 1332 while (TRUE) { 1333 if (RtlCompareMemory(&bfs2->uuid, &fsuuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 1334 if (bfs2->num_devices == 1) 1335 ret = FALSE; 1336 else 1337 ret = look_for_device(bfs2, &devuuid); 1338 1339 goto end; 1340 } 1341 1342 if (bfs2->next_entry == 0) 1343 break; 1344 else 1345 bfs2 = (btrfs_filesystem*)((uint8_t*)bfs2 + bfs2->next_entry); 1346 } 1347 } 1348 1349 end: 1350 NtClose(h2); 1351 1352 if (bfs) 1353 #ifndef __REACTOS__ 1354 free(bfs); 1355 #else 1356 RtlFreeHeap(RtlGetProcessHeap(), 0, bfs); 1357 #endif 1358 1359 return ret; 1360 } 1361 1362 static void do_full_trim(HANDLE h) { 1363 IO_STATUS_BLOCK iosb; 1364 DEVICE_MANAGE_DATA_SET_ATTRIBUTES dmdsa; 1365 1366 RtlZeroMemory(&dmdsa, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES)); 1367 1368 dmdsa.Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES); 1369 dmdsa.Action = DeviceDsmAction_Trim; 1370 dmdsa.Flags = DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE | DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED; 1371 dmdsa.ParameterBlockOffset = 0; 1372 dmdsa.ParameterBlockLength = 0; 1373 dmdsa.DataSetRangesOffset = 0; 1374 dmdsa.DataSetRangesLength = 0; 1375 1376 NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES, &dmdsa, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES), NULL, 0); 1377 } 1378 1379 static BOOL is_power_of_two(ULONG i) { 1380 return ((i != 0) && !(i & (i - 1))); 1381 } 1382 1383 #ifndef __REACTOS__ 1384 static NTSTATUS NTAPI FormatEx2(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFlag, PUNICODE_STRING Label, 1385 #else 1386 NTSTATUS NTAPI BtrfsFormatEx(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFlag, PUNICODE_STRING Label, 1387 #endif 1388 BOOLEAN QuickFormat, ULONG ClusterSize, PFMIFSCALLBACK Callback) 1389 { 1390 NTSTATUS Status; 1391 HANDLE h, btrfsh; 1392 OBJECT_ATTRIBUTES attr; 1393 IO_STATUS_BLOCK iosb; 1394 GET_LENGTH_INFORMATION gli; 1395 DISK_GEOMETRY dg; 1396 uint32_t sector_size, node_size; 1397 UNICODE_STRING btrfsus; 1398 #ifndef __REACTOS__ 1399 HANDLE token; 1400 TOKEN_PRIVILEGES tp; 1401 LUID luid; 1402 #endif 1403 uint64_t incompat_flags; 1404 UNICODE_STRING empty_label; 1405 1406 static WCHAR btrfs[] = L"\\Btrfs"; 1407 1408 #ifndef __REACTOS__ 1409 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1410 return STATUS_PRIVILEGE_NOT_HELD; 1411 1412 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) { 1413 CloseHandle(token); 1414 return STATUS_PRIVILEGE_NOT_HELD; 1415 } 1416 1417 tp.PrivilegeCount = 1; 1418 tp.Privileges[0].Luid = luid; 1419 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1420 1421 if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { 1422 CloseHandle(token); 1423 return STATUS_PRIVILEGE_NOT_HELD; 1424 } 1425 1426 CloseHandle(token); 1427 #endif 1428 1429 InitializeObjectAttributes(&attr, DriveRoot, OBJ_CASE_INSENSITIVE, NULL, NULL); 1430 1431 Status = NtOpenFile(&h, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb, 1432 FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT); 1433 1434 if (!NT_SUCCESS(Status)) 1435 return Status; 1436 1437 Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli)); 1438 if (!NT_SUCCESS(Status)) { 1439 NtClose(h); 1440 return Status; 1441 } 1442 1443 // MSDN tells us to use IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, but there are 1444 // some instances where it fails and IOCTL_DISK_GET_DRIVE_GEOMETRY succeeds - 1445 // such as with spanned volumes. 1446 Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg)); 1447 if (!NT_SUCCESS(Status)) { 1448 NtClose(h); 1449 return Status; 1450 } 1451 1452 if (def_sector_size == 0) { 1453 sector_size = dg.BytesPerSector; 1454 1455 if (sector_size == 0x200 || sector_size == 0) 1456 sector_size = 0x1000; 1457 } else { 1458 if (dg.BytesPerSector != 0 && (def_sector_size < dg.BytesPerSector || def_sector_size % dg.BytesPerSector != 0 || !is_power_of_two(def_sector_size / dg.BytesPerSector))) { 1459 NtClose(h); 1460 return STATUS_INVALID_PARAMETER; 1461 } 1462 1463 sector_size = def_sector_size; 1464 } 1465 1466 if (def_node_size == 0) 1467 node_size = 0x4000; 1468 else { 1469 if (def_node_size < sector_size || def_node_size % sector_size != 0 || !is_power_of_two(def_node_size / sector_size)) { 1470 NtClose(h); 1471 return STATUS_INVALID_PARAMETER; 1472 } 1473 1474 node_size = def_node_size; 1475 } 1476 1477 if (Callback) { 1478 ULONG pc = 0; 1479 Callback(PROGRESS, 0, (PVOID)&pc); 1480 } 1481 1482 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); 1483 1484 if (is_mounted_multi_device(h, sector_size)) { 1485 Status = STATUS_ACCESS_DENIED; 1486 goto end; 1487 } 1488 1489 do_full_trim(h); 1490 1491 incompat_flags = def_incompat_flags; 1492 incompat_flags |= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_BIG_METADATA; 1493 1494 if (!Label) { 1495 empty_label.Buffer = NULL; 1496 empty_label.Length = empty_label.MaximumLength = 0; 1497 Label = &empty_label; 1498 } 1499 1500 Status = write_btrfs(h, gli.Length.QuadPart, Label, sector_size, node_size, incompat_flags); 1501 1502 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); 1503 1504 end: 1505 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0); 1506 1507 NtClose(h); 1508 1509 if (NT_SUCCESS(Status)) { 1510 btrfsus.Buffer = btrfs; 1511 btrfsus.Length = btrfsus.MaximumLength = (USHORT)(wcslen(btrfs) * sizeof(WCHAR)); 1512 1513 InitializeObjectAttributes(&attr, &btrfsus, 0, NULL, NULL); 1514 1515 Status = NtOpenFile(&btrfsh, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb, 1516 FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT); 1517 1518 if (NT_SUCCESS(Status)) { 1519 MOUNTDEV_NAME* mdn; 1520 ULONG mdnsize; 1521 1522 mdnsize = offsetof(MOUNTDEV_NAME, Name[0]) + DriveRoot->Length; 1523 #ifndef __REACTOS__ 1524 mdn = malloc(mdnsize); 1525 #else 1526 mdn = RtlAllocateHeap(RtlGetProcessHeap(), 0, mdnsize); 1527 #endif 1528 1529 mdn->NameLength = DriveRoot->Length; 1530 memcpy(mdn->Name, DriveRoot->Buffer, DriveRoot->Length); 1531 1532 NtDeviceIoControlFile(btrfsh, NULL, NULL, NULL, &iosb, IOCTL_BTRFS_PROBE_VOLUME, mdn, mdnsize, NULL, 0); 1533 1534 #ifndef __REACTOS__ 1535 free(mdn); 1536 #else 1537 RtlFreeHeap(RtlGetProcessHeap(), 0, mdn); 1538 #endif 1539 1540 NtClose(btrfsh); 1541 } 1542 1543 Status = STATUS_SUCCESS; 1544 } 1545 1546 if (Callback) { 1547 BOOL success = NT_SUCCESS(Status); 1548 Callback(DONE, 0, (PVOID)&success); 1549 } 1550 1551 return Status; 1552 } 1553 1554 BOOL __stdcall FormatEx(DSTRING* root, STREAM_MESSAGE* message, options* opts, uint32_t unk1) { 1555 UNICODE_STRING DriveRoot, Label; 1556 NTSTATUS Status; 1557 1558 if (!root || !root->string) 1559 return FALSE; 1560 1561 DriveRoot.Length = DriveRoot.MaximumLength = (USHORT)(wcslen(root->string) * sizeof(WCHAR)); 1562 DriveRoot.Buffer = root->string; 1563 1564 if (opts && opts->label && opts->label->string) { 1565 Label.Length = Label.MaximumLength = (USHORT)(wcslen(opts->label->string) * sizeof(WCHAR)); 1566 Label.Buffer = opts->label->string; 1567 } else { 1568 Label.Length = Label.MaximumLength = 0; 1569 Label.Buffer = NULL; 1570 } 1571 1572 #ifndef __REACTOS__ 1573 Status = FormatEx2(&DriveRoot, FMIFS_HARDDISK, &Label, opts && opts->flags & FORMAT_FLAG_QUICK_FORMAT, 0, NULL); 1574 #else 1575 Status = BtrfsFormatEx(&DriveRoot, FMIFS_HARDDISK, &Label, opts && opts->flags & FORMAT_FLAG_QUICK_FORMAT, 0, NULL); 1576 #endif 1577 1578 return NT_SUCCESS(Status); 1579 } 1580 1581 void __stdcall SetSizes(ULONG sector, ULONG node) { 1582 if (sector != 0) 1583 def_sector_size = sector; 1584 1585 if (node != 0) 1586 def_node_size = node; 1587 } 1588 1589 void __stdcall SetIncompatFlags(uint64_t incompat_flags) { 1590 def_incompat_flags = incompat_flags; 1591 } 1592 1593 BOOL __stdcall GetFilesystemInformation(uint32_t unk1, uint32_t unk2, void* unk3) { 1594 // STUB - undocumented 1595 1596 return TRUE; 1597 } 1598 1599 #ifndef __REACTOS__ 1600 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) { 1601 if (dwReason == DLL_PROCESS_ATTACH) 1602 module = (HMODULE)hModule; 1603 1604 return TRUE; 1605 } 1606 #endif 1607