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 = 6; 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, 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, 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 init_fs_tree(btrfs_root* r, uint32_t node_size) { 933 INODE_ITEM ii; 934 INODE_REF* ir; 935 FILETIME filetime; 936 LARGE_INTEGER time; 937 938 memset(&ii, 0, sizeof(INODE_ITEM)); 939 940 ii.generation = 1; 941 ii.st_blocks = node_size; 942 ii.st_nlink = 1; 943 ii.st_mode = 040755; 944 945 GetSystemTimeAsFileTime(&filetime); 946 time.LowPart = filetime.dwLowDateTime; 947 time.HighPart = filetime.dwHighDateTime; 948 949 win_time_to_unix(time, &ii.st_atime); 950 ii.st_ctime = ii.st_mtime = ii.st_atime; 951 952 add_item(r, SUBVOL_ROOT_INODE, TYPE_INODE_ITEM, 0, &ii, sizeof(INODE_ITEM)); 953 954 #ifndef __REACTOS__ 955 ir = malloc(sizeof(INODE_REF) - 1 + 2); 956 #else 957 ir = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(INODE_REF) - 1 + 2); 958 #endif 959 960 ir->index = 0; 961 ir->n = 2; 962 ir->name[0] = '.'; 963 ir->name[1] = '.'; 964 965 add_item(r, SUBVOL_ROOT_INODE, TYPE_INODE_REF, SUBVOL_ROOT_INODE, ir, sizeof(INODE_REF) - 1 + ir->n); 966 967 #ifndef __REACTOS__ 968 free(ir); 969 #else 970 RtlFreeHeap(RtlGetProcessHeap(), 0, ir); 971 #endif 972 } 973 974 static void add_block_group_items(LIST_ENTRY* chunks, btrfs_root* extent_root) { 975 LIST_ENTRY* le; 976 977 le = chunks->Flink; 978 while (le != chunks) { 979 btrfs_chunk* c = CONTAINING_RECORD(le, btrfs_chunk, list_entry); 980 BLOCK_GROUP_ITEM bgi; 981 982 bgi.used = c->used; 983 bgi.chunk_tree = 0x100; 984 bgi.flags = c->chunk_item->type; 985 add_item(extent_root, c->offset, TYPE_BLOCK_GROUP_ITEM, c->chunk_item->size, &bgi, sizeof(BLOCK_GROUP_ITEM)); 986 987 le = le->Flink; 988 } 989 } 990 991 static NTSTATUS clear_first_megabyte(HANDLE h) { 992 NTSTATUS Status; 993 IO_STATUS_BLOCK iosb; 994 LARGE_INTEGER zero; 995 uint8_t* mb; 996 997 #ifndef __REACTOS__ 998 mb = malloc(0x100000); 999 memset(mb, 0, 0x100000); 1000 #else 1001 mb = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x100000); 1002 #endif 1003 1004 zero.QuadPart = 0; 1005 1006 Status = NtWriteFile(h, NULL, NULL, NULL, &iosb, mb, 0x100000, &zero, NULL); 1007 1008 #ifndef __REACTOS__ 1009 free(mb); 1010 #else 1011 RtlFreeHeap(RtlGetProcessHeap(), 0, mb); 1012 #endif 1013 1014 return Status; 1015 } 1016 1017 static BOOL is_ssd(HANDLE h) { 1018 ULONG aptelen; 1019 ATA_PASS_THROUGH_EX* apte; 1020 IO_STATUS_BLOCK iosb; 1021 NTSTATUS Status; 1022 IDENTIFY_DEVICE_DATA* idd; 1023 1024 aptelen = sizeof(ATA_PASS_THROUGH_EX) + 512; 1025 #ifndef __REACTOS__ 1026 apte = malloc(aptelen); 1027 1028 RtlZeroMemory(apte, aptelen); 1029 #else 1030 apte = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, aptelen); 1031 #endif 1032 1033 apte->Length = sizeof(ATA_PASS_THROUGH_EX); 1034 apte->AtaFlags = ATA_FLAGS_DATA_IN; 1035 apte->DataTransferLength = aptelen - sizeof(ATA_PASS_THROUGH_EX); 1036 apte->TimeOutValue = 3; 1037 apte->DataBufferOffset = apte->Length; 1038 apte->CurrentTaskFile[6] = IDE_COMMAND_IDENTIFY; 1039 1040 Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_ATA_PASS_THROUGH, apte, aptelen, apte, aptelen); 1041 1042 if (NT_SUCCESS(Status)) { 1043 idd = (IDENTIFY_DEVICE_DATA*)((uint8_t*)apte + sizeof(ATA_PASS_THROUGH_EX)); 1044 1045 if (idd->NominalMediaRotationRate == 1) { 1046 #ifndef __REACTOS__ 1047 free(apte); 1048 #else 1049 RtlFreeHeap(RtlGetProcessHeap(), 0, apte); 1050 #endif 1051 return TRUE; 1052 } 1053 } 1054 1055 #ifndef __REACTOS__ 1056 free(apte); 1057 #else 1058 RtlFreeHeap(RtlGetProcessHeap(), 0, apte); 1059 #endif 1060 1061 return FALSE; 1062 } 1063 1064 static NTSTATUS write_btrfs(HANDLE h, uint64_t size, PUNICODE_STRING label, uint32_t sector_size, uint32_t node_size, uint64_t incompat_flags) { 1065 NTSTATUS Status; 1066 LIST_ENTRY roots, chunks; 1067 btrfs_root *root_root, *chunk_root, *extent_root, *dev_root, *fs_root, *reloc_root; 1068 btrfs_chunk *sys_chunk, *metadata_chunk; 1069 btrfs_dev dev; 1070 BTRFS_UUID fsuuid, chunkuuid; 1071 BOOL ssd; 1072 uint64_t metadata_flags; 1073 #ifdef __REACTOS__ 1074 ULONG seed; 1075 #endif 1076 1077 #ifndef __REACTOS__ 1078 srand((unsigned int)time(0)); 1079 get_uuid(&fsuuid); 1080 get_uuid(&chunkuuid); 1081 #else 1082 seed = NtGetTickCount(); 1083 get_uuid(&fsuuid, &seed); 1084 get_uuid(&chunkuuid, &seed); 1085 #endif 1086 1087 InitializeListHead(&roots); 1088 InitializeListHead(&chunks); 1089 1090 root_root = add_root(&roots, BTRFS_ROOT_ROOT); 1091 chunk_root = add_root(&roots, BTRFS_ROOT_CHUNK); 1092 extent_root = add_root(&roots, BTRFS_ROOT_EXTENT); 1093 dev_root = add_root(&roots, BTRFS_ROOT_DEVTREE); 1094 add_root(&roots, BTRFS_ROOT_CHECKSUM); 1095 fs_root = add_root(&roots, BTRFS_ROOT_FSTREE); 1096 reloc_root = add_root(&roots, BTRFS_ROOT_DATA_RELOC); 1097 1098 #ifndef __REACTOS__ 1099 init_device(&dev, 1, size, &fsuuid, sector_size); 1100 #else 1101 init_device(&dev, 1, size, &fsuuid, sector_size, &seed); 1102 #endif 1103 1104 ssd = is_ssd(h); 1105 1106 sys_chunk = add_chunk(&chunks, BLOCK_FLAG_SYSTEM | (ssd ? 0 : BLOCK_FLAG_DUPLICATE), chunk_root, &dev, dev_root, &chunkuuid, sector_size); 1107 if (!sys_chunk) 1108 return STATUS_INTERNAL_ERROR; 1109 1110 metadata_flags = BLOCK_FLAG_METADATA; 1111 1112 if (!ssd && !(incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS)) 1113 metadata_flags |= BLOCK_FLAG_DUPLICATE; 1114 1115 if (incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS) 1116 metadata_flags |= BLOCK_FLAG_DATA; 1117 1118 metadata_chunk = add_chunk(&chunks, metadata_flags, chunk_root, &dev, dev_root, &chunkuuid, sector_size); 1119 if (!metadata_chunk) 1120 return STATUS_INTERNAL_ERROR; 1121 1122 add_item(chunk_root, 1, TYPE_DEV_ITEM, dev.dev_item.dev_id, &dev.dev_item, sizeof(DEV_ITEM)); 1123 1124 init_fs_tree(fs_root, node_size); 1125 init_fs_tree(reloc_root, node_size); 1126 1127 assign_addresses(&roots, sys_chunk, metadata_chunk, node_size, root_root, extent_root, incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA); 1128 1129 add_block_group_items(&chunks, extent_root); 1130 1131 Status = write_roots(h, &roots, node_size, &fsuuid, &chunkuuid); 1132 if (!NT_SUCCESS(Status)) 1133 return Status; 1134 1135 Status = clear_first_megabyte(h); 1136 if (!NT_SUCCESS(Status)) 1137 return Status; 1138 1139 Status = write_superblocks(h, &dev, chunk_root, root_root, extent_root, sys_chunk, node_size, &fsuuid, sector_size, label, incompat_flags); 1140 if (!NT_SUCCESS(Status)) 1141 return Status; 1142 1143 free_roots(&roots); 1144 free_chunks(&chunks); 1145 1146 return STATUS_SUCCESS; 1147 } 1148 1149 static BOOL look_for_device(btrfs_filesystem* bfs, BTRFS_UUID* devuuid) { 1150 uint32_t i; 1151 btrfs_filesystem_device* dev; 1152 1153 for (i = 0; i < bfs->num_devices; i++) { 1154 if (i == 0) 1155 dev = &bfs->device; 1156 else 1157 dev = (btrfs_filesystem_device*)((uint8_t*)dev + offsetof(btrfs_filesystem_device, name[0]) + dev->name_length); 1158 1159 if (RtlCompareMemory(&dev->uuid, devuuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) 1160 return TRUE; 1161 } 1162 1163 return FALSE; 1164 } 1165 1166 static BOOL is_mounted_multi_device(HANDLE h, uint32_t sector_size) { 1167 NTSTATUS Status; 1168 superblock* sb; 1169 ULONG sblen; 1170 IO_STATUS_BLOCK iosb; 1171 LARGE_INTEGER off; 1172 BTRFS_UUID fsuuid, devuuid; 1173 uint32_t crc32; 1174 UNICODE_STRING us; 1175 OBJECT_ATTRIBUTES atts; 1176 HANDLE h2; 1177 btrfs_filesystem *bfs = NULL, *bfs2; 1178 ULONG bfssize; 1179 BOOL ret = FALSE; 1180 1181 static WCHAR btrfs[] = L"\\Btrfs"; 1182 1183 sblen = sizeof(*sb); 1184 if (sblen & (sector_size - 1)) 1185 sblen = (sblen & sector_size) + sector_size; 1186 1187 #ifndef __REACTOS__ 1188 sb = malloc(sblen); 1189 #else 1190 sb = RtlAllocateHeap(RtlGetProcessHeap(), 0, sblen); 1191 #endif 1192 1193 off.QuadPart = superblock_addrs[0]; 1194 1195 Status = NtReadFile(h, NULL, NULL, NULL, &iosb, sb, sblen, &off, NULL); 1196 if (!NT_SUCCESS(Status)) { 1197 #ifndef __REACTOS__ 1198 free(sb); 1199 #else 1200 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 1201 #endif 1202 return FALSE; 1203 } 1204 1205 if (sb->magic != BTRFS_MAGIC) { 1206 #ifndef __REACTOS__ 1207 free(sb); 1208 #else 1209 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 1210 #endif 1211 return FALSE; 1212 } 1213 1214 crc32 = ~calc_crc32c(0xffffffff, (uint8_t*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); 1215 if (crc32 != *((uint32_t*)sb)) { 1216 #ifndef __REACTOS__ 1217 free(sb); 1218 #else 1219 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 1220 #endif 1221 return FALSE; 1222 } 1223 1224 fsuuid = sb->uuid; 1225 devuuid = sb->dev_item.device_uuid; 1226 1227 #ifndef __REACTOS__ 1228 free(sb); 1229 #else 1230 RtlFreeHeap(RtlGetProcessHeap(), 0, sb); 1231 #endif 1232 1233 us.Length = us.MaximumLength = (USHORT)(wcslen(btrfs) * sizeof(WCHAR)); 1234 us.Buffer = btrfs; 1235 1236 InitializeObjectAttributes(&atts, &us, 0, NULL, NULL); 1237 1238 Status = NtOpenFile(&h2, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &atts, &iosb, 1239 FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT); 1240 if (!NT_SUCCESS(Status)) // not a problem, it usually just means the driver isn't loaded 1241 return FALSE; 1242 1243 bfssize = 0; 1244 1245 do { 1246 bfssize += 1024; 1247 1248 #ifndef __REACTOS__ 1249 if (bfs) free(bfs); 1250 bfs = malloc(bfssize); 1251 #else 1252 if (bfs) RtlFreeHeap(RtlGetProcessHeap(), 0, bfs); 1253 bfs = RtlAllocateHeap(RtlGetProcessHeap(), 0, bfssize); 1254 #endif 1255 1256 Status = NtDeviceIoControlFile(h2, NULL, NULL, NULL, &iosb, IOCTL_BTRFS_QUERY_FILESYSTEMS, NULL, 0, bfs, bfssize); 1257 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { 1258 NtClose(h2); 1259 return FALSE; 1260 } 1261 } while (Status == STATUS_BUFFER_OVERFLOW); 1262 1263 if (!NT_SUCCESS(Status)) 1264 goto end; 1265 1266 if (bfs->num_devices != 0) { 1267 bfs2 = bfs; 1268 while (TRUE) { 1269 if (RtlCompareMemory(&bfs2->uuid, &fsuuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) { 1270 if (bfs2->num_devices == 1) 1271 ret = FALSE; 1272 else 1273 ret = look_for_device(bfs2, &devuuid); 1274 1275 goto end; 1276 } 1277 1278 if (bfs2->next_entry == 0) 1279 break; 1280 else 1281 bfs2 = (btrfs_filesystem*)((uint8_t*)bfs2 + bfs2->next_entry); 1282 } 1283 } 1284 1285 end: 1286 NtClose(h2); 1287 1288 if (bfs) 1289 #ifndef __REACTOS__ 1290 free(bfs); 1291 #else 1292 RtlFreeHeap(RtlGetProcessHeap(), 0, bfs); 1293 #endif 1294 1295 return ret; 1296 } 1297 1298 static void do_full_trim(HANDLE h) { 1299 IO_STATUS_BLOCK iosb; 1300 DEVICE_MANAGE_DATA_SET_ATTRIBUTES dmdsa; 1301 1302 RtlZeroMemory(&dmdsa, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES)); 1303 1304 dmdsa.Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES); 1305 dmdsa.Action = DeviceDsmAction_Trim; 1306 dmdsa.Flags = DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE | DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED; 1307 dmdsa.ParameterBlockOffset = 0; 1308 dmdsa.ParameterBlockLength = 0; 1309 dmdsa.DataSetRangesOffset = 0; 1310 dmdsa.DataSetRangesLength = 0; 1311 1312 NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES, &dmdsa, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES), NULL, 0); 1313 } 1314 1315 static BOOL is_power_of_two(ULONG i) { 1316 return ((i != 0) && !(i & (i - 1))); 1317 } 1318 1319 #ifndef __REACTOS__ 1320 static NTSTATUS NTAPI FormatEx2(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFlag, PUNICODE_STRING Label, 1321 #else 1322 NTSTATUS NTAPI BtrfsFormatEx(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFlag, PUNICODE_STRING Label, 1323 #endif 1324 BOOLEAN QuickFormat, ULONG ClusterSize, PFMIFSCALLBACK Callback) 1325 { 1326 NTSTATUS Status; 1327 HANDLE h, btrfsh; 1328 OBJECT_ATTRIBUTES attr; 1329 IO_STATUS_BLOCK iosb; 1330 GET_LENGTH_INFORMATION gli; 1331 DISK_GEOMETRY dg; 1332 uint32_t sector_size, node_size; 1333 UNICODE_STRING btrfsus; 1334 #ifndef __REACTOS__ 1335 HANDLE token; 1336 TOKEN_PRIVILEGES tp; 1337 LUID luid; 1338 #endif 1339 uint64_t incompat_flags; 1340 UNICODE_STRING empty_label; 1341 1342 static WCHAR btrfs[] = L"\\Btrfs"; 1343 1344 #ifndef __REACTOS__ 1345 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) 1346 return STATUS_PRIVILEGE_NOT_HELD; 1347 1348 if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) { 1349 CloseHandle(token); 1350 return STATUS_PRIVILEGE_NOT_HELD; 1351 } 1352 1353 tp.PrivilegeCount = 1; 1354 tp.Privileges[0].Luid = luid; 1355 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1356 1357 if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { 1358 CloseHandle(token); 1359 return STATUS_PRIVILEGE_NOT_HELD; 1360 } 1361 1362 CloseHandle(token); 1363 #endif 1364 1365 InitializeObjectAttributes(&attr, DriveRoot, OBJ_CASE_INSENSITIVE, NULL, NULL); 1366 1367 Status = NtOpenFile(&h, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb, 1368 FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT); 1369 1370 if (!NT_SUCCESS(Status)) 1371 return Status; 1372 1373 Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli)); 1374 if (!NT_SUCCESS(Status)) { 1375 NtClose(h); 1376 return Status; 1377 } 1378 1379 // MSDN tells us to use IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, but there are 1380 // some instances where it fails and IOCTL_DISK_GET_DRIVE_GEOMETRY succeeds - 1381 // such as with spanned volumes. 1382 Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg)); 1383 if (!NT_SUCCESS(Status)) { 1384 NtClose(h); 1385 return Status; 1386 } 1387 1388 if (def_sector_size == 0) { 1389 sector_size = dg.BytesPerSector; 1390 1391 if (sector_size == 0x200 || sector_size == 0) 1392 sector_size = 0x1000; 1393 } else { 1394 if (dg.BytesPerSector != 0 && (def_sector_size < dg.BytesPerSector || def_sector_size % dg.BytesPerSector != 0 || !is_power_of_two(def_sector_size / dg.BytesPerSector))) { 1395 NtClose(h); 1396 return STATUS_INVALID_PARAMETER; 1397 } 1398 1399 sector_size = def_sector_size; 1400 } 1401 1402 if (def_node_size == 0) 1403 node_size = 0x4000; 1404 else { 1405 if (def_node_size < sector_size || def_node_size % sector_size != 0 || !is_power_of_two(def_node_size / sector_size)) { 1406 NtClose(h); 1407 return STATUS_INVALID_PARAMETER; 1408 } 1409 1410 node_size = def_node_size; 1411 } 1412 1413 if (Callback) { 1414 ULONG pc = 0; 1415 Callback(PROGRESS, 0, (PVOID)&pc); 1416 } 1417 1418 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); 1419 1420 if (is_mounted_multi_device(h, sector_size)) { 1421 Status = STATUS_ACCESS_DENIED; 1422 goto end; 1423 } 1424 1425 do_full_trim(h); 1426 1427 incompat_flags = def_incompat_flags; 1428 incompat_flags |= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_BIG_METADATA; 1429 1430 if (!Label) { 1431 empty_label.Buffer = NULL; 1432 empty_label.Length = empty_label.MaximumLength = 0; 1433 Label = &empty_label; 1434 } 1435 1436 Status = write_btrfs(h, gli.Length.QuadPart, Label, sector_size, node_size, incompat_flags); 1437 1438 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); 1439 1440 end: 1441 NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0); 1442 1443 NtClose(h); 1444 1445 if (NT_SUCCESS(Status)) { 1446 btrfsus.Buffer = btrfs; 1447 btrfsus.Length = btrfsus.MaximumLength = (USHORT)(wcslen(btrfs) * sizeof(WCHAR)); 1448 1449 InitializeObjectAttributes(&attr, &btrfsus, 0, NULL, NULL); 1450 1451 Status = NtOpenFile(&btrfsh, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb, 1452 FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT); 1453 1454 if (NT_SUCCESS(Status)) { 1455 MOUNTDEV_NAME* mdn; 1456 ULONG mdnsize; 1457 1458 mdnsize = offsetof(MOUNTDEV_NAME, Name[0]) + DriveRoot->Length; 1459 #ifndef __REACTOS__ 1460 mdn = malloc(mdnsize); 1461 #else 1462 mdn = RtlAllocateHeap(RtlGetProcessHeap(), 0, mdnsize); 1463 #endif 1464 1465 mdn->NameLength = DriveRoot->Length; 1466 memcpy(mdn->Name, DriveRoot->Buffer, DriveRoot->Length); 1467 1468 NtDeviceIoControlFile(btrfsh, NULL, NULL, NULL, &iosb, IOCTL_BTRFS_PROBE_VOLUME, mdn, mdnsize, NULL, 0); 1469 1470 #ifndef __REACTOS__ 1471 free(mdn); 1472 #else 1473 RtlFreeHeap(RtlGetProcessHeap(), 0, mdn); 1474 #endif 1475 1476 NtClose(btrfsh); 1477 } 1478 1479 Status = STATUS_SUCCESS; 1480 } 1481 1482 if (Callback) { 1483 BOOL success = NT_SUCCESS(Status); 1484 Callback(DONE, 0, (PVOID)&success); 1485 } 1486 1487 return Status; 1488 } 1489 1490 BOOL __stdcall FormatEx(DSTRING* root, STREAM_MESSAGE* message, options* opts, uint32_t unk1) { 1491 UNICODE_STRING DriveRoot, Label; 1492 NTSTATUS Status; 1493 1494 if (!root || !root->string) 1495 return FALSE; 1496 1497 DriveRoot.Length = DriveRoot.MaximumLength = (USHORT)(wcslen(root->string) * sizeof(WCHAR)); 1498 DriveRoot.Buffer = root->string; 1499 1500 if (opts && opts->label && opts->label->string) { 1501 Label.Length = Label.MaximumLength = (USHORT)(wcslen(opts->label->string) * sizeof(WCHAR)); 1502 Label.Buffer = opts->label->string; 1503 } else { 1504 Label.Length = Label.MaximumLength = 0; 1505 Label.Buffer = NULL; 1506 } 1507 1508 #ifndef __REACTOS__ 1509 Status = FormatEx2(&DriveRoot, FMIFS_HARDDISK, &Label, opts && opts->flags & FORMAT_FLAG_QUICK_FORMAT, 0, NULL); 1510 #else 1511 Status = BtrfsFormatEx(&DriveRoot, FMIFS_HARDDISK, &Label, opts && opts->flags & FORMAT_FLAG_QUICK_FORMAT, 0, NULL); 1512 #endif 1513 1514 return NT_SUCCESS(Status); 1515 } 1516 1517 void __stdcall SetSizes(ULONG sector, ULONG node) { 1518 if (sector != 0) 1519 def_sector_size = sector; 1520 1521 if (node != 0) 1522 def_node_size = node; 1523 } 1524 1525 void __stdcall SetIncompatFlags(uint64_t incompat_flags) { 1526 def_incompat_flags = incompat_flags; 1527 } 1528 1529 BOOL __stdcall GetFilesystemInformation(uint32_t unk1, uint32_t unk2, void* unk3) { 1530 // STUB - undocumented 1531 1532 return TRUE; 1533 } 1534 1535 #ifndef __REACTOS__ 1536 BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) { 1537 if (dwReason == DLL_PROCESS_ATTACH) 1538 module = (HMODULE)hModule; 1539 1540 return TRUE; 1541 } 1542 #endif 1543