From 8e31783cb77f2c0874906e5486f1a6f7dcf832c4 Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Fri, 8 Sep 2017 16:31:32 +0000 Subject: [PATCH] [BTRFSLIB] Sync to 1.0 CORE-13763 svn path=/trunk/; revision=75796 --- reactos/media/doc/README.FSD | 2 +- reactos/sdk/lib/fslib/btrfslib/CMakeLists.txt | 3 + reactos/sdk/lib/fslib/btrfslib/btrfslib.c | 833 +++++++++++------- 3 files changed, 510 insertions(+), 328 deletions(-) diff --git a/reactos/media/doc/README.FSD b/reactos/media/doc/README.FSD index a3d8f513c16..f81290939f9 100644 --- a/reactos/media/doc/README.FSD +++ b/reactos/media/doc/README.FSD @@ -5,7 +5,7 @@ The following FSD are shared with: https://github.com/maharmstone/btrfs. reactos/drivers/filesystems/btrfs # Synced to 1.0 reactos/dll/shellext/shellbtrfs # Synced to 1.0 -reactos/sdk/lib/fslib/btrfslib # Synced to 0.8 +reactos/sdk/lib/fslib/btrfslib # Synced to 1.0 The following FSD are shared with: http://www.ext2fsd.com/ diff --git a/reactos/sdk/lib/fslib/btrfslib/CMakeLists.txt b/reactos/sdk/lib/fslib/btrfslib/CMakeLists.txt index a05c8df77db..3c4eca0190a 100644 --- a/reactos/sdk/lib/fslib/btrfslib/CMakeLists.txt +++ b/reactos/sdk/lib/fslib/btrfslib/CMakeLists.txt @@ -1,3 +1,6 @@ +include_directories( + ${REACTOS_SOURCE_DIR}/drivers/filesystems/btrfs) + add_library(btrfslib btrfslib.c) add_dependencies(btrfslib psdk) diff --git a/reactos/sdk/lib/fslib/btrfslib/btrfslib.c b/reactos/sdk/lib/fslib/btrfslib/btrfslib.c index 3e5baf11856..7677fbea59d 100644 --- a/reactos/sdk/lib/fslib/btrfslib/btrfslib.c +++ b/reactos/sdk/lib/fslib/btrfslib/btrfslib.c @@ -1,17 +1,17 @@ -/* Copyright (c) Mark Harmstone 2016 - * +/* Copyright (c) Mark Harmstone 2016-17 + * * This file is part of WinBtrfs. - * + * * WinBtrfs is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public Licence as published by * the Free Software Foundation, either version 3 of the Licence, or * (at your option) any later version. - * + * * WinBtrfs is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public Licence for more details. - * + * * You should have received a copy of the GNU Lesser General Public Licence * along with WinBtrfs. If not, see . */ @@ -32,11 +32,12 @@ #include #endif #include +#include #include #include #ifdef __REACTOS__ -#include "../../drivers/filesystems/btrfs/btrfs.h" -#include "../../drivers/filesystems/btrfs/btrfsioctl.h" +#include "btrfs.h" +#include "btrfsioctl.h" #else #include "../btrfs.h" #include "../btrfsioctl.h" @@ -46,9 +47,11 @@ #define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_UNLOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS) #define FSCTL_DISMOUNT_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#ifndef _MSC_VER // not in mingw yet +#define DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED 0x80000000 #endif -#ifndef __REACTOS__ #ifdef __cplusplus extern "C" { #endif @@ -65,7 +68,34 @@ NTSYSAPI NTSTATUS NTAPI RtlUnicodeToUTF8N(PCHAR UTF8StringDestination, ULONG UTF #ifdef __cplusplus } #endif +#endif + +// These are undocumented, and what comes from format.exe +typedef struct { + void* table; + void* unk1; + WCHAR* string; +} DSTRING; + +typedef struct { + void* table; +} STREAM_MESSAGE; + +#define FORMAT_FLAG_QUICK_FORMAT 0x00000001 +#define FORMAT_FLAG_UNKNOWN1 0x00000002 +#define FORMAT_FLAG_DISMOUNT_FIRST 0x00000004 +#define FORMAT_FLAG_UNKNOWN2 0x00000040 +#define FORMAT_FLAG_LARGE_RECORDS 0x00000100 +#define FORMAT_FLAG_INTEGRITY_DISABLE 0x00000100 + +typedef struct { + UINT16 unk1; + UINT16 unk2; + UINT32 flags; + DSTRING* label; +} options; +#ifndef __REACTOS__ FORCEINLINE VOID InitializeListHead(PLIST_ENTRY ListHead) { ListHead->Flink = ListHead->Blink = ListHead; } @@ -129,6 +159,8 @@ typedef struct { 0)))))) HMODULE module; +ULONG def_sector_size = 0, def_node_size = 0; +UINT64 def_incompat_flags = BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA; // the following definitions come from fmifs.h in ReactOS @@ -187,50 +219,50 @@ typedef enum { typedef BOOLEAN (NTAPI* PFMIFSCALLBACK)(CALLBACKCOMMAND Command, ULONG SubAction, PVOID ActionInfo); static const UINT32 crctable[] = { - 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, - 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, - 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, - 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, - 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, - 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, - 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, - 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, - 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, - 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, - 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, - 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, - 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, - 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, - 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, - 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, - 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, - 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, - 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, - 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, - 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, - 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, - 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, - 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, - 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, - 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, - 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, - 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, - 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, - 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, - 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, + 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb, + 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b, 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, + 0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384, + 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b, + 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a, 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, + 0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa, + 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a, + 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a, 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, + 0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957, + 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198, + 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927, 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, + 0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7, + 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789, + 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859, 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, + 0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6, + 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829, + 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c, 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, + 0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c, + 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc, + 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c, 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, + 0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d, + 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982, + 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d, 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, + 0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed, + 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f, + 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff, 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, + 0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540, + 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f, + 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee, 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, + 0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e, + 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e, 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351, }; static UINT32 calc_crc32c(UINT32 seed, UINT8* msg, ULONG msglen) { UINT32 rem; ULONG i; - + rem = seed; - + for (i = 0; i < msglen; i++) { rem = crctable[(rem ^ msg[i]) & 0xff] ^ (rem >> 8); } - + return rem; } @@ -241,83 +273,83 @@ NTSTATUS NTAPI BtrfsChkdskEx(PUNICODE_STRING DriveRoot, BOOLEAN FixErrors, BOOLE #endif BOOLEAN ScanDrive, PFMIFSCALLBACK Callback) { // STUB - + if (Callback) { TEXTOUTPUT TextOut; - + TextOut.Lines = 1; TextOut.Output = "stub, not implemented"; - + Callback(OUTPUT, 0, &TextOut); } - + return STATUS_SUCCESS; } static btrfs_root* add_root(LIST_ENTRY* roots, UINT64 id) { btrfs_root* root; - + #ifdef __REACTOS__ root = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(btrfs_root)); #else root = malloc(sizeof(btrfs_root)); #endif - + root->id = id; #ifndef __REACTOS__ RtlZeroMemory(&root->header, sizeof(tree_header)); #endif InitializeListHead(&root->items); InsertTailList(roots, &root->list_entry); - + return root; } static void free_roots(LIST_ENTRY* roots) { LIST_ENTRY* le; - + le = roots->Flink; while (le != roots) { LIST_ENTRY *le2 = le->Flink, *le3; btrfs_root* r = CONTAINING_RECORD(le, btrfs_root, list_entry); - + le3 = r->items.Flink; while (le3 != &r->items) { LIST_ENTRY* le4 = le3->Flink; btrfs_item* item = CONTAINING_RECORD(le3, btrfs_item, list_entry); - + if (item->data) #ifdef __REACTOS__ RtlFreeHeap(RtlGetProcessHeap(), 0, item->data); - + RtlFreeHeap(RtlGetProcessHeap(), 0, item); #else free(item->data); - + free(item); #endif - + le3 = le4; } - + #ifdef __REACTOS__ RtlFreeHeap(RtlGetProcessHeap(), 0, r); #else free(r); #endif - + le = le2; } } static void free_chunks(LIST_ENTRY* chunks) { LIST_ENTRY* le; - + le = chunks->Flink; while (le != chunks) { LIST_ENTRY *le2 = le->Flink; btrfs_chunk* c = CONTAINING_RECORD(le, btrfs_chunk, list_entry); - + #ifndef __REACTOS__ free(c->chunk_item); free(c); @@ -325,7 +357,7 @@ static void free_chunks(LIST_ENTRY* chunks) { RtlFreeHeap(RtlGetProcessHeap(), 0, c->chunk_item); RtlFreeHeap(RtlGetProcessHeap(), 0, c); #endif - + le = le2; } } @@ -333,18 +365,18 @@ static void free_chunks(LIST_ENTRY* chunks) { static void add_item(btrfs_root* r, UINT64 obj_id, UINT8 obj_type, UINT64 offset, void* data, UINT16 size) { LIST_ENTRY* le; btrfs_item* item; - + #ifndef __REACTOS__ item = malloc(sizeof(btrfs_item)); #else item = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(btrfs_item)); #endif - + item->key.obj_id = obj_id; item->key.obj_type = obj_type; item->key.offset = offset; item->size = size; - + if (size == 0) item->data = NULL; else { @@ -355,39 +387,39 @@ static void add_item(btrfs_root* r, UINT64 obj_id, UINT8 obj_type, UINT64 offset #endif memcpy(item->data, data, size); } - + le = r->items.Flink; while (le != &r->items) { btrfs_item* i2 = CONTAINING_RECORD(le, btrfs_item, list_entry); - + if (keycmp(item->key, i2->key) != 1) { InsertTailList(le, &item->list_entry); return; } - + le = le->Flink; } - + InsertTailList(&r->items, &item->list_entry); } static UINT64 find_chunk_offset(UINT64 size, UINT64 offset, btrfs_dev* dev, btrfs_root* dev_root, BTRFS_UUID* chunkuuid) { UINT64 off; DEV_EXTENT de; - + off = dev->last_alloc; dev->last_alloc += size; - + dev->dev_item.bytes_used += size; - + de.chunktree = BTRFS_ROOT_CHUNK; de.objid = 0x100; de.address = offset; de.length = size; de.chunktree_uuid = *chunkuuid; - + add_item(dev_root, dev->dev_item.dev_id, TYPE_DEV_EXTENT, off, &de, sizeof(DEV_EXTENT)); - + return off; } @@ -397,15 +429,15 @@ static btrfs_chunk* add_chunk(LIST_ENTRY* chunks, UINT64 flags, btrfs_root* chun btrfs_chunk* c; LIST_ENTRY* le; CHUNK_ITEM_STRIPE* cis; - + off = 0xc00000; le = chunks->Flink; while (le != chunks) { c = CONTAINING_RECORD(le, btrfs_chunk, list_entry); - + if (c->offset + c->chunk_item->size > off) off = c->offset + c->chunk_item->size; - + le = le->Flink; } @@ -416,15 +448,15 @@ static btrfs_chunk* add_chunk(LIST_ENTRY* chunks, UINT64 flags, btrfs_root* chun size = 0x10000000; // 256 MB } else if (flags & BLOCK_FLAG_SYSTEM) size = 0x800000; - + size = min(size, dev->dev_item.num_bytes / 10); // cap at 10% size &= ~(sector_size - 1); - + stripes = flags & BLOCK_FLAG_DUPLICATE ? 2 : 1; - + if (dev->dev_item.num_bytes - dev->dev_item.bytes_used < stripes * size) // not enough space return NULL; - + #ifndef __REACTOS__ c = malloc(sizeof(btrfs_chunk)); #else @@ -433,35 +465,35 @@ static btrfs_chunk* add_chunk(LIST_ENTRY* chunks, UINT64 flags, btrfs_root* chun c->offset = off; c->lastoff = off; c->used = 0; - + #ifndef __REACTOS__ - c->chunk_item = malloc(sizeof(CHUNK_ITEM) + (stripes * sizeof(CHUNK_ITEM_STRIPE))); + c->chunk_item = malloc(sizeof(CHUNK_ITEM) + (stripes * sizeof(CHUNK_ITEM_STRIPE))); #else c->chunk_item = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(CHUNK_ITEM) + (stripes * sizeof(CHUNK_ITEM_STRIPE))); #endif - + c->chunk_item->size = size; c->chunk_item->root_id = BTRFS_ROOT_EXTENT; - c->chunk_item->stripe_length = 0x10000; + c->chunk_item->stripe_length = max(sector_size, 0x10000); c->chunk_item->type = flags; - c->chunk_item->opt_io_alignment = 0x10000; - c->chunk_item->opt_io_width = 0x10000; + c->chunk_item->opt_io_alignment = max(sector_size, 0x10000); + c->chunk_item->opt_io_width = max(sector_size, 0x10000); c->chunk_item->sector_size = sector_size; c->chunk_item->num_stripes = stripes; c->chunk_item->sub_stripes = 0; - + cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1]; - + for (i = 0; i < stripes; i++) { cis[i].dev_id = dev->dev_item.dev_id; cis[i].offset = find_chunk_offset(size, c->offset, dev, dev_root, chunkuuid); cis[i].dev_uuid = dev->dev_item.device_uuid; } - + add_item(chunk_root, 0x100, TYPE_CHUNK_ITEM, c->offset, c->chunk_item, sizeof(CHUNK_ITEM) + (stripes * sizeof(CHUNK_ITEM_STRIPE))); InsertTailList(chunks, &c->list_entry); - + return c; } @@ -469,35 +501,35 @@ static BOOL superblock_collision(btrfs_chunk* c, UINT64 address) { CHUNK_ITEM_STRIPE* cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1]; UINT64 stripe = (address - c->offset) / c->chunk_item->stripe_length; UINT16 i, j; - + for (i = 0; i < c->chunk_item->num_stripes; i++) { j = 0; while (superblock_addrs[j] != 0) { if (superblock_addrs[j] >= cis[i].offset) { UINT64 stripe2 = (superblock_addrs[j] - cis[i].offset) / c->chunk_item->stripe_length; - + if (stripe2 == stripe) return TRUE; } j++; } } - + return FALSE; } static UINT64 get_next_address(btrfs_chunk* c) { UINT64 addr; - + addr = c->lastoff; - + while (superblock_collision(c, addr)) { addr = addr - ((addr - c->offset) % c->chunk_item->stripe_length) + c->chunk_item->stripe_length; - + if (addr >= c->offset + c->chunk_item->size) // chunk has been exhausted return 0; } - + return addr; } @@ -507,35 +539,67 @@ typedef struct { TREE_BLOCK_REF tbr; } EXTENT_ITEM_METADATA; +typedef struct { + EXTENT_ITEM ei; + EXTENT_ITEM2 ei2; + UINT8 type; + TREE_BLOCK_REF tbr; +} EXTENT_ITEM_METADATA2; + static void assign_addresses(LIST_ENTRY* roots, btrfs_chunk* sys_chunk, btrfs_chunk* metadata_chunk, UINT32 node_size, - btrfs_root* root_root, btrfs_root* extent_root) { + btrfs_root* root_root, btrfs_root* extent_root, BOOL skinny) { LIST_ENTRY* le; - + le = roots->Flink; while (le != roots) { btrfs_root* r = CONTAINING_RECORD(le, btrfs_root, list_entry); btrfs_chunk* c = r->id == BTRFS_ROOT_CHUNK ? sys_chunk : metadata_chunk; - EXTENT_ITEM_METADATA eim; - + r->header.address = get_next_address(c); r->c = c; c->lastoff = r->header.address + node_size; c->used += node_size; - - eim.ei.refcount = 1; - eim.ei.generation = 1; - eim.ei.flags = EXTENT_ITEM_TREE_BLOCK; - eim.type = TYPE_TREE_BLOCK_REF; - eim.tbr.offset = r->id; - - // FIXME - support non-skinny EXTENT_ITEM - add_item(extent_root, r->header.address, TYPE_METADATA_ITEM, 0, &eim, sizeof(EXTENT_ITEM_METADATA)); - + + if (skinny) { + EXTENT_ITEM_METADATA eim; + + eim.ei.refcount = 1; + eim.ei.generation = 1; + eim.ei.flags = EXTENT_ITEM_TREE_BLOCK; + eim.type = TYPE_TREE_BLOCK_REF; + eim.tbr.offset = r->id; + + add_item(extent_root, r->header.address, TYPE_METADATA_ITEM, 0, &eim, sizeof(EXTENT_ITEM_METADATA)); + } else { + EXTENT_ITEM_METADATA2 eim2; + KEY firstitem; + + if (r->items.Flink == &r->items) { + firstitem.obj_id = 0; + firstitem.obj_type = 0; + firstitem.offset = 0; + } else { + btrfs_item* bi = CONTAINING_RECORD(r->items.Flink, btrfs_item, list_entry); + + firstitem = bi->key; + } + + eim2.ei.refcount = 1; + eim2.ei.generation = 1; + eim2.ei.flags = EXTENT_ITEM_TREE_BLOCK; + eim2.ei2.firstitem = firstitem; + eim2.ei2.level = 0; + eim2.type = TYPE_TREE_BLOCK_REF; + eim2.tbr.offset = r->id; + + add_item(extent_root, r->header.address, TYPE_EXTENT_ITEM, node_size, &eim2, sizeof(EXTENT_ITEM_METADATA2)); + } + if (r->id != BTRFS_ROOT_ROOT && r->id != BTRFS_ROOT_CHUNK) { ROOT_ITEM ri; - + memset(&ri, 0, sizeof(ROOT_ITEM)); - + ri.inode.generation = 1; ri.inode.st_size = 3; ri.inode.st_blocks = node_size; @@ -547,10 +611,10 @@ static void assign_addresses(LIST_ENTRY* roots, btrfs_chunk* sys_chunk, btrfs_ch ri.bytes_used = node_size; ri.num_references = 1; ri.generation2 = ri.generation; - + add_item(root_root, r->id, TYPE_ROOT_ITEM, 0, &ri, sizeof(ROOT_ITEM)); } - + le = le->Flink; } } @@ -561,17 +625,17 @@ static NTSTATUS write_data(HANDLE h, UINT64 address, btrfs_chunk* c, void* data, IO_STATUS_BLOCK iosb; LARGE_INTEGER off; CHUNK_ITEM_STRIPE* cis; - + cis = (CHUNK_ITEM_STRIPE*)&c->chunk_item[1]; - + for (i = 0; i < c->chunk_item->num_stripes; i++) { off.QuadPart = cis[i].offset + address - c->offset; - + Status = NtWriteFile(h, NULL, NULL, NULL, &iosb, data, size, &off, NULL); if (!NT_SUCCESS(Status)) return Status; } - + return STATUS_SUCCESS; } @@ -579,13 +643,13 @@ static NTSTATUS write_roots(HANDLE h, LIST_ENTRY* roots, UINT32 node_size, BTRFS LIST_ENTRY *le, *le2; NTSTATUS Status; UINT8* tree; - + #ifndef __REACTOS__ tree = malloc(node_size); #else tree = RtlAllocateHeap(RtlGetProcessHeap(), 0, node_size); #endif - + le = roots->Flink; while (le != roots) { btrfs_root* r = CONTAINING_RECORD(le, btrfs_root, list_entry); @@ -594,45 +658,45 @@ static NTSTATUS write_roots(HANDLE h, LIST_ENTRY* roots, UINT32 node_size, BTRFS UINT32 crc32; memset(tree, 0, node_size); - + r->header.num_items = 0; r->header.fs_uuid = *fsuuid; r->header.flags = HEADER_FLAG_MIXED_BACKREF | HEADER_FLAG_WRITTEN; r->header.chunk_tree_uuid = *chunkuuid; r->header.generation = 1; r->header.tree_id = r->id; - + ln = (leaf_node*)(tree + sizeof(tree_header)); - + dp = tree + node_size; - + le2 = r->items.Flink; while (le2 != &r->items) { btrfs_item* item = CONTAINING_RECORD(le2, btrfs_item, list_entry); ln->key = item->key; ln->size = item->size; - + if (item->size > 0) { dp -= item->size; memcpy(dp, item->data, item->size); - + ln->offset = dp - tree - sizeof(tree_header); } else ln->offset = 0; - + ln = &ln[1]; - + r->header.num_items++; - + le2 = le2->Flink; } - + memcpy(tree, &r->header, sizeof(tree_header)); - + crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&((tree_header*)tree)->fs_uuid, node_size - sizeof(((tree_header*)tree)->csum)); memcpy(tree, &crc32, sizeof(UINT32)); - + Status = write_data(h, r->header.address, r->c, tree, node_size); if (!NT_SUCCESS(Status)) { #ifndef __REACTOS__ @@ -642,16 +706,16 @@ static NTSTATUS write_roots(HANDLE h, LIST_ENTRY* roots, UINT32 node_size, BTRFS #endif return Status; } - + le = le->Flink; } - + #ifndef __REACTOS__ free(tree); #else RtlFreeHeap(RtlGetProcessHeap(), 0, tree); #endif - + return STATUS_SUCCESS; } @@ -661,14 +725,14 @@ static void get_uuid(BTRFS_UUID* uuid) { static void get_uuid(BTRFS_UUID* uuid, ULONG* seed) { #endif UINT8 i; - + for (i = 0; i < 16; i+=2) { #ifndef __REACTOS__ ULONG r = rand(); #else ULONG r = RtlRandom(seed); #endif - + uuid->uuid[i] = (r & 0xff00) >> 8; uuid->uuid[i+1] = r & 0xff; } @@ -697,7 +761,7 @@ static void init_device(btrfs_dev* dev, UINT64 id, UINT64 size, BTRFS_UUID* fsuu get_uuid(&dev->dev_item.device_uuid, seed); #endif dev->dev_item.fs_uuid = *fsuuid; - + dev->last_alloc = 0x100000; // skip first megabyte } @@ -812,7 +876,7 @@ NTSTATUS NTAPI RtlUnicodeToUTF8N(CHAR *utf8_dest, ULONG utf8_bytes_max, #endif static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_root, btrfs_root* root_root, btrfs_root* extent_root, - btrfs_chunk* sys_chunk, UINT32 node_size, BTRFS_UUID* fsuuid, UINT32 sector_size, PUNICODE_STRING label) { + btrfs_chunk* sys_chunk, UINT32 node_size, BTRFS_UUID* fsuuid, UINT32 sector_size, PUNICODE_STRING label, UINT64 incompat_flags) { NTSTATUS Status; IO_STATUS_BLOCK iosb; ULONG sblen; @@ -822,32 +886,32 @@ static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_ro KEY* key; UINT64 bytes_used; LIST_ENTRY* le; - + sblen = sizeof(sb); if (sblen & (sector_size - 1)) sblen = (sblen & sector_size) + sector_size; - + bytes_used = 0; - + le = extent_root->items.Flink; while (le != &extent_root->items) { btrfs_item* item = CONTAINING_RECORD(le, btrfs_item, list_entry); - + if (item->key.obj_type == TYPE_EXTENT_ITEM) bytes_used += item->key.offset; else if (item->key.obj_type == TYPE_METADATA_ITEM) bytes_used += node_size; - + le = le->Flink; } - + #ifndef __REACTOS__ sb = malloc(sblen); memset(sb, 0, sblen); #else sb = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sblen); #endif - + sb->uuid = *fsuuid; sb->flags = 1; sb->magic = BTRFS_MAGIC; @@ -864,13 +928,13 @@ static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_ro sb->stripe_size = sector_size; sb->n = sizeof(KEY) + sizeof(CHUNK_ITEM) + (sys_chunk->chunk_item->num_stripes * sizeof(CHUNK_ITEM_STRIPE)); sb->chunk_root_generation = 1; - sb->incompat_flags = BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF | BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA; + sb->incompat_flags = incompat_flags; memcpy(&sb->dev_item, &dev->dev_item, sizeof(DEV_ITEM)); - + if (label->Length > 0) { int i; ULONG utf8len; - + for (i = 0; i < label->Length / sizeof(WCHAR); i++) { if (label->Buffer[i] == '/' || label->Buffer[i] == '\\') { #ifndef __REACTOS__ @@ -881,7 +945,7 @@ static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_ro return STATUS_INVALID_VOLUME_LABEL; } } - + Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, label->Buffer, label->Length); if (!NT_SUCCESS(Status)) { #ifndef __REACTOS__ @@ -891,7 +955,7 @@ static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_ro #endif return Status; } - + if (utf8len > MAX_LABEL_SIZE) { #ifndef __REACTOS__ free(sb); @@ -900,7 +964,7 @@ static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_ro #endif return STATUS_INVALID_VOLUME_LABEL; } - + Status = RtlUnicodeToUTF8N((PCHAR)&sb->label, MAX_LABEL_SIZE, &utf8len, label->Buffer, label->Length); if (!NT_SUCCESS(Status)) { #ifndef __REACTOS__ @@ -912,27 +976,27 @@ static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_ro } } sb->cache_generation = 0xffffffffffffffff; - + key = (KEY*)sb->sys_chunk_array; key->obj_id = 0x100; key->obj_type = TYPE_CHUNK_ITEM; key->offset = sys_chunk->offset; memcpy(&key[1], sys_chunk->chunk_item, sizeof(CHUNK_ITEM) + (sys_chunk->chunk_item->num_stripes * sizeof(CHUNK_ITEM_STRIPE))); - + i = 0; while (superblock_addrs[i] != 0) { LARGE_INTEGER off; - + if (superblock_addrs[i] > dev->dev_item.num_bytes) break; - + sb->sb_phys_addr = superblock_addrs[i]; - + crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); memcpy(&sb->checksum, &crc32, sizeof(UINT32)); - + off.QuadPart = superblock_addrs[i]; - + Status = NtWriteFile(h, NULL, NULL, NULL, &iosb, sb, sblen, &off, NULL); if (!NT_SUCCESS(Status)) { #ifndef __REACTOS__ @@ -942,22 +1006,22 @@ static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_ro #endif return Status; } - + i++; } - + #ifndef __REACTOS__ free(sb); #else RtlFreeHeap(RtlGetProcessHeap(), 0, sb); #endif - + return STATUS_SUCCESS; } static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME* out) { ULONGLONG l = t.QuadPart - 116444736000000000; - + out->seconds = l / 10000000; out->nanoseconds = (l % 10000000) * 100; } @@ -984,46 +1048,38 @@ GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime) static void init_fs_tree(btrfs_root* r, UINT32 node_size) { INODE_ITEM ii; INODE_REF* ir; -#ifndef __REACTOS__ - SYSTEMTIME systime; -#endif FILETIME filetime; LARGE_INTEGER time; - + memset(&ii, 0, sizeof(INODE_ITEM)); - + ii.generation = 1; ii.st_blocks = node_size; ii.st_nlink = 1; ii.st_mode = 040755; - -#ifndef __REACTOS__ - GetSystemTime(&systime); - SystemTimeToFileTime(&systime, &filetime); -#else + GetSystemTimeAsFileTime(&filetime); -#endif time.LowPart = filetime.dwLowDateTime; time.HighPart = filetime.dwHighDateTime; win_time_to_unix(time, &ii.st_atime); ii.st_ctime = ii.st_mtime = ii.st_atime; - + add_item(r, SUBVOL_ROOT_INODE, TYPE_INODE_ITEM, 0, &ii, sizeof(INODE_ITEM)); - + #ifndef __REACTOS__ ir = malloc(sizeof(INODE_REF) - 1 + 2); #else ir = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(INODE_REF) - 1 + 2); #endif - + ir->index = 0; ir->n = 2; ir->name[0] = '.'; ir->name[1] = '.'; - + add_item(r, SUBVOL_ROOT_INODE, TYPE_INODE_REF, SUBVOL_ROOT_INODE, ir, sizeof(INODE_REF) - 1 + ir->n); - + #ifndef __REACTOS__ free(ir); #else @@ -1033,17 +1089,17 @@ static void init_fs_tree(btrfs_root* r, UINT32 node_size) { static void add_block_group_items(LIST_ENTRY* chunks, btrfs_root* extent_root) { LIST_ENTRY* le; - + le = chunks->Flink; while (le != chunks) { btrfs_chunk* c = CONTAINING_RECORD(le, btrfs_chunk, list_entry); BLOCK_GROUP_ITEM bgi; - + bgi.used = c->used; bgi.chunk_tree = 0x100; bgi.flags = c->chunk_item->type; add_item(extent_root, c->offset, TYPE_BLOCK_GROUP_ITEM, c->chunk_item->size, &bgi, sizeof(BLOCK_GROUP_ITEM)); - + le = le->Flink; } } @@ -1053,24 +1109,25 @@ static NTSTATUS clear_first_megabyte(HANDLE h) { IO_STATUS_BLOCK iosb; LARGE_INTEGER zero; UINT8* mb; - + + #ifndef __REACTOS__ mb = malloc(0x100000); + memset(mb, 0, 0x100000); #else - mb = RtlAllocateHeap(RtlGetProcessHeap(), 0, 0x100000); + mb = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x100000); #endif - memset(mb, 0, 0x100000); - + zero.QuadPart = 0; - + Status = NtWriteFile(h, NULL, NULL, NULL, &iosb, mb, 0x100000, &zero, NULL); - + #ifndef __REACTOS__ free(mb); #else RtlFreeHeap(RtlGetProcessHeap(), 0, mb); #endif - + return Status; } @@ -1080,48 +1137,60 @@ static BOOL is_ssd(HANDLE h) { IO_STATUS_BLOCK iosb; NTSTATUS Status; IDENTIFY_DEVICE_DATA* idd; - + aptelen = sizeof(ATA_PASS_THROUGH_EX) + 512; #ifndef __REACTOS__ apte = malloc(aptelen); - + RtlZeroMemory(apte, aptelen); #else apte = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, aptelen); #endif - + apte->Length = sizeof(ATA_PASS_THROUGH_EX); apte->AtaFlags = ATA_FLAGS_DATA_IN; apte->DataTransferLength = aptelen - sizeof(ATA_PASS_THROUGH_EX); apte->TimeOutValue = 3; apte->DataBufferOffset = apte->Length; apte->CurrentTaskFile[6] = IDE_COMMAND_IDENTIFY; - + Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_ATA_PASS_THROUGH, apte, aptelen, apte, aptelen); - + if (NT_SUCCESS(Status)) { idd = (IDENTIFY_DEVICE_DATA*)((UINT8*)apte + sizeof(ATA_PASS_THROUGH_EX)); - - if (idd->NominalMediaRotationRate == 1) + + if (idd->NominalMediaRotationRate == 1) { +#ifndef __REACTOS__ + free(apte); +#else + RtlFreeHeap(RtlGetProcessHeap(), 0, apte); +#endif return TRUE; + } } - + +#ifndef __REACTOS__ + free(apte); +#else + RtlFreeHeap(RtlGetProcessHeap(), 0, apte); +#endif + return FALSE; } -static NTSTATUS write_btrfs(HANDLE h, UINT64 size, PUNICODE_STRING label, UINT32 sector_size) { +static NTSTATUS write_btrfs(HANDLE h, UINT64 size, PUNICODE_STRING label, UINT32 sector_size, UINT32 node_size, UINT64 incompat_flags) { NTSTATUS Status; - UINT32 node_size; LIST_ENTRY roots, chunks; btrfs_root *root_root, *chunk_root, *extent_root, *dev_root, *fs_root, *reloc_root; - btrfs_chunk *sys_chunk, *metadata_chunk; + btrfs_chunk *sys_chunk, *metadata_chunk; btrfs_dev dev; BTRFS_UUID fsuuid, chunkuuid; BOOL ssd; + UINT64 metadata_flags; #ifdef __REACTOS__ ULONG seed; #endif - + #ifndef __REACTOS__ srand(time(0)); get_uuid(&fsuuid); @@ -1131,10 +1200,10 @@ static NTSTATUS write_btrfs(HANDLE h, UINT64 size, PUNICODE_STRING label, UINT32 get_uuid(&fsuuid, &seed); get_uuid(&chunkuuid, &seed); #endif - + InitializeListHead(&roots); InitializeListHead(&chunks); - + root_root = add_root(&roots, BTRFS_ROOT_ROOT); chunk_root = add_root(&roots, BTRFS_ROOT_CHUNK); extent_root = add_root(&roots, BTRFS_ROOT_EXTENT); @@ -1142,65 +1211,72 @@ static NTSTATUS write_btrfs(HANDLE h, UINT64 size, PUNICODE_STRING label, UINT32 add_root(&roots, BTRFS_ROOT_CHECKSUM); fs_root = add_root(&roots, BTRFS_ROOT_FSTREE); reloc_root = add_root(&roots, BTRFS_ROOT_DATA_RELOC); - + #ifndef __REACTOS__ init_device(&dev, 1, size, &fsuuid, sector_size); #else init_device(&dev, 1, size, &fsuuid, sector_size, &seed); #endif - + ssd = is_ssd(h); - + sys_chunk = add_chunk(&chunks, BLOCK_FLAG_SYSTEM | (ssd ? 0 : BLOCK_FLAG_DUPLICATE), chunk_root, &dev, dev_root, &chunkuuid, sector_size); if (!sys_chunk) return STATUS_INTERNAL_ERROR; - - metadata_chunk = add_chunk(&chunks, BLOCK_FLAG_METADATA | (ssd ? 0 : BLOCK_FLAG_DUPLICATE), chunk_root, &dev, dev_root, &chunkuuid, sector_size); + + metadata_flags = BLOCK_FLAG_METADATA; + + if (!ssd && !(incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS)) + metadata_flags |= BLOCK_FLAG_DUPLICATE; + + if (incompat_flags & BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS) + metadata_flags |= BLOCK_FLAG_DATA; + + metadata_chunk = add_chunk(&chunks, metadata_flags, chunk_root, &dev, dev_root, &chunkuuid, sector_size); if (!metadata_chunk) return STATUS_INTERNAL_ERROR; - - node_size = 0x4000; - assign_addresses(&roots, sys_chunk, metadata_chunk, node_size, root_root, extent_root); - + add_item(chunk_root, 1, TYPE_DEV_ITEM, dev.dev_item.dev_id, &dev.dev_item, sizeof(DEV_ITEM)); - + init_fs_tree(fs_root, node_size); init_fs_tree(reloc_root, node_size); - + + assign_addresses(&roots, sys_chunk, metadata_chunk, node_size, root_root, extent_root, incompat_flags & BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA); + add_block_group_items(&chunks, extent_root); - + Status = write_roots(h, &roots, node_size, &fsuuid, &chunkuuid); if (!NT_SUCCESS(Status)) return Status; - + Status = clear_first_megabyte(h); if (!NT_SUCCESS(Status)) return Status; - - Status = write_superblocks(h, &dev, chunk_root, root_root, extent_root, sys_chunk, node_size, &fsuuid, sector_size, label); + + Status = write_superblocks(h, &dev, chunk_root, root_root, extent_root, sys_chunk, node_size, &fsuuid, sector_size, label, incompat_flags); if (!NT_SUCCESS(Status)) return Status; - + free_roots(&roots); free_chunks(&chunks); - + return STATUS_SUCCESS; } static BOOL look_for_device(btrfs_filesystem* bfs, BTRFS_UUID* devuuid) { UINT32 i; btrfs_filesystem_device* dev; - + for (i = 0; i < bfs->num_devices; i++) { if (i == 0) dev = &bfs->device; else dev = (btrfs_filesystem_device*)((UINT8*)dev + offsetof(btrfs_filesystem_device, name[0]) + dev->name_length); - + if (RtlCompareMemory(&dev->uuid, devuuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) return TRUE; } - + return FALSE; } @@ -1218,21 +1294,21 @@ static BOOL is_mounted_multi_device(HANDLE h, UINT32 sector_size) { btrfs_filesystem *bfs = NULL, *bfs2; ULONG bfssize; BOOL ret = FALSE; - + static WCHAR btrfs[] = L"\\Btrfs"; - + sblen = sizeof(sb); if (sblen & (sector_size - 1)) sblen = (sblen & sector_size) + sector_size; - + #ifndef __REACTOS__ sb = malloc(sblen); #else sb = RtlAllocateHeap(RtlGetProcessHeap(), 0, sblen); #endif - + off.QuadPart = superblock_addrs[0]; - + Status = NtReadFile(h, NULL, NULL, NULL, &iosb, sb, sblen, &off, NULL); if (!NT_SUCCESS(Status)) { #ifndef __REACTOS__ @@ -1242,7 +1318,7 @@ static BOOL is_mounted_multi_device(HANDLE h, UINT32 sector_size) { #endif return FALSE; } - + if (sb->magic != BTRFS_MAGIC) { #ifndef __REACTOS__ free(sb); @@ -1251,7 +1327,7 @@ static BOOL is_mounted_multi_device(HANDLE h, UINT32 sector_size) { #endif return FALSE; } - + crc32 = ~calc_crc32c(0xffffffff, (UINT8*)&sb->uuid, (ULONG)sizeof(superblock) - sizeof(sb->checksum)); if (crc32 != *((UINT32*)sb)) { #ifndef __REACTOS__ @@ -1261,31 +1337,31 @@ static BOOL is_mounted_multi_device(HANDLE h, UINT32 sector_size) { #endif return FALSE; } - + fsuuid = sb->uuid; devuuid = sb->dev_item.device_uuid; - + #ifndef __REACTOS__ free(sb); #else RtlFreeHeap(RtlGetProcessHeap(), 0, sb); #endif - + us.Length = us.MaximumLength = wcslen(btrfs) * sizeof(WCHAR); us.Buffer = btrfs; - + InitializeObjectAttributes(&atts, &us, 0, NULL, NULL); - + Status = NtOpenFile(&h2, SYNCHRONIZE | FILE_READ_ATTRIBUTES, &atts, &iosb, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT); if (!NT_SUCCESS(Status)) // not a problem, it usually just means the driver isn't loaded return FALSE; - + bfssize = 0; - + do { bfssize += 1024; - + #ifndef __REACTOS__ if (bfs) free(bfs); bfs = malloc(bfssize); @@ -1293,17 +1369,17 @@ static BOOL is_mounted_multi_device(HANDLE h, UINT32 sector_size) { if (bfs) RtlFreeHeap(RtlGetProcessHeap(), 0, bfs); bfs = RtlAllocateHeap(RtlGetProcessHeap(), 0, bfssize); #endif - + Status = NtDeviceIoControlFile(h2, NULL, NULL, NULL, &iosb, IOCTL_BTRFS_QUERY_FILESYSTEMS, NULL, 0, bfs, bfssize); if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) { NtClose(h2); return FALSE; } } while (Status == STATUS_BUFFER_OVERFLOW); - + if (!NT_SUCCESS(Status)) goto end; - + if (bfs->num_devices != 0) { bfs2 = bfs; while (TRUE) { @@ -1312,162 +1388,265 @@ static BOOL is_mounted_multi_device(HANDLE h, UINT32 sector_size) { ret = FALSE; else ret = look_for_device(bfs2, &devuuid); - + goto end; } - + if (bfs2->next_entry == 0) break; else bfs2 = (btrfs_filesystem*)((UINT8*)bfs2 + bfs2->next_entry); } } - + end: NtClose(h2); - + if (bfs) #ifndef __REACTOS__ free(bfs); #else RtlFreeHeap(RtlGetProcessHeap(), 0, bfs); #endif - + return ret; } -static void add_drive_letter(HANDLE h) { - NTSTATUS Status; +static void do_full_trim(HANDLE h) { IO_STATUS_BLOCK iosb; - MOUNTDEV_NAME mdn, *mdn2; - UNICODE_STRING us; - OBJECT_ATTRIBUTES attr; - HANDLE mountmgr; - MOUNTMGR_DRIVE_LETTER_INFORMATION mdli; - - Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &mdn, sizeof(mdn)); - if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) - return; - -#ifndef __REACTOS__ - mdn2 = malloc(offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength); -#else - mdn2 = RtlAllocateHeap(RtlGetProcessHeap(), 0, offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength); -#endif - - Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, mdn2, offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength); - if (!NT_SUCCESS(Status)) - goto end; - - RtlInitUnicodeString(&us, MOUNTMGR_DEVICE_NAME); - InitializeObjectAttributes(&attr, &us, 0, NULL, NULL); - - Status = NtOpenFile(&mountmgr, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb, - FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT); - - if (!NT_SUCCESS(Status)) - goto end; - - // MOUNTDEV_NAME is identical to MOUNTMGR_TARGET_NAME - Status = NtDeviceIoControlFile(mountmgr, NULL, NULL, NULL, &iosb, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, - mdn2, offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength, NULL, 0); - if (!NT_SUCCESS(Status)) - goto end2; - - // MOUNTDEV_NAME is identical to MOUNTMGR_DRIVE_LETTER_TARGET - Status = NtDeviceIoControlFile(mountmgr, NULL, NULL, NULL, &iosb, IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER, - mdn2, offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength, &mdli, sizeof(mdli)); - if (!NT_SUCCESS(Status)) - goto end2; + DEVICE_MANAGE_DATA_SET_ATTRIBUTES dmdsa; -end2: - NtClose(mountmgr); - -end: -#ifndef __REACTOS__ - free(mdn2); -#else - RtlFreeHeap(RtlGetProcessHeap(), 0, mdn2); -#endif + RtlZeroMemory(&dmdsa, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES)); + + dmdsa.Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES); + dmdsa.Action = DeviceDsmAction_Trim; + dmdsa.Flags = DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE | DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED; + dmdsa.ParameterBlockOffset = 0; + dmdsa.ParameterBlockLength = 0; + dmdsa.DataSetRangesOffset = 0; + dmdsa.DataSetRangesLength = 0; + + NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES, &dmdsa, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES), NULL, 0); +} + +static BOOL is_power_of_two(ULONG i) { + return ((i != 0) && !(i & (i - 1))); } #ifndef __REACTOS__ -NTSTATUS NTAPI FormatEx(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFlag, PUNICODE_STRING Label, +static NTSTATUS NTAPI FormatEx2(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFlag, PUNICODE_STRING Label, #else NTSTATUS NTAPI BtrfsFormatEx(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFlag, PUNICODE_STRING Label, #endif - BOOLEAN QuickFormat, ULONG ClusterSize, PFMIFSCALLBACK Callback) + BOOLEAN QuickFormat, ULONG ClusterSize, PFMIFSCALLBACK Callback) { NTSTATUS Status; - HANDLE h; + HANDLE h, btrfsh; OBJECT_ATTRIBUTES attr; IO_STATUS_BLOCK iosb; GET_LENGTH_INFORMATION gli; - DISK_GEOMETRY_EX dgex; - UINT32 sector_size; - - InitializeObjectAttributes(&attr, DriveRoot, 0, NULL, NULL); - + DISK_GEOMETRY dg; + UINT32 sector_size, node_size; + UNICODE_STRING btrfsus; +#ifndef __REACTOS__ + HANDLE token; + TOKEN_PRIVILEGES tp; + LUID luid; +#endif + UINT64 incompat_flags; + + static WCHAR btrfs[] = L"\\Btrfs"; + +#ifndef __REACTOS__ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) + return STATUS_PRIVILEGE_NOT_HELD; + + if (!LookupPrivilegeValueW(NULL, L"SeManageVolumePrivilege", &luid)) { + CloseHandle(token); + return STATUS_PRIVILEGE_NOT_HELD; + } + + tp.PrivilegeCount = 1; + tp.Privileges[0].Luid = luid; + tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { + CloseHandle(token); + return STATUS_PRIVILEGE_NOT_HELD; + } + + CloseHandle(token); +#endif + + InitializeObjectAttributes(&attr, DriveRoot, OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = NtOpenFile(&h, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT); - + if (!NT_SUCCESS(Status)) return Status; - + Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli)); if (!NT_SUCCESS(Status)) { NtClose(h); return Status; } - Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &dgex, sizeof(dgex)); + // MSDN tells us to use IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, but there are + // some instances where it fails and IOCTL_DISK_GET_DRIVE_GEOMETRY succeeds - + // such as with spanned volumes. + Status = NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(dg)); if (!NT_SUCCESS(Status)) { NtClose(h); return Status; } - - sector_size = dgex.Geometry.BytesPerSector; - - if (sector_size == 0x200 || sector_size == 0) - sector_size = 0x1000; - + + if (def_sector_size == 0) { + sector_size = dg.BytesPerSector; + + if (sector_size == 0x200 || sector_size == 0) + sector_size = 0x1000; + } else { + if (dg.BytesPerSector != 0 && (def_sector_size < dg.BytesPerSector || def_sector_size % dg.BytesPerSector != 0 || !is_power_of_two(def_sector_size / dg.BytesPerSector))) { + NtClose(h); + return STATUS_INVALID_PARAMETER; + } + + sector_size = def_sector_size; + } + + if (def_node_size == 0) + node_size = 0x4000; + else { + if (def_node_size < sector_size || def_node_size % sector_size != 0 || !is_power_of_two(def_node_size / sector_size)) { + NtClose(h); + return STATUS_INVALID_PARAMETER; + } + + node_size = def_node_size; + } + if (Callback) { ULONG pc = 0; Callback(PROGRESS, 0, (PVOID)&pc); } - + NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0); - + if (is_mounted_multi_device(h, sector_size)) { Status = STATUS_ACCESS_DENIED; goto end; } - - Status = write_btrfs(h, gli.Length.QuadPart, Label, sector_size); - + + do_full_trim(h); + + incompat_flags = def_incompat_flags; + incompat_flags |= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF | BTRFS_INCOMPAT_FLAGS_BIG_METADATA; + + Status = write_btrfs(h, gli.Length.QuadPart, Label, sector_size, node_size, incompat_flags); + NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0); - + end: NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0); - - if (NT_SUCCESS(Status)) - add_drive_letter(h); - + NtClose(h); - + + if (NT_SUCCESS(Status)) { + btrfsus.Buffer = btrfs; + btrfsus.Length = btrfsus.MaximumLength = wcslen(btrfs) * sizeof(WCHAR); + + InitializeObjectAttributes(&attr, &btrfsus, 0, NULL, NULL); + + Status = NtOpenFile(&btrfsh, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb, + FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT); + + if (NT_SUCCESS(Status)) { + MOUNTDEV_NAME* mdn; + ULONG mdnsize; + + mdnsize = offsetof(MOUNTDEV_NAME, Name[0]) + DriveRoot->Length; +#ifndef __REACTOS__ + mdn = malloc(mdnsize); +#else + mdn = RtlAllocateHeap(RtlGetProcessHeap(), 0, mdnsize); +#endif + + mdn->NameLength = DriveRoot->Length; + memcpy(mdn->Name, DriveRoot->Buffer, DriveRoot->Length); + + NtDeviceIoControlFile(btrfsh, NULL, NULL, NULL, &iosb, IOCTL_BTRFS_PROBE_VOLUME, mdn, mdnsize, NULL, 0); + +#ifndef __REACTOS__ + free(mdn); +#else + RtlFreeHeap(RtlGetProcessHeap(), 0, mdn); +#endif + + NtClose(btrfsh); + } + + Status = STATUS_SUCCESS; + } + if (Callback) { BOOL success = NT_SUCCESS(Status); Callback(DONE, 0, (PVOID)&success); } - + return Status; } +BOOL __stdcall FormatEx(DSTRING* root, STREAM_MESSAGE* message, options* opts, UINT32 unk1) { + UNICODE_STRING DriveRoot, Label; + NTSTATUS Status; + + if (!root || !root->string) + return FALSE; + + DriveRoot.Length = DriveRoot.MaximumLength = wcslen(root->string) * sizeof(WCHAR); + DriveRoot.Buffer = root->string; + + if (opts && opts->label && opts->label->string) { + Label.Length = Label.MaximumLength = wcslen(opts->label->string) * sizeof(WCHAR); + Label.Buffer = opts->label->string; + } else { + Label.Length = Label.MaximumLength = 0; + Label.Buffer = NULL; + } + +#ifndef __REACTOS__ + Status = FormatEx2(&DriveRoot, FMIFS_HARDDISK, &Label, opts && opts->flags & FORMAT_FLAG_QUICK_FORMAT, 0, NULL); +#else + Status = BtrfsFormatEx(&DriveRoot, FMIFS_HARDDISK, &Label, opts && opts->flags & FORMAT_FLAG_QUICK_FORMAT, 0, NULL); +#endif + + return NT_SUCCESS(Status); +} + +void __stdcall SetSizes(ULONG sector, ULONG node) { + if (sector != 0) + def_sector_size = sector; + + if (node != 0) + def_node_size = node; +} + +void __stdcall SetIncompatFlags(UINT64 incompat_flags) { + def_incompat_flags = incompat_flags; +} + +BOOL __stdcall GetFilesystemInformation(UINT32 unk1, UINT32 unk2, void* unk3) { + // STUB - undocumented + + return TRUE; +} + #ifndef __REACTOS__ BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) { if (dwReason == DLL_PROCESS_ATTACH) module = (HMODULE)hModule; - + return TRUE; } #endif -- 2.17.1