mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 15:23:03 +00:00
[BTRFSLIB]
Sync to 1.0 CORE-13763 svn path=/trunk/; revision=75796
This commit is contained in:
parent
925c2e9d2f
commit
8e31783cb7
3 changed files with 511 additions and 329 deletions
|
@ -5,7 +5,7 @@ The following FSD are shared with: https://github.com/maharmstone/btrfs.
|
||||||
|
|
||||||
reactos/drivers/filesystems/btrfs # Synced to 1.0
|
reactos/drivers/filesystems/btrfs # Synced to 1.0
|
||||||
reactos/dll/shellext/shellbtrfs # 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/
|
The following FSD are shared with: http://www.ext2fsd.com/
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${REACTOS_SOURCE_DIR}/drivers/filesystems/btrfs)
|
||||||
|
|
||||||
add_library(btrfslib btrfslib.c)
|
add_library(btrfslib btrfslib.c)
|
||||||
add_dependencies(btrfslib psdk)
|
add_dependencies(btrfslib psdk)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (c) Mark Harmstone 2016
|
/* Copyright (c) Mark Harmstone 2016-17
|
||||||
*
|
*
|
||||||
* This file is part of WinBtrfs.
|
* This file is part of WinBtrfs.
|
||||||
*
|
*
|
||||||
|
@ -32,11 +32,12 @@
|
||||||
#include <ndk/rtlfuncs.h>
|
#include <ndk/rtlfuncs.h>
|
||||||
#endif
|
#endif
|
||||||
#include <ntddscsi.h>
|
#include <ntddscsi.h>
|
||||||
|
#include <ntddstor.h>
|
||||||
#include <ata.h>
|
#include <ata.h>
|
||||||
#include <mountmgr.h>
|
#include <mountmgr.h>
|
||||||
#ifdef __REACTOS__
|
#ifdef __REACTOS__
|
||||||
#include "../../drivers/filesystems/btrfs/btrfs.h"
|
#include "btrfs.h"
|
||||||
#include "../../drivers/filesystems/btrfs/btrfsioctl.h"
|
#include "btrfsioctl.h"
|
||||||
#else
|
#else
|
||||||
#include "../btrfs.h"
|
#include "../btrfs.h"
|
||||||
#include "../btrfsioctl.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_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_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)
|
#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
|
#endif
|
||||||
|
|
||||||
#ifndef __REACTOS__
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -65,7 +68,34 @@ NTSYSAPI NTSTATUS NTAPI RtlUnicodeToUTF8N(PCHAR UTF8StringDestination, ULONG UTF
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
FORCEINLINE VOID InitializeListHead(PLIST_ENTRY ListHead) {
|
||||||
ListHead->Flink = ListHead->Blink = ListHead;
|
ListHead->Flink = ListHead->Blink = ListHead;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +159,8 @@ typedef struct {
|
||||||
0))))))
|
0))))))
|
||||||
|
|
||||||
HMODULE module;
|
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
|
// 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->size = size;
|
||||||
c->chunk_item->root_id = BTRFS_ROOT_EXTENT;
|
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->type = flags;
|
||||||
c->chunk_item->opt_io_alignment = 0x10000;
|
c->chunk_item->opt_io_alignment = max(sector_size, 0x10000);
|
||||||
c->chunk_item->opt_io_width = 0x10000;
|
c->chunk_item->opt_io_width = max(sector_size, 0x10000);
|
||||||
c->chunk_item->sector_size = sector_size;
|
c->chunk_item->sector_size = sector_size;
|
||||||
c->chunk_item->num_stripes = stripes;
|
c->chunk_item->num_stripes = stripes;
|
||||||
c->chunk_item->sub_stripes = 0;
|
c->chunk_item->sub_stripes = 0;
|
||||||
|
@ -507,29 +539,61 @@ typedef struct {
|
||||||
TREE_BLOCK_REF tbr;
|
TREE_BLOCK_REF tbr;
|
||||||
} EXTENT_ITEM_METADATA;
|
} 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,
|
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;
|
LIST_ENTRY* le;
|
||||||
|
|
||||||
le = roots->Flink;
|
le = roots->Flink;
|
||||||
while (le != roots) {
|
while (le != roots) {
|
||||||
btrfs_root* r = CONTAINING_RECORD(le, btrfs_root, list_entry);
|
btrfs_root* r = CONTAINING_RECORD(le, btrfs_root, list_entry);
|
||||||
btrfs_chunk* c = r->id == BTRFS_ROOT_CHUNK ? sys_chunk : metadata_chunk;
|
btrfs_chunk* c = r->id == BTRFS_ROOT_CHUNK ? sys_chunk : metadata_chunk;
|
||||||
EXTENT_ITEM_METADATA eim;
|
|
||||||
|
|
||||||
r->header.address = get_next_address(c);
|
r->header.address = get_next_address(c);
|
||||||
r->c = c;
|
r->c = c;
|
||||||
c->lastoff = r->header.address + node_size;
|
c->lastoff = r->header.address + node_size;
|
||||||
c->used += node_size;
|
c->used += node_size;
|
||||||
|
|
||||||
|
if (skinny) {
|
||||||
|
EXTENT_ITEM_METADATA eim;
|
||||||
|
|
||||||
eim.ei.refcount = 1;
|
eim.ei.refcount = 1;
|
||||||
eim.ei.generation = 1;
|
eim.ei.generation = 1;
|
||||||
eim.ei.flags = EXTENT_ITEM_TREE_BLOCK;
|
eim.ei.flags = EXTENT_ITEM_TREE_BLOCK;
|
||||||
eim.type = TYPE_TREE_BLOCK_REF;
|
eim.type = TYPE_TREE_BLOCK_REF;
|
||||||
eim.tbr.offset = r->id;
|
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));
|
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) {
|
if (r->id != BTRFS_ROOT_ROOT && r->id != BTRFS_ROOT_CHUNK) {
|
||||||
ROOT_ITEM ri;
|
ROOT_ITEM ri;
|
||||||
|
@ -812,7 +876,7 @@ NTSTATUS NTAPI RtlUnicodeToUTF8N(CHAR *utf8_dest, ULONG utf8_bytes_max,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static NTSTATUS write_superblocks(HANDLE h, btrfs_dev* dev, btrfs_root* chunk_root, btrfs_root* root_root, btrfs_root* extent_root,
|
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;
|
NTSTATUS Status;
|
||||||
IO_STATUS_BLOCK iosb;
|
IO_STATUS_BLOCK iosb;
|
||||||
ULONG sblen;
|
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->stripe_size = sector_size;
|
||||||
sb->n = sizeof(KEY) + sizeof(CHUNK_ITEM) + (sys_chunk->chunk_item->num_stripes * sizeof(CHUNK_ITEM_STRIPE));
|
sb->n = sizeof(KEY) + sizeof(CHUNK_ITEM) + (sys_chunk->chunk_item->num_stripes * sizeof(CHUNK_ITEM_STRIPE));
|
||||||
sb->chunk_root_generation = 1;
|
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));
|
memcpy(&sb->dev_item, &dev->dev_item, sizeof(DEV_ITEM));
|
||||||
|
|
||||||
if (label->Length > 0) {
|
if (label->Length > 0) {
|
||||||
|
@ -984,9 +1048,6 @@ GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime)
|
||||||
static void init_fs_tree(btrfs_root* r, UINT32 node_size) {
|
static void init_fs_tree(btrfs_root* r, UINT32 node_size) {
|
||||||
INODE_ITEM ii;
|
INODE_ITEM ii;
|
||||||
INODE_REF* ir;
|
INODE_REF* ir;
|
||||||
#ifndef __REACTOS__
|
|
||||||
SYSTEMTIME systime;
|
|
||||||
#endif
|
|
||||||
FILETIME filetime;
|
FILETIME filetime;
|
||||||
LARGE_INTEGER time;
|
LARGE_INTEGER time;
|
||||||
|
|
||||||
|
@ -997,12 +1058,7 @@ static void init_fs_tree(btrfs_root* r, UINT32 node_size) {
|
||||||
ii.st_nlink = 1;
|
ii.st_nlink = 1;
|
||||||
ii.st_mode = 040755;
|
ii.st_mode = 040755;
|
||||||
|
|
||||||
#ifndef __REACTOS__
|
|
||||||
GetSystemTime(&systime);
|
|
||||||
SystemTimeToFileTime(&systime, &filetime);
|
|
||||||
#else
|
|
||||||
GetSystemTimeAsFileTime(&filetime);
|
GetSystemTimeAsFileTime(&filetime);
|
||||||
#endif
|
|
||||||
time.LowPart = filetime.dwLowDateTime;
|
time.LowPart = filetime.dwLowDateTime;
|
||||||
time.HighPart = filetime.dwHighDateTime;
|
time.HighPart = filetime.dwHighDateTime;
|
||||||
|
|
||||||
|
@ -1054,12 +1110,13 @@ static NTSTATUS clear_first_megabyte(HANDLE h) {
|
||||||
LARGE_INTEGER zero;
|
LARGE_INTEGER zero;
|
||||||
UINT8* mb;
|
UINT8* mb;
|
||||||
|
|
||||||
|
|
||||||
#ifndef __REACTOS__
|
#ifndef __REACTOS__
|
||||||
mb = malloc(0x100000);
|
mb = malloc(0x100000);
|
||||||
#else
|
|
||||||
mb = RtlAllocateHeap(RtlGetProcessHeap(), 0, 0x100000);
|
|
||||||
#endif
|
|
||||||
memset(mb, 0, 0x100000);
|
memset(mb, 0, 0x100000);
|
||||||
|
#else
|
||||||
|
mb = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x100000);
|
||||||
|
#endif
|
||||||
|
|
||||||
zero.QuadPart = 0;
|
zero.QuadPart = 0;
|
||||||
|
|
||||||
|
@ -1102,22 +1159,34 @@ static BOOL is_ssd(HANDLE h) {
|
||||||
if (NT_SUCCESS(Status)) {
|
if (NT_SUCCESS(Status)) {
|
||||||
idd = (IDENTIFY_DEVICE_DATA*)((UINT8*)apte + sizeof(ATA_PASS_THROUGH_EX));
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef __REACTOS__
|
||||||
|
free(apte);
|
||||||
|
#else
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, apte);
|
||||||
|
#endif
|
||||||
|
|
||||||
return FALSE;
|
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;
|
NTSTATUS Status;
|
||||||
UINT32 node_size;
|
|
||||||
LIST_ENTRY roots, chunks;
|
LIST_ENTRY roots, chunks;
|
||||||
btrfs_root *root_root, *chunk_root, *extent_root, *dev_root, *fs_root, *reloc_root;
|
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_dev dev;
|
||||||
BTRFS_UUID fsuuid, chunkuuid;
|
BTRFS_UUID fsuuid, chunkuuid;
|
||||||
BOOL ssd;
|
BOOL ssd;
|
||||||
|
UINT64 metadata_flags;
|
||||||
#ifdef __REACTOS__
|
#ifdef __REACTOS__
|
||||||
ULONG seed;
|
ULONG seed;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1155,18 +1224,25 @@ static NTSTATUS write_btrfs(HANDLE h, UINT64 size, PUNICODE_STRING label, UINT32
|
||||||
if (!sys_chunk)
|
if (!sys_chunk)
|
||||||
return STATUS_INTERNAL_ERROR;
|
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)
|
if (!metadata_chunk)
|
||||||
return STATUS_INTERNAL_ERROR;
|
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));
|
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(fs_root, node_size);
|
||||||
init_fs_tree(reloc_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);
|
add_block_group_items(&chunks, extent_root);
|
||||||
|
|
||||||
Status = write_roots(h, &roots, node_size, &fsuuid, &chunkuuid);
|
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))
|
if (!NT_SUCCESS(Status))
|
||||||
return 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))
|
if (!NT_SUCCESS(Status))
|
||||||
return Status;
|
return Status;
|
||||||
|
|
||||||
|
@ -1336,77 +1412,73 @@ end:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_drive_letter(HANDLE h) {
|
static void do_full_trim(HANDLE h) {
|
||||||
NTSTATUS Status;
|
|
||||||
IO_STATUS_BLOCK iosb;
|
IO_STATUS_BLOCK iosb;
|
||||||
MOUNTDEV_NAME mdn, *mdn2;
|
DEVICE_MANAGE_DATA_SET_ATTRIBUTES dmdsa;
|
||||||
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));
|
RtlZeroMemory(&dmdsa, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES));
|
||||||
if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW)
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifndef __REACTOS__
|
dmdsa.Size = sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES);
|
||||||
mdn2 = malloc(offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength);
|
dmdsa.Action = DeviceDsmAction_Trim;
|
||||||
#else
|
dmdsa.Flags = DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE | DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED;
|
||||||
mdn2 = RtlAllocateHeap(RtlGetProcessHeap(), 0, offsetof(MOUNTDEV_NAME, Name[0]) + mdn.NameLength);
|
dmdsa.ParameterBlockOffset = 0;
|
||||||
#endif
|
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);
|
NtDeviceIoControlFile(h, NULL, NULL, NULL, &iosb, IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES, &dmdsa, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES), NULL, 0);
|
||||||
if (!NT_SUCCESS(Status))
|
}
|
||||||
goto end;
|
|
||||||
|
|
||||||
RtlInitUnicodeString(&us, MOUNTMGR_DEVICE_NAME);
|
static BOOL is_power_of_two(ULONG i) {
|
||||||
InitializeObjectAttributes(&attr, &us, 0, NULL, NULL);
|
return ((i != 0) && !(i & (i - 1)));
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __REACTOS__
|
#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
|
#else
|
||||||
NTSTATUS NTAPI BtrfsFormatEx(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFlag, PUNICODE_STRING Label,
|
NTSTATUS NTAPI BtrfsFormatEx(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFlag, PUNICODE_STRING Label,
|
||||||
#endif
|
#endif
|
||||||
BOOLEAN QuickFormat, ULONG ClusterSize, PFMIFSCALLBACK Callback)
|
BOOLEAN QuickFormat, ULONG ClusterSize, PFMIFSCALLBACK Callback)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
HANDLE h;
|
HANDLE h, btrfsh;
|
||||||
OBJECT_ATTRIBUTES attr;
|
OBJECT_ATTRIBUTES attr;
|
||||||
IO_STATUS_BLOCK iosb;
|
IO_STATUS_BLOCK iosb;
|
||||||
GET_LENGTH_INFORMATION gli;
|
GET_LENGTH_INFORMATION gli;
|
||||||
DISK_GEOMETRY_EX dgex;
|
DISK_GEOMETRY dg;
|
||||||
UINT32 sector_size;
|
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,
|
Status = NtOpenFile(&h, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &attr, &iosb,
|
||||||
FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT);
|
FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_ALERT);
|
||||||
|
@ -1420,16 +1492,39 @@ NTSTATUS NTAPI BtrfsFormatEx(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFl
|
||||||
return Status;
|
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)) {
|
if (!NT_SUCCESS(Status)) {
|
||||||
NtClose(h);
|
NtClose(h);
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
sector_size = dgex.Geometry.BytesPerSector;
|
if (def_sector_size == 0) {
|
||||||
|
sector_size = dg.BytesPerSector;
|
||||||
|
|
||||||
if (sector_size == 0x200 || sector_size == 0)
|
if (sector_size == 0x200 || sector_size == 0)
|
||||||
sector_size = 0x1000;
|
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) {
|
if (Callback) {
|
||||||
ULONG pc = 0;
|
ULONG pc = 0;
|
||||||
|
@ -1443,18 +1538,57 @@ NTSTATUS NTAPI BtrfsFormatEx(PUNICODE_STRING DriveRoot, FMIFS_MEDIA_FLAG MediaFl
|
||||||
goto end;
|
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);
|
NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0);
|
NtFsControlFile(h, NULL, NULL, NULL, &iosb, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0);
|
||||||
|
|
||||||
if (NT_SUCCESS(Status))
|
|
||||||
add_drive_letter(h);
|
|
||||||
|
|
||||||
NtClose(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) {
|
if (Callback) {
|
||||||
BOOL success = NT_SUCCESS(Status);
|
BOOL success = NT_SUCCESS(Status);
|
||||||
Callback(DONE, 0, (PVOID)&success);
|
Callback(DONE, 0, (PVOID)&success);
|
||||||
|
@ -1463,6 +1597,51 @@ end:
|
||||||
return Status;
|
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__
|
#ifndef __REACTOS__
|
||||||
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) {
|
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved) {
|
||||||
if (dwReason == DLL_PROCESS_ATTACH)
|
if (dwReason == DLL_PROCESS_ATTACH)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue