[BTRFSLIB]

Sync to 1.0

CORE-13763

svn path=/trunk/; revision=75796
This commit is contained in:
Pierre Schweitzer 2017-09-08 16:31:32 +00:00
parent 925c2e9d2f
commit 8e31783cb7
3 changed files with 511 additions and 329 deletions

View file

@ -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/

View file

@ -1,3 +1,6 @@
include_directories(
${REACTOS_SOURCE_DIR}/drivers/filesystems/btrfs)
add_library(btrfslib btrfslib.c)
add_dependencies(btrfslib psdk)

View file

@ -1,4 +1,4 @@
/* Copyright (c) Mark Harmstone 2016
/* Copyright (c) Mark Harmstone 2016-17
*
* This file is part of WinBtrfs.
*
@ -32,11 +32,12 @@
#include <ndk/rtlfuncs.h>
#endif
#include <ntddscsi.h>
#include <ntddstor.h>
#include <ata.h>
#include <mountmgr.h>
#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
@ -442,10 +474,10 @@ static btrfs_chunk* add_chunk(LIST_ENTRY* chunks, UINT64 flags, btrfs_root* chun
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;
@ -507,29 +539,61 @@ 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;
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;
// FIXME - support non-skinny EXTENT_ITEM
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;
@ -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;
@ -864,7 +928,7 @@ 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) {
@ -984,9 +1048,6 @@ 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;
@ -997,12 +1058,7 @@ static void init_fs_tree(btrfs_root* r, UINT32 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;
@ -1054,12 +1110,13 @@ static NTSTATUS clear_first_megabyte(HANDLE h) {
LARGE_INTEGER zero;
UINT8* mb;
#ifndef __REACTOS__
mb = malloc(0x100000);
#else
mb = RtlAllocateHeap(RtlGetProcessHeap(), 0, 0x100000);
#endif
memset(mb, 0, 0x100000);
#else
mb = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x100000);
#endif
zero.QuadPart = 0;
@ -1102,22 +1159,34 @@ static BOOL is_ssd(HANDLE h) {
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_dev dev;
BTRFS_UUID fsuuid, chunkuuid;
BOOL ssd;
UINT64 metadata_flags;
#ifdef __REACTOS__
ULONG seed;
#endif
@ -1155,18 +1224,25 @@ static NTSTATUS write_btrfs(HANDLE h, UINT64 size, PUNICODE_STRING label, UINT32
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);
@ -1177,7 +1253,7 @@ static NTSTATUS write_btrfs(HANDLE h, UINT64 size, PUNICODE_STRING label, UINT32
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;
@ -1336,77 +1412,73 @@ end:
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;
DEVICE_MANAGE_DATA_SET_ATTRIBUTES dmdsa;
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;
RtlZeroMemory(&dmdsa, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES));
#ifndef __REACTOS__
mdn2 = malloc(offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength);
#else
mdn2 = RtlAllocateHeap(RtlGetProcessHeap(), 0, offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength);
#endif
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;
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;
NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES, &dmdsa, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES), NULL, 0);
}
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;
end2:
NtClose(mountmgr);
end:
#ifndef __REACTOS__
free(mdn2);
#else
RtlFreeHeap(RtlGetProcessHeap(), 0, mdn2);
#endif
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)
{
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;
DISK_GEOMETRY dg;
UINT32 sector_size, node_size;
UNICODE_STRING btrfsus;
#ifndef __REACTOS__
HANDLE token;
TOKEN_PRIVILEGES tp;
LUID luid;
#endif
UINT64 incompat_flags;
InitializeObjectAttributes(&attr, DriveRoot, 0, NULL, NULL);
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);
@ -1420,16 +1492,39 @@ NTSTATUS NTAPI BtrfsFormatEx(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFl
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 (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;
@ -1443,18 +1538,57 @@ NTSTATUS NTAPI BtrfsFormatEx(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFl
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);
@ -1463,6 +1597,51 @@ end:
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)