1 /* Copyright (c) Mark Harmstone 2016-17
3 * This file is part of WinBtrfs.
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
22 #define WIN32_NO_STATUS
30 #include <ndk/iofuncs.h>
31 #include <ndk/obfuncs.h>
32 #include <ndk/rtlfuncs.h>
42 #include "btrfsioctl.h"
46 #include <stringapiset.h>
49 #include "../btrfsioctl.h"
50 #include "../crc32c.h"
51 #include "../xxhash.h"
53 #if defined(_X86_) || defined(_AMD64_)
63 #define malloc(size) RtlAllocateHeap(RtlGetProcessHeap(), 0, (size))
64 #define free(ptr) RtlFreeHeap(RtlGetProcessHeap(), 0, (ptr))
67 #define SHA256_HASH_SIZE 32
68 void calc_sha256(uint8_t* hash
, const void* input
, size_t len
);
70 #define BLAKE2_HASH_SIZE 32
71 void blake2b(void *out
, size_t outlen
, const void* in
, size_t inlen
);
74 #define FSCTL_LOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
75 #define FSCTL_UNLOCK_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
76 #define FSCTL_DISMOUNT_VOLUME CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
78 #ifndef _MSC_VER // not in mingw yet
79 #define DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED 0x80000000
85 NTSTATUS NTAPI
NtWriteFile(HANDLE FileHandle
, HANDLE Event
, PIO_APC_ROUTINE ApcRoutine
, PVOID ApcContext
, PIO_STATUS_BLOCK IoStatusBlock
, PVOID Buffer
,
86 ULONG Length
, PLARGE_INTEGER ByteOffset
, PULONG Key
);
88 NTSTATUS NTAPI
NtReadFile(HANDLE FileHandle
, HANDLE Event
, PIO_APC_ROUTINE ApcRoutine
, PVOID ApcContext
, PIO_STATUS_BLOCK IoStatusBlock
, PVOID Buffer
,
89 ULONG Length
, PLARGE_INTEGER ByteOffset
, PULONG Key
);
95 // These are undocumented, and what comes from format.exe
106 #define FORMAT_FLAG_QUICK_FORMAT 0x00000001
107 #define FORMAT_FLAG_UNKNOWN1 0x00000002
108 #define FORMAT_FLAG_DISMOUNT_FIRST 0x00000004
109 #define FORMAT_FLAG_UNKNOWN2 0x00000040
110 #define FORMAT_FLAG_LARGE_RECORDS 0x00000100
111 #define FORMAT_FLAG_INTEGRITY_DISABLE 0x00000100
121 FORCEINLINE VOID
InitializeListHead(PLIST_ENTRY ListHead
) {
122 ListHead
->Flink
= ListHead
->Blink
= ListHead
;
125 FORCEINLINE VOID
InsertTailList(PLIST_ENTRY ListHead
, PLIST_ENTRY Entry
) {
128 Blink
= ListHead
->Blink
;
129 Entry
->Flink
= ListHead
;
130 Entry
->Blink
= Blink
;
131 Blink
->Flink
= Entry
;
132 ListHead
->Blink
= Entry
;
137 ULONG NTAPI
NtGetTickCount(VOID
);
144 LIST_ENTRY list_entry
;
149 CHUNK_ITEM
* chunk_item
;
152 LIST_ENTRY list_entry
;
160 LIST_ENTRY list_entry
;
168 #define keycmp(key1, key2)\
169 ((key1.obj_id < key2.obj_id) ? -1 :\
170 ((key1.obj_id > key2.obj_id) ? 1 :\
171 ((key1.obj_type < key2.obj_type) ? -1 :\
172 ((key1.obj_type > key2.obj_type) ? 1 :\
173 ((key1.offset < key2.offset) ? -1 :\
174 ((key1.offset > key2.offset) ? 1 :\
178 ULONG def_sector_size
= 0, def_node_size
= 0;
179 uint64_t def_incompat_flags
= BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF
| BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA
;
180 uint16_t def_csum_type
= CSUM_TYPE_CRC32C
;
183 // the following definitions come from fmifs.h in ReactOS
188 } TEXTOUTPUT
, *PTEXTOUTPUT
;
237 typedef BOOLEAN (NTAPI
* PFMIFSCALLBACK
)(CALLBACKCOMMAND Command
, ULONG SubAction
, PVOID ActionInfo
);
241 #include <fmifs/fmifs.h>
243 #endif // __REACTOS__
246 NTSTATUS WINAPI
ChkdskEx(PUNICODE_STRING DriveRoot
, BOOLEAN FixErrors
, BOOLEAN Verbose
, BOOLEAN CheckOnlyIfDirty
,
247 BOOLEAN ScanDrive
, PFMIFSCALLBACK Callback
) {
252 IN PUNICODE_STRING DriveRoot
,
253 IN PFMIFSCALLBACK Callback
,
254 IN BOOLEAN FixErrors
,
256 IN BOOLEAN CheckOnlyIfDirty
,
257 IN BOOLEAN ScanDrive
,
262 IN PULONG ExitStatus
)
271 TextOut
.Output
= "stub, not implemented";
273 Callback(OUTPUT
, 0, &TextOut
);
277 return STATUS_SUCCESS
;
279 *ExitStatus
= (ULONG
)STATUS_SUCCESS
;
284 static btrfs_root
* add_root(LIST_ENTRY
* roots
, uint64_t id
) {
287 root
= malloc(sizeof(btrfs_root
));
290 RtlZeroMemory(&root
->header
, sizeof(tree_header
));
291 InitializeListHead(&root
->items
);
292 InsertTailList(roots
, &root
->list_entry
);
297 static void free_roots(LIST_ENTRY
* roots
) {
301 while (le
!= roots
) {
302 LIST_ENTRY
*le2
= le
->Flink
, *le3
;
303 btrfs_root
* r
= CONTAINING_RECORD(le
, btrfs_root
, list_entry
);
305 le3
= r
->items
.Flink
;
306 while (le3
!= &r
->items
) {
307 LIST_ENTRY
* le4
= le3
->Flink
;
308 btrfs_item
* item
= CONTAINING_RECORD(le3
, btrfs_item
, list_entry
);
324 static void free_chunks(LIST_ENTRY
* chunks
) {
328 while (le
!= chunks
) {
329 LIST_ENTRY
*le2
= le
->Flink
;
330 btrfs_chunk
* c
= CONTAINING_RECORD(le
, btrfs_chunk
, list_entry
);
339 static void add_item(btrfs_root
* r
, uint64_t obj_id
, uint8_t obj_type
, uint64_t offset
, void* data
, uint16_t size
) {
343 item
= malloc(sizeof(btrfs_item
));
345 item
->key
.obj_id
= obj_id
;
346 item
->key
.obj_type
= obj_type
;
347 item
->key
.offset
= offset
;
353 item
->data
= malloc(size
);
354 memcpy(item
->data
, data
, size
);
358 while (le
!= &r
->items
) {
359 btrfs_item
* i2
= CONTAINING_RECORD(le
, btrfs_item
, list_entry
);
361 if (keycmp(item
->key
, i2
->key
) != 1) {
362 InsertTailList(le
, &item
->list_entry
);
369 InsertTailList(&r
->items
, &item
->list_entry
);
372 static uint64_t find_chunk_offset(uint64_t size
, uint64_t offset
, btrfs_dev
* dev
, btrfs_root
* dev_root
, BTRFS_UUID
* chunkuuid
) {
376 off
= dev
->last_alloc
;
377 dev
->last_alloc
+= size
;
379 dev
->dev_item
.bytes_used
+= size
;
381 de
.chunktree
= BTRFS_ROOT_CHUNK
;
385 de
.chunktree_uuid
= *chunkuuid
;
387 add_item(dev_root
, dev
->dev_item
.dev_id
, TYPE_DEV_EXTENT
, off
, &de
, sizeof(DEV_EXTENT
));
392 static btrfs_chunk
* add_chunk(LIST_ENTRY
* chunks
, uint64_t flags
, btrfs_root
* chunk_root
, btrfs_dev
* dev
, btrfs_root
* dev_root
, BTRFS_UUID
* chunkuuid
, uint32_t sector_size
) {
397 CHUNK_ITEM_STRIPE
* cis
;
401 while (le
!= chunks
) {
402 c
= CONTAINING_RECORD(le
, btrfs_chunk
, list_entry
);
404 if (c
->offset
+ c
->chunk_item
->size
> off
)
405 off
= c
->offset
+ c
->chunk_item
->size
;
410 if (flags
& BLOCK_FLAG_METADATA
) {
411 if (dev
->dev_item
.num_bytes
> 0xC80000000) // 50 GB
412 size
= 0x40000000; // 1 GB
414 size
= 0x10000000; // 256 MB
415 } else if (flags
& BLOCK_FLAG_SYSTEM
)
418 size
= min(size
, dev
->dev_item
.num_bytes
/ 10); // cap at 10%
419 size
&= ~(sector_size
- 1);
421 stripes
= flags
& BLOCK_FLAG_DUPLICATE
? 2 : 1;
423 if (dev
->dev_item
.num_bytes
- dev
->dev_item
.bytes_used
< stripes
* size
) // not enough space
426 c
= malloc(sizeof(btrfs_chunk
));
431 c
->chunk_item
= malloc(sizeof(CHUNK_ITEM
) + (stripes
* sizeof(CHUNK_ITEM_STRIPE
)));
433 c
->chunk_item
->size
= size
;
434 c
->chunk_item
->root_id
= BTRFS_ROOT_EXTENT
;
435 c
->chunk_item
->stripe_length
= max(sector_size
, 0x10000);
436 c
->chunk_item
->type
= flags
;
437 c
->chunk_item
->opt_io_alignment
= max(sector_size
, 0x10000);
438 c
->chunk_item
->opt_io_width
= max(sector_size
, 0x10000);
439 c
->chunk_item
->sector_size
= sector_size
;
440 c
->chunk_item
->num_stripes
= stripes
;
441 c
->chunk_item
->sub_stripes
= 0;
443 cis
= (CHUNK_ITEM_STRIPE
*)&c
->chunk_item
[1];
445 for (i
= 0; i
< stripes
; i
++) {
446 cis
[i
].dev_id
= dev
->dev_item
.dev_id
;
447 cis
[i
].offset
= find_chunk_offset(size
, c
->offset
, dev
, dev_root
, chunkuuid
);
448 cis
[i
].dev_uuid
= dev
->dev_item
.device_uuid
;
451 add_item(chunk_root
, 0x100, TYPE_CHUNK_ITEM
, c
->offset
, c
->chunk_item
, sizeof(CHUNK_ITEM
) + (stripes
* sizeof(CHUNK_ITEM_STRIPE
)));
453 InsertTailList(chunks
, &c
->list_entry
);
458 static bool superblock_collision(btrfs_chunk
* c
, uint64_t address
) {
459 CHUNK_ITEM_STRIPE
* cis
= (CHUNK_ITEM_STRIPE
*)&c
->chunk_item
[1];
460 uint64_t stripe
= (address
- c
->offset
) / c
->chunk_item
->stripe_length
;
463 for (i
= 0; i
< c
->chunk_item
->num_stripes
; i
++) {
465 while (superblock_addrs
[j
] != 0) {
466 if (superblock_addrs
[j
] >= cis
[i
].offset
) {
467 uint64_t stripe2
= (superblock_addrs
[j
] - cis
[i
].offset
) / c
->chunk_item
->stripe_length
;
469 if (stripe2
== stripe
)
479 static uint64_t get_next_address(btrfs_chunk
* c
) {
484 while (superblock_collision(c
, addr
)) {
485 addr
= addr
- ((addr
- c
->offset
) % c
->chunk_item
->stripe_length
) + c
->chunk_item
->stripe_length
;
487 if (addr
>= c
->offset
+ c
->chunk_item
->size
) // chunk has been exhausted
498 } EXTENT_ITEM_METADATA
;
505 } EXTENT_ITEM_METADATA2
;
507 static void assign_addresses(LIST_ENTRY
* roots
, btrfs_chunk
* sys_chunk
, btrfs_chunk
* metadata_chunk
, uint32_t node_size
,
508 btrfs_root
* root_root
, btrfs_root
* extent_root
, bool skinny
) {
512 while (le
!= roots
) {
513 btrfs_root
* r
= CONTAINING_RECORD(le
, btrfs_root
, list_entry
);
514 btrfs_chunk
* c
= r
->id
== BTRFS_ROOT_CHUNK
? sys_chunk
: metadata_chunk
;
516 r
->header
.address
= get_next_address(c
);
518 c
->lastoff
= r
->header
.address
+ node_size
;
519 c
->used
+= node_size
;
522 EXTENT_ITEM_METADATA eim
;
525 eim
.ei
.generation
= 1;
526 eim
.ei
.flags
= EXTENT_ITEM_TREE_BLOCK
;
527 eim
.type
= TYPE_TREE_BLOCK_REF
;
528 eim
.tbr
.offset
= r
->id
;
530 add_item(extent_root
, r
->header
.address
, TYPE_METADATA_ITEM
, 0, &eim
, sizeof(EXTENT_ITEM_METADATA
));
532 EXTENT_ITEM_METADATA2 eim2
;
535 if (r
->items
.Flink
== &r
->items
) {
536 firstitem
.obj_id
= 0;
537 firstitem
.obj_type
= 0;
538 firstitem
.offset
= 0;
540 btrfs_item
* bi
= CONTAINING_RECORD(r
->items
.Flink
, btrfs_item
, list_entry
);
545 eim2
.ei
.refcount
= 1;
546 eim2
.ei
.generation
= 1;
547 eim2
.ei
.flags
= EXTENT_ITEM_TREE_BLOCK
;
548 eim2
.ei2
.firstitem
= firstitem
;
550 eim2
.type
= TYPE_TREE_BLOCK_REF
;
551 eim2
.tbr
.offset
= r
->id
;
553 add_item(extent_root
, r
->header
.address
, TYPE_EXTENT_ITEM
, node_size
, &eim2
, sizeof(EXTENT_ITEM_METADATA2
));
556 if (r
->id
!= BTRFS_ROOT_ROOT
&& r
->id
!= BTRFS_ROOT_CHUNK
) {
559 memset(&ri
, 0, sizeof(ROOT_ITEM
));
561 ri
.inode
.generation
= 1;
562 ri
.inode
.st_size
= 3;
563 ri
.inode
.st_blocks
= node_size
;
564 ri
.inode
.st_nlink
= 1;
565 ri
.inode
.st_mode
= 040755;
567 ri
.objid
= r
->id
== 5 || r
->id
>= 0x100 ? SUBVOL_ROOT_INODE
: 0;
568 ri
.block_number
= r
->header
.address
;
569 ri
.bytes_used
= node_size
;
570 ri
.num_references
= 1;
571 ri
.generation2
= ri
.generation
;
573 add_item(root_root
, r
->id
, TYPE_ROOT_ITEM
, 0, &ri
, sizeof(ROOT_ITEM
));
580 static NTSTATUS
write_data(HANDLE h
, uint64_t address
, btrfs_chunk
* c
, void* data
, ULONG size
) {
583 IO_STATUS_BLOCK iosb
;
585 CHUNK_ITEM_STRIPE
* cis
;
587 cis
= (CHUNK_ITEM_STRIPE
*)&c
->chunk_item
[1];
589 for (i
= 0; i
< c
->chunk_item
->num_stripes
; i
++) {
590 off
.QuadPart
= cis
[i
].offset
+ address
- c
->offset
;
592 Status
= NtWriteFile(h
, NULL
, NULL
, NULL
, &iosb
, data
, size
, &off
, NULL
);
593 if (!NT_SUCCESS(Status
))
597 return STATUS_SUCCESS
;
600 static void calc_tree_checksum(tree_header
* th
, uint32_t node_size
) {
601 switch (def_csum_type
) {
602 case CSUM_TYPE_CRC32C
:
603 *(uint32_t*)th
= ~calc_crc32c(0xffffffff, (uint8_t*)&th
->fs_uuid
, node_size
- sizeof(th
->csum
));
606 case CSUM_TYPE_XXHASH
:
607 *(uint64_t*)th
= XXH64((uint8_t*)&th
->fs_uuid
, node_size
- sizeof(th
->csum
), 0);
610 case CSUM_TYPE_SHA256
:
611 calc_sha256((uint8_t*)th
, &th
->fs_uuid
, node_size
- sizeof(th
->csum
));
614 case CSUM_TYPE_BLAKE2
:
615 blake2b((uint8_t*)th
, BLAKE2_HASH_SIZE
, &th
->fs_uuid
, node_size
- sizeof(th
->csum
));
620 static NTSTATUS
write_roots(HANDLE h
, LIST_ENTRY
* roots
, uint32_t node_size
, BTRFS_UUID
* fsuuid
, BTRFS_UUID
* chunkuuid
) {
621 LIST_ENTRY
*le
, *le2
;
625 tree
= malloc(node_size
);
628 while (le
!= roots
) {
629 btrfs_root
* r
= CONTAINING_RECORD(le
, btrfs_root
, list_entry
);
633 memset(tree
, 0, node_size
);
635 r
->header
.num_items
= 0;
636 r
->header
.fs_uuid
= *fsuuid
;
637 r
->header
.flags
= HEADER_FLAG_MIXED_BACKREF
| HEADER_FLAG_WRITTEN
;
638 r
->header
.chunk_tree_uuid
= *chunkuuid
;
639 r
->header
.generation
= 1;
640 r
->header
.tree_id
= r
->id
;
642 ln
= (leaf_node
*)(tree
+ sizeof(tree_header
));
644 dp
= tree
+ node_size
;
646 le2
= r
->items
.Flink
;
647 while (le2
!= &r
->items
) {
648 btrfs_item
* item
= CONTAINING_RECORD(le2
, btrfs_item
, list_entry
);
651 ln
->size
= item
->size
;
653 if (item
->size
> 0) {
655 memcpy(dp
, item
->data
, item
->size
);
657 ln
->offset
= (uint32_t)(dp
- tree
- sizeof(tree_header
));
663 r
->header
.num_items
++;
668 memcpy(tree
, &r
->header
, sizeof(tree_header
));
670 calc_tree_checksum((tree_header
*)tree
, node_size
);
672 Status
= write_data(h
, r
->header
.address
, r
->c
, tree
, node_size
);
673 if (!NT_SUCCESS(Status
)) {
683 return STATUS_SUCCESS
;
687 static void get_uuid(BTRFS_UUID
* uuid
) {
689 static void get_uuid(BTRFS_UUID
* uuid
, ULONG
* seed
) {
693 for (i
= 0; i
< 16; i
+=2) {
697 ULONG r
= RtlRandom(seed
);
700 uuid
->uuid
[i
] = (r
& 0xff00) >> 8;
701 uuid
->uuid
[i
+1] = r
& 0xff;
706 static void init_device(btrfs_dev
* dev
, uint64_t id
, uint64_t size
, BTRFS_UUID
* fsuuid
, uint32_t sector_size
) {
708 static void init_device(btrfs_dev
* dev
, uint64_t id
, uint64_t size
, BTRFS_UUID
* fsuuid
, uint32_t sector_size
, ULONG
* seed
) {
710 dev
->dev_item
.dev_id
= id
;
711 dev
->dev_item
.num_bytes
= size
;
712 dev
->dev_item
.bytes_used
= 0;
713 dev
->dev_item
.optimal_io_align
= sector_size
;
714 dev
->dev_item
.optimal_io_width
= sector_size
;
715 dev
->dev_item
.minimal_io_size
= sector_size
;
716 dev
->dev_item
.type
= 0;
717 dev
->dev_item
.generation
= 0;
718 dev
->dev_item
.start_offset
= 0;
719 dev
->dev_item
.dev_group
= 0;
720 dev
->dev_item
.seek_speed
= 0;
721 dev
->dev_item
.bandwidth
= 0;
723 get_uuid(&dev
->dev_item
.device_uuid
);
725 get_uuid(&dev
->dev_item
.device_uuid
, seed
);
727 dev
->dev_item
.fs_uuid
= *fsuuid
;
729 dev
->last_alloc
= 0x100000; // skip first megabyte
732 static void calc_superblock_checksum(superblock
* sb
) {
733 switch (def_csum_type
) {
734 case CSUM_TYPE_CRC32C
:
735 *(uint32_t*)sb
= ~calc_crc32c(0xffffffff, (uint8_t*)&sb
->uuid
, (ULONG
)sizeof(superblock
) - sizeof(sb
->checksum
));
738 case CSUM_TYPE_XXHASH
:
739 *(uint64_t*)sb
= XXH64(&sb
->uuid
, sizeof(superblock
) - sizeof(sb
->checksum
), 0);
742 case CSUM_TYPE_SHA256
:
743 calc_sha256((uint8_t*)sb
, &sb
->uuid
, sizeof(superblock
) - sizeof(sb
->checksum
));
746 case CSUM_TYPE_BLAKE2
:
747 blake2b((uint8_t*)sb
, BLAKE2_HASH_SIZE
, &sb
->uuid
, sizeof(superblock
) - sizeof(sb
->checksum
));
752 static NTSTATUS
write_superblocks(HANDLE h
, btrfs_dev
* dev
, btrfs_root
* chunk_root
, btrfs_root
* root_root
, btrfs_root
* extent_root
,
753 btrfs_chunk
* sys_chunk
, uint32_t node_size
, BTRFS_UUID
* fsuuid
, uint32_t sector_size
, PUNICODE_STRING label
, uint64_t incompat_flags
) {
755 IO_STATUS_BLOCK iosb
;
764 if (sblen
& (sector_size
- 1))
765 sblen
= (sblen
& sector_size
) + sector_size
;
769 le
= extent_root
->items
.Flink
;
770 while (le
!= &extent_root
->items
) {
771 btrfs_item
* item
= CONTAINING_RECORD(le
, btrfs_item
, list_entry
);
773 if (item
->key
.obj_type
== TYPE_EXTENT_ITEM
)
774 bytes_used
+= item
->key
.offset
;
775 else if (item
->key
.obj_type
== TYPE_METADATA_ITEM
)
776 bytes_used
+= node_size
;
782 memset(sb
, 0, sblen
);
786 sb
->magic
= BTRFS_MAGIC
;
788 sb
->root_tree_addr
= root_root
->header
.address
;
789 sb
->chunk_tree_addr
= chunk_root
->header
.address
;
790 sb
->total_bytes
= dev
->dev_item
.num_bytes
;
791 sb
->bytes_used
= bytes_used
;
792 sb
->root_dir_objectid
= BTRFS_ROOT_TREEDIR
;
794 sb
->sector_size
= sector_size
;
795 sb
->node_size
= node_size
;
796 sb
->leaf_size
= node_size
;
797 sb
->stripe_size
= sector_size
;
798 sb
->n
= sizeof(KEY
) + sizeof(CHUNK_ITEM
) + (sys_chunk
->chunk_item
->num_stripes
* sizeof(CHUNK_ITEM_STRIPE
));
799 sb
->chunk_root_generation
= 1;
800 sb
->incompat_flags
= incompat_flags
;
801 sb
->csum_type
= def_csum_type
;
802 memcpy(&sb
->dev_item
, &dev
->dev_item
, sizeof(DEV_ITEM
));
804 if (label
->Length
> 0) {
809 for (i
= 0; i
< label
->Length
/ sizeof(WCHAR
); i
++) {
813 for (unsigned int i
= 0; i
< label
->Length
/ sizeof(WCHAR
); i
++) {
815 if (label
->Buffer
[i
] == '/' || label
->Buffer
[i
] == '\\') {
817 return STATUS_INVALID_VOLUME_LABEL
;
822 utf8len
= WideCharToMultiByte(CP_UTF8
, 0, label
->Buffer
, label
->Length
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
824 if (utf8len
== 0 || utf8len
> MAX_LABEL_SIZE
) {
826 return STATUS_INVALID_VOLUME_LABEL
;
829 if (WideCharToMultiByte(CP_UTF8
, 0, label
->Buffer
, label
->Length
/ sizeof(WCHAR
), sb
->label
, utf8len
, NULL
, NULL
) == 0) {
831 as
.Buffer
= sb
->label
;
833 as
.MaximumLength
= MAX_LABEL_SIZE
;
835 if (!NT_SUCCESS(RtlUnicodeStringToAnsiString(&as
, label
, FALSE
)))
839 return STATUS_INVALID_VOLUME_LABEL
;
842 sb
->cache_generation
= 0xffffffffffffffff;
844 key
= (KEY
*)sb
->sys_chunk_array
;
846 key
->obj_type
= TYPE_CHUNK_ITEM
;
847 key
->offset
= sys_chunk
->offset
;
848 memcpy(&key
[1], sys_chunk
->chunk_item
, sizeof(CHUNK_ITEM
) + (sys_chunk
->chunk_item
->num_stripes
* sizeof(CHUNK_ITEM_STRIPE
)));
851 while (superblock_addrs
[i
] != 0) {
854 if (superblock_addrs
[i
] > dev
->dev_item
.num_bytes
)
857 sb
->sb_phys_addr
= superblock_addrs
[i
];
859 calc_superblock_checksum(sb
);
861 off
.QuadPart
= superblock_addrs
[i
];
863 Status
= NtWriteFile(h
, NULL
, NULL
, NULL
, &iosb
, sb
, sblen
, &off
, NULL
);
864 if (!NT_SUCCESS(Status
)) {
874 return STATUS_SUCCESS
;
877 static __inline
void win_time_to_unix(LARGE_INTEGER t
, BTRFS_TIME
* out
) {
878 ULONGLONG l
= t
.QuadPart
- 116444736000000000;
880 out
->seconds
= l
/ 10000000;
881 out
->nanoseconds
= (l
% 10000000) * 100;
887 GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime
)
889 LARGE_INTEGER SystemTime
;
893 SystemTime
.HighPart
= SharedUserData
->SystemTime
.High1Time
;
894 SystemTime
.LowPart
= SharedUserData
->SystemTime
.LowPart
;
896 while (SystemTime
.HighPart
!= SharedUserData
->SystemTime
.High2Time
);
898 lpFileTime
->dwLowDateTime
= SystemTime
.LowPart
;
899 lpFileTime
->dwHighDateTime
= SystemTime
.HighPart
;
903 static void add_inode_ref(btrfs_root
* r
, uint64_t inode
, uint64_t parent
, uint64_t index
, const char* name
) {
904 uint16_t name_len
= (uint16_t)strlen(name
);
905 INODE_REF
* ir
= malloc(offsetof(INODE_REF
, name
[0]) + name_len
);
909 memcpy(ir
->name
, name
, name_len
);
911 add_item(r
, inode
, TYPE_INODE_REF
, parent
, ir
, (uint16_t)offsetof(INODE_REF
, name
[0]) + ir
->n
);
916 static void init_fs_tree(btrfs_root
* r
, uint32_t node_size
) {
921 memset(&ii
, 0, sizeof(INODE_ITEM
));
924 ii
.st_blocks
= node_size
;
928 GetSystemTimeAsFileTime(&filetime
);
929 time
.LowPart
= filetime
.dwLowDateTime
;
930 time
.HighPart
= filetime
.dwHighDateTime
;
932 win_time_to_unix(time
, &ii
.st_atime
);
933 ii
.st_ctime
= ii
.st_mtime
= ii
.st_atime
;
935 add_item(r
, SUBVOL_ROOT_INODE
, TYPE_INODE_ITEM
, 0, &ii
, sizeof(INODE_ITEM
));
937 add_inode_ref(r
, SUBVOL_ROOT_INODE
, SUBVOL_ROOT_INODE
, 0, "..");
940 static void add_block_group_items(LIST_ENTRY
* chunks
, btrfs_root
* extent_root
) {
944 while (le
!= chunks
) {
945 btrfs_chunk
* c
= CONTAINING_RECORD(le
, btrfs_chunk
, list_entry
);
946 BLOCK_GROUP_ITEM bgi
;
949 bgi
.chunk_tree
= 0x100;
950 bgi
.flags
= c
->chunk_item
->type
;
951 add_item(extent_root
, c
->offset
, TYPE_BLOCK_GROUP_ITEM
, c
->chunk_item
->size
, &bgi
, sizeof(BLOCK_GROUP_ITEM
));
957 static NTSTATUS
clear_first_megabyte(HANDLE h
) {
959 IO_STATUS_BLOCK iosb
;
963 mb
= malloc(0x100000);
964 memset(mb
, 0, 0x100000);
968 Status
= NtWriteFile(h
, NULL
, NULL
, NULL
, &iosb
, mb
, 0x100000, &zero
, NULL
);
975 static bool is_ssd(HANDLE h
) {
977 ATA_PASS_THROUGH_EX
* apte
;
978 IO_STATUS_BLOCK iosb
;
980 IDENTIFY_DEVICE_DATA
* idd
;
982 aptelen
= sizeof(ATA_PASS_THROUGH_EX
) + 512;
983 apte
= malloc(aptelen
);
985 RtlZeroMemory(apte
, aptelen
);
987 apte
->Length
= sizeof(ATA_PASS_THROUGH_EX
);
988 apte
->AtaFlags
= ATA_FLAGS_DATA_IN
;
989 apte
->DataTransferLength
= aptelen
- sizeof(ATA_PASS_THROUGH_EX
);
990 apte
->TimeOutValue
= 3;
991 apte
->DataBufferOffset
= apte
->Length
;
992 apte
->CurrentTaskFile
[6] = IDE_COMMAND_IDENTIFY
;
994 Status
= NtDeviceIoControlFile(h
, NULL
, NULL
, NULL
, &iosb
, IOCTL_ATA_PASS_THROUGH
, apte
, aptelen
, apte
, aptelen
);
996 if (NT_SUCCESS(Status
)) {
997 idd
= (IDENTIFY_DEVICE_DATA
*)((uint8_t*)apte
+ sizeof(ATA_PASS_THROUGH_EX
));
999 if (idd
->NominalMediaRotationRate
== 1) {
1010 static void add_dir_item(btrfs_root
* root
, uint64_t inode
, uint32_t hash
, uint64_t key_objid
, uint8_t key_type
,
1011 uint64_t key_offset
, uint64_t transid
, uint8_t type
, const char* name
) {
1012 uint16_t name_len
= (uint16_t)strlen(name
);
1013 DIR_ITEM
* di
= malloc(offsetof(DIR_ITEM
, name
[0]) + name_len
);
1015 di
->key
.obj_id
= key_objid
;
1016 di
->key
.obj_type
= key_type
;
1017 di
->key
.offset
= key_offset
;
1018 di
->transid
= transid
;
1022 memcpy(di
->name
, name
, name_len
);
1024 add_item(root
, inode
, TYPE_DIR_ITEM
, hash
, di
, (uint16_t)(offsetof(DIR_ITEM
, name
[0]) + di
->m
+ di
->n
));
1029 static void set_default_subvol(btrfs_root
* root_root
, uint32_t node_size
) {
1034 static const char default_subvol
[] = "default";
1035 static const uint32_t default_hash
= 0x8dbfc2d2;
1037 add_inode_ref(root_root
, BTRFS_ROOT_FSTREE
, BTRFS_ROOT_TREEDIR
, 0, default_subvol
);
1039 memset(&ii
, 0, sizeof(INODE_ITEM
));
1042 ii
.st_blocks
= node_size
;
1044 ii
.st_mode
= 040755;
1046 GetSystemTimeAsFileTime(&filetime
);
1047 time
.LowPart
= filetime
.dwLowDateTime
;
1048 time
.HighPart
= filetime
.dwHighDateTime
;
1050 win_time_to_unix(time
, &ii
.st_atime
);
1051 ii
.st_ctime
= ii
.st_mtime
= ii
.otime
= ii
.st_atime
;
1053 add_item(root_root
, BTRFS_ROOT_TREEDIR
, TYPE_INODE_ITEM
, 0, &ii
, sizeof(INODE_ITEM
));
1055 add_inode_ref(root_root
, BTRFS_ROOT_TREEDIR
, BTRFS_ROOT_TREEDIR
, 0, "..");
1057 add_dir_item(root_root
, BTRFS_ROOT_TREEDIR
, default_hash
, BTRFS_ROOT_FSTREE
, TYPE_ROOT_ITEM
,
1058 0xffffffffffffffff, 0, BTRFS_TYPE_DIRECTORY
, default_subvol
);
1061 static NTSTATUS
write_btrfs(HANDLE h
, uint64_t size
, PUNICODE_STRING label
, uint32_t sector_size
, uint32_t node_size
, uint64_t incompat_flags
) {
1063 LIST_ENTRY roots
, chunks
;
1064 btrfs_root
*root_root
, *chunk_root
, *extent_root
, *dev_root
, *fs_root
, *reloc_root
;
1065 btrfs_chunk
*sys_chunk
, *metadata_chunk
;
1067 BTRFS_UUID fsuuid
, chunkuuid
;
1069 uint64_t metadata_flags
;
1075 srand((unsigned int)time(0));
1077 get_uuid(&chunkuuid
);
1079 seed
= NtGetTickCount();
1080 get_uuid(&fsuuid
, &seed
);
1081 get_uuid(&chunkuuid
, &seed
);
1084 InitializeListHead(&roots
);
1085 InitializeListHead(&chunks
);
1087 root_root
= add_root(&roots
, BTRFS_ROOT_ROOT
);
1088 chunk_root
= add_root(&roots
, BTRFS_ROOT_CHUNK
);
1089 extent_root
= add_root(&roots
, BTRFS_ROOT_EXTENT
);
1090 dev_root
= add_root(&roots
, BTRFS_ROOT_DEVTREE
);
1091 add_root(&roots
, BTRFS_ROOT_CHECKSUM
);
1092 fs_root
= add_root(&roots
, BTRFS_ROOT_FSTREE
);
1093 reloc_root
= add_root(&roots
, BTRFS_ROOT_DATA_RELOC
);
1096 init_device(&dev
, 1, size
, &fsuuid
, sector_size
);
1098 init_device(&dev
, 1, size
, &fsuuid
, sector_size
, &seed
);
1103 sys_chunk
= add_chunk(&chunks
, BLOCK_FLAG_SYSTEM
| (ssd
? 0 : BLOCK_FLAG_DUPLICATE
), chunk_root
, &dev
, dev_root
, &chunkuuid
, sector_size
);
1105 return STATUS_INTERNAL_ERROR
;
1107 metadata_flags
= BLOCK_FLAG_METADATA
;
1109 if (!ssd
&& !(incompat_flags
& BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS
))
1110 metadata_flags
|= BLOCK_FLAG_DUPLICATE
;
1112 if (incompat_flags
& BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS
)
1113 metadata_flags
|= BLOCK_FLAG_DATA
;
1115 metadata_chunk
= add_chunk(&chunks
, metadata_flags
, chunk_root
, &dev
, dev_root
, &chunkuuid
, sector_size
);
1116 if (!metadata_chunk
)
1117 return STATUS_INTERNAL_ERROR
;
1119 add_item(chunk_root
, 1, TYPE_DEV_ITEM
, dev
.dev_item
.dev_id
, &dev
.dev_item
, sizeof(DEV_ITEM
));
1121 set_default_subvol(root_root
, node_size
);
1123 init_fs_tree(fs_root
, node_size
);
1124 init_fs_tree(reloc_root
, node_size
);
1126 assign_addresses(&roots
, sys_chunk
, metadata_chunk
, node_size
, root_root
, extent_root
, incompat_flags
& BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA
);
1128 add_block_group_items(&chunks
, extent_root
);
1130 Status
= write_roots(h
, &roots
, node_size
, &fsuuid
, &chunkuuid
);
1131 if (!NT_SUCCESS(Status
))
1134 Status
= clear_first_megabyte(h
);
1135 if (!NT_SUCCESS(Status
))
1138 Status
= write_superblocks(h
, &dev
, chunk_root
, root_root
, extent_root
, sys_chunk
, node_size
, &fsuuid
, sector_size
, label
, incompat_flags
);
1139 if (!NT_SUCCESS(Status
))
1143 free_chunks(&chunks
);
1145 return STATUS_SUCCESS
;
1148 static bool look_for_device(btrfs_filesystem
* bfs
, BTRFS_UUID
* devuuid
) {
1150 btrfs_filesystem_device
* dev
;
1152 for (i
= 0; i
< bfs
->num_devices
; i
++) {
1156 dev
= (btrfs_filesystem_device
*)((uint8_t*)dev
+ offsetof(btrfs_filesystem_device
, name
[0]) + dev
->name_length
);
1158 if (RtlCompareMemory(&dev
->uuid
, devuuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
))
1165 static bool check_superblock_checksum(superblock
* sb
) {
1166 switch (sb
->csum_type
) {
1167 case CSUM_TYPE_CRC32C
: {
1168 uint32_t crc32
= ~calc_crc32c(0xffffffff, (uint8_t*)&sb
->uuid
, (ULONG
)sizeof(superblock
) - sizeof(sb
->checksum
));
1170 return crc32
== *(uint32_t*)sb
;
1173 case CSUM_TYPE_XXHASH
: {
1174 uint64_t hash
= XXH64(&sb
->uuid
, sizeof(superblock
) - sizeof(sb
->checksum
), 0);
1176 return hash
== *(uint64_t*)sb
;
1179 case CSUM_TYPE_SHA256
: {
1180 uint8_t hash
[SHA256_HASH_SIZE
];
1182 calc_sha256(hash
, &sb
->uuid
, sizeof(superblock
) - sizeof(sb
->checksum
));
1184 return !memcmp(hash
, sb
, SHA256_HASH_SIZE
);
1187 case CSUM_TYPE_BLAKE2
: {
1188 uint8_t hash
[BLAKE2_HASH_SIZE
];
1190 blake2b(hash
, sizeof(hash
), &sb
->uuid
, sizeof(superblock
) - sizeof(sb
->checksum
));
1192 return !memcmp(hash
, sb
, BLAKE2_HASH_SIZE
);
1200 static bool is_mounted_multi_device(HANDLE h
, uint32_t sector_size
) {
1204 IO_STATUS_BLOCK iosb
;
1206 BTRFS_UUID fsuuid
, devuuid
;
1208 OBJECT_ATTRIBUTES atts
;
1210 btrfs_filesystem
*bfs
= NULL
, *bfs2
;
1214 static WCHAR btrfs
[] = L
"\\Btrfs";
1216 sblen
= sizeof(*sb
);
1217 if (sblen
& (sector_size
- 1))
1218 sblen
= (sblen
& sector_size
) + sector_size
;
1222 off
.QuadPart
= superblock_addrs
[0];
1224 Status
= NtReadFile(h
, NULL
, NULL
, NULL
, &iosb
, sb
, sblen
, &off
, NULL
);
1225 if (!NT_SUCCESS(Status
)) {
1230 if (sb
->magic
!= BTRFS_MAGIC
) {
1235 if (!check_superblock_checksum(sb
)) {
1241 devuuid
= sb
->dev_item
.device_uuid
;
1245 us
.Length
= us
.MaximumLength
= (USHORT
)(wcslen(btrfs
) * sizeof(WCHAR
));
1248 InitializeObjectAttributes(&atts
, &us
, 0, NULL
, NULL
);
1250 Status
= NtOpenFile(&h2
, SYNCHRONIZE
| FILE_READ_ATTRIBUTES
, &atts
, &iosb
,
1251 FILE_SHARE_READ
| FILE_SHARE_WRITE
, FILE_SYNCHRONOUS_IO_ALERT
);
1252 if (!NT_SUCCESS(Status
)) // not a problem, it usually just means the driver isn't loaded
1261 bfs
= malloc(bfssize
);
1263 Status
= NtDeviceIoControlFile(h2
, NULL
, NULL
, NULL
, &iosb
, IOCTL_BTRFS_QUERY_FILESYSTEMS
, NULL
, 0, bfs
, bfssize
);
1264 } while (Status
== STATUS_BUFFER_OVERFLOW
);
1266 if (!NT_SUCCESS(Status
))
1269 if (bfs
->num_devices
!= 0) {
1272 if (RtlCompareMemory(&bfs2
->uuid
, &fsuuid
, sizeof(BTRFS_UUID
)) == sizeof(BTRFS_UUID
)) {
1273 if (bfs2
->num_devices
== 1)
1276 ret
= look_for_device(bfs2
, &devuuid
);
1281 if (bfs2
->next_entry
== 0)
1284 bfs2
= (btrfs_filesystem
*)((uint8_t*)bfs2
+ bfs2
->next_entry
);
1297 static void do_full_trim(HANDLE h
) {
1298 IO_STATUS_BLOCK iosb
;
1299 DEVICE_MANAGE_DATA_SET_ATTRIBUTES dmdsa
;
1301 RtlZeroMemory(&dmdsa
, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES
));
1303 dmdsa
.Size
= sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES
);
1304 dmdsa
.Action
= DeviceDsmAction_Trim
;
1305 dmdsa
.Flags
= DEVICE_DSM_FLAG_ENTIRE_DATA_SET_RANGE
| DEVICE_DSM_FLAG_TRIM_NOT_FS_ALLOCATED
;
1306 dmdsa
.ParameterBlockOffset
= 0;
1307 dmdsa
.ParameterBlockLength
= 0;
1308 dmdsa
.DataSetRangesOffset
= 0;
1309 dmdsa
.DataSetRangesLength
= 0;
1311 NtDeviceIoControlFile(h
, NULL
, NULL
, NULL
, &iosb
, IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES
, &dmdsa
, sizeof(DEVICE_MANAGE_DATA_SET_ATTRIBUTES
), NULL
, 0);
1314 static bool is_power_of_two(ULONG i
) {
1315 return ((i
!= 0) && !(i
& (i
- 1)));
1318 #if !defined(__REACTOS__) && (defined(_X86_) || defined(_AMD64_))
1319 static void check_cpu() {
1320 unsigned int cpuInfo
[4];
1324 __get_cpuid(1, &cpuInfo
[0], &cpuInfo
[1], &cpuInfo
[2], &cpuInfo
[3]);
1325 have_sse42
= cpuInfo
[2] & bit_SSE4_2
;
1327 __cpuid(cpuInfo
, 1);
1328 have_sse42
= cpuInfo
[2] & (1 << 20);
1332 calc_crc32c
= calc_crc32c_hw
;
1336 static NTSTATUS NTAPI
FormatEx2(PUNICODE_STRING DriveRoot
, FMIFS_MEDIA_FLAG MediaFlag
, PUNICODE_STRING Label
,
1337 BOOLEAN QuickFormat
, ULONG ClusterSize
, PFMIFSCALLBACK Callback
)
1341 OBJECT_ATTRIBUTES attr
;
1342 IO_STATUS_BLOCK iosb
;
1343 GET_LENGTH_INFORMATION gli
;
1345 uint32_t sector_size
, node_size
;
1346 UNICODE_STRING btrfsus
;
1349 TOKEN_PRIVILEGES tp
;
1352 uint64_t incompat_flags
;
1353 UNICODE_STRING empty_label
;
1355 static WCHAR btrfs
[] = L
"\\Btrfs";
1358 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &token
))
1359 return STATUS_PRIVILEGE_NOT_HELD
;
1361 if (!LookupPrivilegeValueW(NULL
, L
"SeManageVolumePrivilege", &luid
)) {
1363 return STATUS_PRIVILEGE_NOT_HELD
;
1366 tp
.PrivilegeCount
= 1;
1367 tp
.Privileges
[0].Luid
= luid
;
1368 tp
.Privileges
[0].Attributes
= SE_PRIVILEGE_ENABLED
;
1370 if (!AdjustTokenPrivileges(token
, false, &tp
, sizeof(TOKEN_PRIVILEGES
), NULL
, NULL
)) {
1372 return STATUS_PRIVILEGE_NOT_HELD
;
1377 #if defined(_X86_) || defined(_AMD64_)
1382 if (def_csum_type
!= CSUM_TYPE_CRC32C
&& def_csum_type
!= CSUM_TYPE_XXHASH
&& def_csum_type
!= CSUM_TYPE_SHA256
&&
1383 def_csum_type
!= CSUM_TYPE_BLAKE2
)
1384 return STATUS_INVALID_PARAMETER
;
1386 InitializeObjectAttributes(&attr
, DriveRoot
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
1388 Status
= NtOpenFile(&h
, FILE_GENERIC_READ
| FILE_GENERIC_WRITE
, &attr
, &iosb
,
1389 FILE_SHARE_READ
, FILE_SYNCHRONOUS_IO_ALERT
);
1391 if (!NT_SUCCESS(Status
))
1394 Status
= NtDeviceIoControlFile(h
, NULL
, NULL
, NULL
, &iosb
, IOCTL_DISK_GET_LENGTH_INFO
, NULL
, 0, &gli
, sizeof(gli
));
1395 if (!NT_SUCCESS(Status
)) {
1400 // MSDN tells us to use IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, but there are
1401 // some instances where it fails and IOCTL_DISK_GET_DRIVE_GEOMETRY succeeds -
1402 // such as with spanned volumes.
1403 Status
= NtDeviceIoControlFile(h
, NULL
, NULL
, NULL
, &iosb
, IOCTL_DISK_GET_DRIVE_GEOMETRY
, NULL
, 0, &dg
, sizeof(dg
));
1404 if (!NT_SUCCESS(Status
)) {
1409 if (def_sector_size
== 0) {
1410 sector_size
= dg
.BytesPerSector
;
1412 if (sector_size
== 0x200 || sector_size
== 0)
1413 sector_size
= 0x1000;
1415 if (dg
.BytesPerSector
!= 0 && (def_sector_size
< dg
.BytesPerSector
|| def_sector_size
% dg
.BytesPerSector
!= 0 || !is_power_of_two(def_sector_size
/ dg
.BytesPerSector
))) {
1417 return STATUS_INVALID_PARAMETER
;
1420 sector_size
= def_sector_size
;
1423 if (def_node_size
== 0)
1426 if (def_node_size
< sector_size
|| def_node_size
% sector_size
!= 0 || !is_power_of_two(def_node_size
/ sector_size
)) {
1428 return STATUS_INVALID_PARAMETER
;
1431 node_size
= def_node_size
;
1436 Callback(PROGRESS
, 0, (PVOID
)&pc
);
1439 NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_LOCK_VOLUME
, NULL
, 0, NULL
, 0);
1441 if (is_mounted_multi_device(h
, sector_size
)) {
1442 Status
= STATUS_ACCESS_DENIED
;
1448 incompat_flags
= def_incompat_flags
;
1449 incompat_flags
|= BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF
| BTRFS_INCOMPAT_FLAGS_BIG_METADATA
;
1452 empty_label
.Buffer
= NULL
;
1453 empty_label
.Length
= empty_label
.MaximumLength
= 0;
1454 Label
= &empty_label
;
1457 Status
= write_btrfs(h
, gli
.Length
.QuadPart
, Label
, sector_size
, node_size
, incompat_flags
);
1459 NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_DISMOUNT_VOLUME
, NULL
, 0, NULL
, 0);
1462 NtFsControlFile(h
, NULL
, NULL
, NULL
, &iosb
, FSCTL_UNLOCK_VOLUME
, NULL
, 0, NULL
, 0);
1466 if (NT_SUCCESS(Status
)) {
1467 btrfsus
.Buffer
= btrfs
;
1468 btrfsus
.Length
= btrfsus
.MaximumLength
= (USHORT
)(wcslen(btrfs
) * sizeof(WCHAR
));
1470 InitializeObjectAttributes(&attr
, &btrfsus
, 0, NULL
, NULL
);
1472 Status
= NtOpenFile(&btrfsh
, FILE_GENERIC_READ
| FILE_GENERIC_WRITE
, &attr
, &iosb
,
1473 FILE_SHARE_READ
, FILE_SYNCHRONOUS_IO_ALERT
);
1475 if (NT_SUCCESS(Status
)) {
1479 mdnsize
= (ULONG
)(offsetof(MOUNTDEV_NAME
, Name
[0]) + DriveRoot
->Length
);
1480 mdn
= malloc(mdnsize
);
1482 mdn
->NameLength
= DriveRoot
->Length
;
1483 memcpy(mdn
->Name
, DriveRoot
->Buffer
, DriveRoot
->Length
);
1485 NtDeviceIoControlFile(btrfsh
, NULL
, NULL
, NULL
, &iosb
, IOCTL_BTRFS_PROBE_VOLUME
, mdn
, mdnsize
, NULL
, 0);
1492 Status
= STATUS_SUCCESS
;
1497 bool success
= NT_SUCCESS(Status
);
1498 Callback(DONE
, 0, (PVOID
)&success
);
1510 IN PUNICODE_STRING DriveRoot
,
1511 IN PFMIFSCALLBACK Callback
,
1512 IN BOOLEAN QuickFormat
,
1513 IN BOOLEAN BackwardCompatible
,
1514 IN MEDIA_TYPE MediaType
,
1515 IN PUNICODE_STRING Label
,
1516 IN ULONG ClusterSize
)
1520 if (BackwardCompatible
)
1522 // DPRINT1("BackwardCompatible == TRUE is unsupported!\n");
1526 Status
= FormatEx2(DriveRoot
, (FMIFS_MEDIA_FLAG
)MediaType
, Label
, QuickFormat
, ClusterSize
, Callback
);
1528 return NT_SUCCESS(Status
);
1533 BOOL __stdcall
FormatEx(DSTRING
* root
, STREAM_MESSAGE
* message
, options
* opts
, uint32_t unk1
) {
1534 UNICODE_STRING DriveRoot
, Label
;
1537 if (!root
|| !root
->string
)
1540 DriveRoot
.Length
= DriveRoot
.MaximumLength
= (USHORT
)(wcslen(root
->string
) * sizeof(WCHAR
));
1541 DriveRoot
.Buffer
= root
->string
;
1543 if (opts
&& opts
->label
&& opts
->label
->string
) {
1544 Label
.Length
= Label
.MaximumLength
= (USHORT
)(wcslen(opts
->label
->string
) * sizeof(WCHAR
));
1545 Label
.Buffer
= opts
->label
->string
;
1547 Label
.Length
= Label
.MaximumLength
= 0;
1548 Label
.Buffer
= NULL
;
1551 Status
= FormatEx2(&DriveRoot
, FMIFS_HARDDISK
, &Label
, opts
&& opts
->flags
& FORMAT_FLAG_QUICK_FORMAT
, 0, NULL
);
1553 return NT_SUCCESS(Status
);
1556 #endif // __REACTOS__
1558 void __stdcall
SetSizes(ULONG sector
, ULONG node
) {
1560 def_sector_size
= sector
;
1563 def_node_size
= node
;
1566 void __stdcall
SetIncompatFlags(uint64_t incompat_flags
) {
1567 def_incompat_flags
= incompat_flags
;
1570 void __stdcall
SetCsumType(uint16_t csum_type
) {
1571 def_csum_type
= csum_type
;
1574 BOOL __stdcall
GetFilesystemInformation(uint32_t unk1
, uint32_t unk2
, void* unk3
) {
1575 // STUB - undocumented
1581 BOOL APIENTRY
DllMain(HANDLE hModule
, DWORD dwReason
, void* lpReserved
) {
1582 if (dwReason
== DLL_PROCESS_ATTACH
)
1583 module
= (HMODULE
)hModule
;