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