https://git.reactos.org/?p=reactos.git;a=commitdiff;h=eb7fbc253fcb0d2bc5344…
commit eb7fbc253fcb0d2bc534412b4965bf2f736eac05
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Sun Dec 16 12:03:16 2018 +0100
Commit: Pierre Schweitzer <pierre(a)reactos.org>
CommitDate: Sun Dec 16 12:06:46 2018 +0100
[BTRFS] Upgrade to 1.1
CORE-15452
---
drivers/filesystems/btrfs/CMakeLists.txt | 16 +
drivers/filesystems/btrfs/balance.c | 50 +-
drivers/filesystems/btrfs/btrfs.c | 188 +-
drivers/filesystems/btrfs/btrfs.h | 3 +-
drivers/filesystems/btrfs/btrfs.rc | 8 +-
drivers/filesystems/btrfs/btrfs_drv.h | 47 +-
drivers/filesystems/btrfs/btrfsioctl.h | 20 +
drivers/filesystems/btrfs/compress.c | 268 +-
drivers/filesystems/btrfs/create.c | 420 +-
drivers/filesystems/btrfs/dirctrl.c | 63 +-
drivers/filesystems/btrfs/fastio.c | 21 +-
drivers/filesystems/btrfs/fileinfo.c | 214 +-
drivers/filesystems/btrfs/flushthread.c | 175 +-
drivers/filesystems/btrfs/free-space.c | 26 +-
drivers/filesystems/btrfs/fsctl.c | 112 +-
drivers/filesystems/btrfs/pnp.c | 18 +-
drivers/filesystems/btrfs/read.c | 49 +-
drivers/filesystems/btrfs/registry.c | 51 +-
drivers/filesystems/btrfs/reparse.c | 190 +-
drivers/filesystems/btrfs/scrub.c | 4 +-
drivers/filesystems/btrfs/search.c | 10 +-
drivers/filesystems/btrfs/send.c | 50 +-
drivers/filesystems/btrfs/treefuncs.c | 12 +-
drivers/filesystems/btrfs/volume.c | 12 +-
drivers/filesystems/btrfs/write.c | 67 +-
drivers/filesystems/btrfs/zstd/bitstream.h | 455 +++
drivers/filesystems/btrfs/zstd/compiler.h | 133 +
drivers/filesystems/btrfs/zstd/cpu.h | 215 ++
drivers/filesystems/btrfs/zstd/debug.h | 123 +
drivers/filesystems/btrfs/zstd/entropy_common.c | 236 ++
drivers/filesystems/btrfs/zstd/error_private.c | 48 +
drivers/filesystems/btrfs/zstd/error_private.h | 76 +
drivers/filesystems/btrfs/zstd/fse.h | 708 ++++
drivers/filesystems/btrfs/zstd/fse_compress.c | 724 ++++
drivers/filesystems/btrfs/zstd/fse_decompress.c | 313 ++
drivers/filesystems/btrfs/zstd/hist.c | 195 +
drivers/filesystems/btrfs/zstd/hist.h | 92 +
drivers/filesystems/btrfs/zstd/huf.h | 334 ++
drivers/filesystems/btrfs/zstd/huf_compress.c | 796 ++++
drivers/filesystems/btrfs/zstd/huf_decompress.c | 1096 ++++++
drivers/filesystems/btrfs/zstd/mem.h | 376 ++
drivers/filesystems/btrfs/zstd/xxhash.c | 887 +++++
drivers/filesystems/btrfs/zstd/xxhash.h | 305 ++
drivers/filesystems/btrfs/zstd/zstd.h | 1526 ++++++++
drivers/filesystems/btrfs/zstd/zstd_common.c | 72 +
drivers/filesystems/btrfs/zstd/zstd_compress.c | 4040 ++++++++++++++++++++
.../btrfs/zstd/zstd_compress_internal.h | 798 ++++
drivers/filesystems/btrfs/zstd/zstd_decompress.c | 3108 +++++++++++++++
drivers/filesystems/btrfs/zstd/zstd_double_fast.c | 499 +++
drivers/filesystems/btrfs/zstd/zstd_double_fast.h | 38 +
drivers/filesystems/btrfs/zstd/zstd_errors.h | 92 +
drivers/filesystems/btrfs/zstd/zstd_fast.c | 391 ++
drivers/filesystems/btrfs/zstd/zstd_fast.h | 37 +
drivers/filesystems/btrfs/zstd/zstd_internal.h | 257 ++
drivers/filesystems/btrfs/zstd/zstd_lazy.c | 1099 ++++++
drivers/filesystems/btrfs/zstd/zstd_lazy.h | 67 +
drivers/filesystems/btrfs/zstd/zstd_ldm.c | 646 ++++
drivers/filesystems/btrfs/zstd/zstd_ldm.h | 109 +
drivers/filesystems/btrfs/zstd/zstd_opt.c | 1132 ++++++
drivers/filesystems/btrfs/zstd/zstd_opt.h | 48 +
media/doc/README.FSD | 2 +-
61 files changed, 22588 insertions(+), 579 deletions(-)
diff --git a/drivers/filesystems/btrfs/CMakeLists.txt
b/drivers/filesystems/btrfs/CMakeLists.txt
index 65e61d255a..59fe9565e6 100644
--- a/drivers/filesystems/btrfs/CMakeLists.txt
+++ b/drivers/filesystems/btrfs/CMakeLists.txt
@@ -33,6 +33,22 @@ list(APPEND SOURCE
volume.c
worker-thread.c
write.c
+ zstd/entropy_common.c
+ zstd/fse_compress.c
+ zstd/hist.c
+ zstd/huf_decompress.c
+ zstd/zstd_common.c
+ zstd/zstd_decompress.c
+ zstd/zstd_fast.c
+ zstd/zstd_ldm.c
+ zstd/error_private.c
+ zstd/fse_decompress.c
+ zstd/huf_compress.c
+ zstd/xxhash.c
+ zstd/zstd_compress.c
+ zstd/zstd_double_fast.c
+ zstd/zstd_lazy.c
+ zstd/zstd_opt.c
btrfs_drv.h)
add_library(btrfs SHARED ${SOURCE} btrfs.rc)
diff --git a/drivers/filesystems/btrfs/balance.c b/drivers/filesystems/btrfs/balance.c
index 3e36489c31..fe641f4f41 100644
--- a/drivers/filesystems/btrfs/balance.c
+++ b/drivers/filesystems/btrfs/balance.c
@@ -107,13 +107,13 @@ static NTSTATUS
add_metadata_reloc(_Requires_exclusive_lock_held_(_Curr_->tree_l
c = get_chunk_from_address(Vcb, tp->item->key.obj_id);
if (c) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
c->used -= Vcb->superblock.node_size;
space_list_add(c, tp->item->key.obj_id, Vcb->superblock.node_size,
rollback);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
}
ei = (EXTENT_ITEM*)tp->item->data;
@@ -747,7 +747,7 @@ static NTSTATUS
write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
flags = Vcb->metadata_flags;
if (newchunk) {
- ExAcquireResourceExclusiveLite(&newchunk->lock, TRUE);
+ acquire_chunk_lock(newchunk, Vcb);
if (newchunk->chunk_item->type == flags &&
find_metadata_address_in_chunk(Vcb, newchunk, &mr->new_address)) {
newchunk->used += Vcb->superblock.node_size;
@@ -755,7 +755,7 @@ static NTSTATUS
write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
done = TRUE;
}
- ExReleaseResourceLite(&newchunk->lock);
+ release_chunk_lock(newchunk, Vcb);
}
if (!done) {
@@ -766,20 +766,20 @@ static NTSTATUS
write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
chunk* c2 = CONTAINING_RECORD(le2, chunk, list_entry);
if (!c2->readonly && !c2->reloc && c2 !=
newchunk && c2->chunk_item->type == flags) {
- ExAcquireResourceExclusiveLite(&c2->lock, TRUE);
+ acquire_chunk_lock(c2, Vcb);
if ((c2->chunk_item->size - c2->used) >=
Vcb->superblock.node_size) {
if (find_metadata_address_in_chunk(Vcb, c2,
&mr->new_address)) {
c2->used += Vcb->superblock.node_size;
space_list_subtract(c2, FALSE, mr->new_address,
Vcb->superblock.node_size, rollback);
- ExReleaseResourceLite(&c2->lock);
+ release_chunk_lock(c2, Vcb);
newchunk = c2;
done = TRUE;
break;
}
}
- ExReleaseResourceLite(&c2->lock);
+ release_chunk_lock(c2, Vcb);
}
le2 = le2->Flink;
@@ -795,12 +795,12 @@ static NTSTATUS
write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
goto end;
}
- ExAcquireResourceExclusiveLite(&newchunk->lock, TRUE);
+ acquire_chunk_lock(newchunk, Vcb);
newchunk->balance_num = Vcb->balance.balance_num;
if (!find_metadata_address_in_chunk(Vcb, newchunk,
&mr->new_address)) {
- ExReleaseResourceLite(&newchunk->lock);
+ release_chunk_lock(newchunk, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
ERR("could not find address in new chunk\n");
Status = STATUS_DISK_FULL;
@@ -810,7 +810,7 @@ static NTSTATUS
write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
space_list_subtract(newchunk, FALSE, mr->new_address,
Vcb->superblock.node_size, rollback);
}
- ExReleaseResourceLite(&newchunk->lock);
+ release_chunk_lock(newchunk, Vcb);
}
ExReleaseResourceLite(&Vcb->chunk_lock);
@@ -1340,13 +1340,13 @@ static NTSTATUS
add_data_reloc(_Requires_exclusive_lock_held_(_Curr_->tree_lock)
c = get_chunk_from_address(Vcb, tp->item->key.obj_id);
if (c) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
c->used -= tp->item->key.offset;
space_list_add(c, tp->item->key.obj_id, tp->item->key.offset,
rollback);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
}
ei = (EXTENT_ITEM*)tp->item->data;
@@ -1756,7 +1756,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c,
BOOL* change
ULONG runlength, index, lastoff;
if (newchunk) {
- ExAcquireResourceExclusiveLite(&newchunk->lock, TRUE);
+ acquire_chunk_lock(newchunk, Vcb);
if (find_data_address_in_chunk(Vcb, newchunk, dr->size,
&dr->new_address)) {
newchunk->used += dr->size;
@@ -1764,7 +1764,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c,
BOOL* change
done = TRUE;
}
- ExReleaseResourceLite(&newchunk->lock);
+ release_chunk_lock(newchunk, Vcb);
}
if (!done) {
@@ -1775,20 +1775,20 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk*
c, BOOL* change
chunk* c2 = CONTAINING_RECORD(le2, chunk, list_entry);
if (!c2->readonly && !c2->reloc && c2 != newchunk
&& c2->chunk_item->type == Vcb->data_flags) {
- ExAcquireResourceExclusiveLite(&c2->lock, TRUE);
+ acquire_chunk_lock(c2, Vcb);
if ((c2->chunk_item->size - c2->used) >= dr->size) {
if (find_data_address_in_chunk(Vcb, c2, dr->size,
&dr->new_address)) {
c2->used += dr->size;
space_list_subtract(c2, FALSE, dr->new_address,
dr->size, &rollback);
- ExReleaseResourceLite(&c2->lock);
+ release_chunk_lock(c2, Vcb);
newchunk = c2;
done = TRUE;
break;
}
}
- ExReleaseResourceLite(&c2->lock);
+ release_chunk_lock(c2, Vcb);
}
le2 = le2->Flink;
@@ -1804,12 +1804,12 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk*
c, BOOL* change
goto end;
}
- ExAcquireResourceExclusiveLite(&newchunk->lock, TRUE);
+ acquire_chunk_lock(newchunk, Vcb);
newchunk->balance_num = Vcb->balance.balance_num;
if (!find_data_address_in_chunk(Vcb, newchunk, dr->size,
&dr->new_address)) {
- ExReleaseResourceLite(&newchunk->lock);
+ release_chunk_lock(newchunk, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
ERR("could not find address in new chunk\n");
Status = STATUS_DISK_FULL;
@@ -1819,7 +1819,7 @@ static NTSTATUS balance_data_chunk(device_extension* Vcb, chunk* c,
BOOL* change
space_list_subtract(newchunk, FALSE, dr->new_address, dr->size,
&rollback);
}
- ExReleaseResourceLite(&newchunk->lock);
+ release_chunk_lock(newchunk, Vcb);
}
ExReleaseResourceLite(&Vcb->chunk_lock);
@@ -2957,6 +2957,8 @@ static NTSTATUS try_consolidation(device_extension* Vcb, UINT64
flags, chunk** n
ERR("do_write returned %08x\n", Status);
return Status;
}
+
+ free_trees(Vcb);
}
ExAcquireResourceExclusiveLite(&Vcb->chunk_lock, TRUE);
@@ -3108,7 +3110,7 @@ void NTAPI balance_thread(void* context) {
chunk* c = CONTAINING_RECORD(le, chunk, list_entry);
UINT8 sort;
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if (c->chunk_item->type & BLOCK_FLAG_DATA)
sort = BALANCE_OPTS_DATA;
@@ -3118,7 +3120,7 @@ void NTAPI balance_thread(void* context) {
sort = BALANCE_OPTS_SYSTEM;
else {
ERR("unexpected chunk type %llx\n", c->chunk_item->type);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
break;
}
@@ -3142,13 +3144,13 @@ void NTAPI balance_thread(void* context) {
if (!NT_SUCCESS(Status)) {
ERR("load_cache_chunk returned %08x\n", Status);
Vcb->balance.status = Status;
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
goto end;
}
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
le = le->Flink;
}
diff --git a/drivers/filesystems/btrfs/btrfs.c b/drivers/filesystems/btrfs/btrfs.c
index bdc2988145..2582ee0b3f 100644
--- a/drivers/filesystems/btrfs/btrfs.c
+++ b/drivers/filesystems/btrfs/btrfs.c
@@ -48,11 +48,12 @@
#define INCOMPAT_SUPPORTED (BTRFS_INCOMPAT_FLAGS_MIXED_BACKREF |
BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL | BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS | \
BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO |
BTRFS_INCOMPAT_FLAGS_BIG_METADATA | BTRFS_INCOMPAT_FLAGS_RAID56 | \
- BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF |
BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES)
+ BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF |
BTRFS_INCOMPAT_FLAGS_SKINNY_METADATA | BTRFS_INCOMPAT_FLAGS_NO_HOLES | \
+ BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD)
#define COMPAT_RO_SUPPORTED (BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE |
BTRFS_COMPAT_RO_FLAGS_FREE_SPACE_CACHE_VALID)
-static WCHAR device_name[] =
{'\\','B','t','r','f','s',0};
-static WCHAR dosdevice_name[] =
{'\\','D','o','s','D','e','v','i','c','e','s','\\','B','t','r','f','s',0};
+static const WCHAR device_name[] =
{'\\','B','t','r','f','s',0};
+static const WCHAR dosdevice_name[] =
{'\\','D','o','s','D','e','v','i','c','e','s','\\','B','t','r','f','s',0};
DEFINE_GUID(BtrfsBusInterface, 0x4d414874, 0x6865, 0x6761, 0x6d, 0x65, 0x83, 0x69, 0x17,
0x9a, 0x7d, 0x1d);
@@ -70,6 +71,7 @@ UINT32 mount_compress = 0;
UINT32 mount_compress_force = 0;
UINT32 mount_compress_type = 0;
UINT32 mount_zlib_level = 3;
+UINT32 mount_zstd_level = 3;
UINT32 mount_flush_interval = 30;
UINT32 mount_max_inline = 2048;
UINT32 mount_skip_balance = 0;
@@ -268,7 +270,7 @@ static void DriverUnload(_In_ PDRIVER_OBJECT DriverObject) {
#endif
UNICODE_STRING dosdevice_nameW;
- ERR("DriverUnload\n");
+ TRACE("(%p)\n");
free_cache();
@@ -295,8 +297,8 @@ static void DriverUnload(_In_ PDRIVER_OBJECT DriverObject) {
IoUnregisterPlugPlayNotificationEx(notification_entry);
#endif
- dosdevice_nameW.Buffer = dosdevice_name;
- dosdevice_nameW.Length = dosdevice_nameW.MaximumLength =
(USHORT)wcslen(dosdevice_name) * sizeof(WCHAR);
+ dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name;
+ dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) -
sizeof(WCHAR);
IoDeleteSymbolicLink(&dosdevice_nameW);
IoDeleteDevice(DriverObject->DeviceObject);
@@ -621,22 +623,32 @@ static BOOL lie_about_fs_type() {
PPEB peb;
LIST_ENTRY* le;
ULONG retlen;
+#ifdef _AMD64_
+ ULONG_PTR wow64info;
+#endif
- static WCHAR mpr[] = L"MPR.DLL";
- static WCHAR cmd[] = L"CMD.EXE";
- static WCHAR fsutil[] = L"FSUTIL.EXE";
+ static const WCHAR mpr[] = L"MPR.DLL";
+ static const WCHAR cmd[] = L"CMD.EXE";
+ static const WCHAR fsutil[] = L"FSUTIL.EXE";
UNICODE_STRING mprus, cmdus, fsutilus;
- mprus.Buffer = mpr;
- mprus.Length = mprus.MaximumLength = (USHORT)(wcslen(mpr) * sizeof(WCHAR));
- cmdus.Buffer = cmd;
- cmdus.Length = cmdus.MaximumLength = (USHORT)(wcslen(cmd) * sizeof(WCHAR));
- fsutilus.Buffer = fsutil;
- fsutilus.Length = fsutilus.MaximumLength = (USHORT)(wcslen(fsutil) * sizeof(WCHAR));
+ mprus.Buffer = (WCHAR*)mpr;
+ mprus.Length = mprus.MaximumLength = sizeof(mpr) - sizeof(WCHAR);
+ cmdus.Buffer = (WCHAR*)cmd;
+ cmdus.Length = cmdus.MaximumLength = sizeof(cmd) - sizeof(WCHAR);
+ fsutilus.Buffer = (WCHAR*)fsutil;
+ fsutilus.Length = fsutilus.MaximumLength = sizeof(fsutil) - sizeof(WCHAR);
if (!PsGetCurrentProcess())
return FALSE;
+#ifdef _AMD64_
+ Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessWow64Information,
&wow64info, sizeof(wow64info), NULL);
+
+ if (NT_SUCCESS(Status) && wow64info != 0)
+ return TRUE;
+#endif
+
Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation,
&pbi, sizeof(pbi), &retlen);
if (!NT_SUCCESS(Status)) {
@@ -750,13 +762,24 @@ static NTSTATUS drv_query_volume_information(_In_ PDEVICE_OBJECT
DeviceObject, _
FILE_FS_ATTRIBUTE_INFORMATION* data = Irp->AssociatedIrp.SystemBuffer;
BOOL overflow = FALSE;
#ifndef __REACTOS__
- WCHAR* fs_name = (Irp->RequestorMode == UserMode &&
lie_about_fs_type()) ? L"NTFS" : L"Btrfs";
- ULONG fs_name_len = (ULONG)wcslen(fs_name) * sizeof(WCHAR);
+ static const WCHAR ntfs[] = L"NTFS";
+#endif
+ static const WCHAR btrfs[] = L"Btrfs";
+ const WCHAR* fs_name;
+ ULONG fs_name_len, orig_fs_name_len;
+
+#ifndef __REACTOS__
+ if (Irp->RequestorMode == UserMode && lie_about_fs_type()) {
+ fs_name = ntfs;
+ orig_fs_name_len = fs_name_len = sizeof(ntfs) - sizeof(WCHAR);
+ } else {
+ fs_name = btrfs;
+ orig_fs_name_len = fs_name_len = sizeof(btrfs) - sizeof(WCHAR);
+ }
#else
- WCHAR* fs_name = L"Btrfs";
- ULONG fs_name_len = 5 * sizeof(WCHAR);
+ fs_name = btrfs;
+ orig_fs_name_len = fs_name_len = sizeof(btrfs) - sizeof(WCHAR);
#endif
- ULONG orig_fs_name_len = fs_name_len;
TRACE("FileFsAttributeInformation\n");
@@ -1705,7 +1728,7 @@ static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP
Irp) {
CcUninitializeCacheMap(FileObject, NULL, NULL);
if (open_files == 0 && fcb->Vcb->removing) {
- uninit(fcb->Vcb, FALSE);
+ uninit(fcb->Vcb);
return STATUS_SUCCESS;
}
@@ -1726,8 +1749,9 @@ static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP
Irp) {
return STATUS_SUCCESS;
}
-void uninit(_In_ device_extension* Vcb, _In_ BOOL flush) {
+void uninit(_In_ device_extension* Vcb) {
UINT64 i;
+ KIRQL irql;
NTSTATUS Status;
LIST_ENTRY* le;
LARGE_INTEGER time;
@@ -1738,6 +1762,11 @@ void uninit(_In_ device_extension* Vcb, _In_ BOOL flush) {
ExReleaseResourceLite(&Vcb->tree_lock);
}
+ IoAcquireVpbSpinLock(&irql);
+ Vcb->Vpb->Flags &= ~VPB_MOUNTED;
+ Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED;
+ IoReleaseVpbSpinLock(irql);
+
RemoveEntryList(&Vcb->list_entry);
if (Vcb->balance.thread) {
@@ -1787,20 +1816,6 @@ void uninit(_In_ device_extension* Vcb, _In_ BOOL flush) {
if (!NT_SUCCESS(Status) && Status != STATUS_TOO_LATE)
WARN("registry_mark_volume_unmounted returned %08x\n", Status);
- if (flush) {
- ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
-
- if (Vcb->need_write && !Vcb->readonly) {
- Status = do_write(Vcb, NULL);
- if (!NT_SUCCESS(Status))
- ERR("do_write returned %08x\n", Status);
- }
-
- free_trees(Vcb);
-
- ExReleaseResourceLite(&Vcb->tree_lock);
- }
-
for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
Vcb->calcthreads.threads[i].quit = TRUE;
}
@@ -3599,7 +3614,7 @@ _Ret_maybenull_
static root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock)
device_extension* Vcb, _In_opt_ PIRP Irp) {
LIST_ENTRY* le;
- static char fn[] = "default";
+ static const char fn[] = "default";
static UINT32 crc32 = 0x8dbfc2d2;
if (Vcb->options.subvol_id != 0) {
@@ -3764,8 +3779,8 @@ static BOOL is_btrfs_volume(_In_ PDEVICE_OBJECT DeviceObject) {
return FALSE;
}
- if (mdn2->NameLength > wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR) &&
- RtlCompareMemory(mdn2->Name, BTRFS_VOLUME_PREFIX, wcslen(BTRFS_VOLUME_PREFIX)
* sizeof(WCHAR)) == wcslen(BTRFS_VOLUME_PREFIX) * sizeof(WCHAR)) {
+ if (mdn2->NameLength > (sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR))
&&
+ RtlCompareMemory(mdn2->Name, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX)
- sizeof(WCHAR)) == sizeof(BTRFS_VOLUME_PREFIX) - sizeof(WCHAR)) {
ExFreePool(mdn2);
return TRUE;
}
@@ -4773,7 +4788,7 @@ static NTSTATUS verify_volume(_In_ PDEVICE_OBJECT devobj) {
ExReleaseResourceLite(&Vcb->tree_lock);
if (remove) {
- uninit(Vcb, FALSE);
+ uninit(Vcb);
return Status;
}
@@ -4924,9 +4939,7 @@ static NTSTATUS drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_
PIRP Irp) {
NTSTATUS Status;
BOOL top_level;
device_extension* Vcb = DeviceObject->DeviceExtension;
-#ifdef __REACTOS__
- LIST_ENTRY *Vcble, *le;
-#endif
+ LIST_ENTRY* le;
FsRtlEnterFileSystem();
@@ -4944,79 +4957,34 @@ static NTSTATUS drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP Irp) {
shutting_down = TRUE;
KeSetEvent(&mountmgr_thread_event, 0, FALSE);
-#ifndef __REACTOS__
- while (!IsListEmpty(&VcbList)) {
- Vcb = CONTAINING_RECORD(VcbList.Flink, device_extension, list_entry);
+ le = VcbList.Flink;
+ while (le != &VcbList) {
+ BOOL open_files;
+ LIST_ENTRY* le2 = le->Flink;
- TRACE("shutting down Vcb %p\n", Vcb);
-
- uninit(Vcb, TRUE);
- }
-#else
- Vcble = VcbList.Flink;
- while (Vcble != &VcbList) {
- Vcb = CONTAINING_RECORD(Vcble, device_extension, list_entry);
+ Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
TRACE("shutting down Vcb %p\n", Vcb);
- if (Vcb->balance.thread) {
- Vcb->balance.paused = FALSE;
- Vcb->balance.stopping = TRUE;
- KeSetEvent(&Vcb->balance.event, 0, FALSE);
- KeWaitForSingleObject(&Vcb->balance.finished, Executive, KernelMode,
FALSE, NULL);
- }
-
- if (Vcb->scrub.thread) {
- Vcb->scrub.paused = FALSE;
- Vcb->scrub.stopping = TRUE;
- KeSetEvent(&Vcb->scrub.event, 0, FALSE);
- KeWaitForSingleObject(&Vcb->scrub.finished, Executive, KernelMode,
FALSE, NULL);
- }
-
- if (Vcb->running_sends != 0) {
- BOOL send_cancelled = FALSE;
-
- ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE);
-
- le = Vcb->send_ops.Flink;
- while (le != &Vcb->send_ops) {
- send_info* send = CONTAINING_RECORD(le, send_info, list_entry);
-
- if (!send->cancelling) {
- send->cancelling = TRUE;
- send_cancelled = TRUE;
- send->ccb = NULL;
- KeSetEvent(&send->cleared_event, 0, FALSE);
- }
-
- le = le->Flink;
- }
-
- ExReleaseResourceLite(&Vcb->send_load_lock);
-
- if (send_cancelled) {
- while (Vcb->running_sends != 0) {
- ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, TRUE);
- ExReleaseResourceLite(&Vcb->send_load_lock);
- }
- }
- }
-
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
+ Vcb->removing = TRUE;
+ open_files = Vcb->open_files > 0;
if (Vcb->need_write && !Vcb->readonly) {
Status = do_write(Vcb, Irp);
-
if (!NT_SUCCESS(Status))
ERR("do_write returned %08x\n", Status);
}
- Vcb->removing = TRUE;
+ free_trees(Vcb);
ExReleaseResourceLite(&Vcb->tree_lock);
- Vcble = Vcble->Flink;
+
+ if (!open_files)
+ uninit(Vcb);
+
+ le = le2;
}
-#endif
#ifdef _DEBUG
if (comfo) {
@@ -5333,7 +5301,7 @@ static void init_logging() {
FILE_STANDARD_INFORMATION fsi;
FILE_POSITION_INFORMATION fpi;
- static char delim[] = "\n---\n";
+ static const char delim[] = "\n---\n";
// move to end of file
@@ -5353,7 +5321,7 @@ static void init_logging() {
goto end;
}
- Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, delim,
(ULONG)strlen(delim), NULL, NULL);
+ Status = ZwWriteFile(log_handle, NULL, NULL, NULL, &iosb, (void*)delim,
sizeof(delim) - 1, NULL, NULL);
if (!NT_SUCCESS(Status)) {
ERR("ZwWriteFile returned %08x\n", Status);
@@ -5453,7 +5421,7 @@ NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT
PhysicalDeviceObj
ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
- volname.Length = volname.MaximumLength = (USHORT)((wcslen(BTRFS_VOLUME_PREFIX) + 36 +
1) * sizeof(WCHAR));
+ volname.Length = volname.MaximumLength = (sizeof(BTRFS_VOLUME_PREFIX) -
sizeof(WCHAR)) + ((36 + 1) * sizeof(WCHAR));
volname.Buffer = ExAllocatePoolWithTag(PagedPool, volname.MaximumLength, ALLOC_TAG);
// FIXME - when do we free this?
if (!volname.Buffer) {
@@ -5462,9 +5430,9 @@ NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT
PhysicalDeviceObj
goto end2;
}
- RtlCopyMemory(volname.Buffer, BTRFS_VOLUME_PREFIX, wcslen(BTRFS_VOLUME_PREFIX) *
sizeof(WCHAR));
+ RtlCopyMemory(volname.Buffer, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) -
sizeof(WCHAR));
- j = (ULONG)wcslen(BTRFS_VOLUME_PREFIX);
+ j = (sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1;
for (i = 0; i < 16; i++) {
volname.Buffer[j] = hex_digit(pdode->uuid.uuid[i] >> 4); j++;
volname.Buffer[j] = hex_digit(pdode->uuid.uuid[i] & 0xf); j++;
@@ -5670,10 +5638,10 @@ NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_
PUNICODE_STRING Regi
init_fast_io_dispatch(&DriverObject->FastIoDispatch);
- device_nameW.Buffer = device_name;
- device_nameW.Length = device_nameW.MaximumLength = (USHORT)wcslen(device_name) *
sizeof(WCHAR);
- dosdevice_nameW.Buffer = dosdevice_name;
- dosdevice_nameW.Length = dosdevice_nameW.MaximumLength =
(USHORT)wcslen(dosdevice_name) * sizeof(WCHAR);
+ device_nameW.Buffer = (WCHAR*)device_name;
+ device_nameW.Length = device_nameW.MaximumLength = sizeof(device_name) -
sizeof(WCHAR);
+ dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name;
+ dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) -
sizeof(WCHAR);
Status = IoCreateDevice(DriverObject, sizeof(control_device_extension),
&device_nameW, FILE_DEVICE_DISK_FILE_SYSTEM,
FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject);
diff --git a/drivers/filesystems/btrfs/btrfs.h b/drivers/filesystems/btrfs/btrfs.h
index 27e9b63f51..eede405985 100644
--- a/drivers/filesystems/btrfs/btrfs.h
+++ b/drivers/filesystems/btrfs/btrfs.h
@@ -58,6 +58,7 @@ static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000,
0x4000000000, 0x4
#define BTRFS_COMPRESSION_NONE 0
#define BTRFS_COMPRESSION_ZLIB 1
#define BTRFS_COMPRESSION_LZO 2
+#define BTRFS_COMPRESSION_ZSTD 3
#define BTRFS_ENCRYPTION_NONE 0
@@ -103,7 +104,7 @@ static const UINT64 superblock_addrs[] = { 0x10000, 0x4000000,
0x4000000000, 0x4
#define BTRFS_INCOMPAT_FLAGS_DEFAULT_SUBVOL 0x0002
#define BTRFS_INCOMPAT_FLAGS_MIXED_GROUPS 0x0004
#define BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO 0x0008
-#define BTRFS_INCOMPAT_FLAGS_COMPRESS_LZOV2 0x0010
+#define BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD 0x0010
#define BTRFS_INCOMPAT_FLAGS_BIG_METADATA 0x0020
#define BTRFS_INCOMPAT_FLAGS_EXTENDED_IREF 0x0040
#define BTRFS_INCOMPAT_FLAGS_RAID56 0x0080
diff --git a/drivers/filesystems/btrfs/btrfs.rc b/drivers/filesystems/btrfs/btrfs.rc
index 50f7463328..957792add5 100644
--- a/drivers/filesystems/btrfs/btrfs.rc
+++ b/drivers/filesystems/btrfs/btrfs.rc
@@ -53,8 +53,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,2,0
- PRODUCTVERSION 1,0,2,0
+ FILEVERSION 1,1,0,0
+ PRODUCTVERSION 1,1,0,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -70,12 +70,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "FileDescription", "WinBtrfs"
- VALUE "FileVersion", "1.0.2"
+ VALUE "FileVersion", "1.1"
VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone
2016-18"
VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs"
- VALUE "ProductVersion", "1.0.2"
+ VALUE "ProductVersion", "1.1"
END
END
BLOCK "VarFileInfo"
diff --git a/drivers/filesystems/btrfs/btrfs_drv.h
b/drivers/filesystems/btrfs/btrfs_drv.h
index 857555f755..e6ea5891f3 100644
--- a/drivers/filesystems/btrfs/btrfs_drv.h
+++ b/drivers/filesystems/btrfs/btrfs_drv.h
@@ -74,6 +74,7 @@
// #define DEBUG_LONG_MESSAGES
// #define DEBUG_FLUSH_TIMES
// #define DEBUG_STATS
+// #define DEBUG_CHUNK_LOCKS
#define DEBUG_PARANOID
#endif
@@ -110,6 +111,11 @@
#define IO_REPARSE_TAG_LXSS_SYMLINK 0xa000001d // undocumented?
+#define IO_REPARSE_TAG_LXSS_SOCKET 0x80000023
+#define IO_REPARSE_TAG_LXSS_FIFO 0x80000024
+#define IO_REPARSE_TAG_LXSS_CHARDEV 0x80000025
+#define IO_REPARSE_TAG_LXSS_BLOCKDEV 0x80000026
+
#define BTRFS_VOLUME_PREFIX L"\\Device\\Btrfs{"
#ifdef _MSC_VER
@@ -234,7 +240,8 @@ typedef struct {
enum prop_compression_type {
PropCompression_None,
PropCompression_Zlib,
- PropCompression_LZO
+ PropCompression_LZO,
+ PropCompression_ZSTD
};
typedef struct {
@@ -606,6 +613,7 @@ typedef struct {
UINT8 compress_type;
BOOL readonly;
UINT32 zlib_level;
+ UINT32 zstd_level;
UINT32 flush_interval;
UINT32 max_inline;
UINT64 subvol_id;
@@ -716,6 +724,9 @@ typedef struct _device_extension {
LIST_ENTRY devices;
#ifdef DEBUG_STATS
debug_stats stats;
+#endif
+#ifdef DEBUG_CHUNK_LOCKS
+ LONG chunk_locks_held;
#endif
UINT64 devices_loaded;
superblock superblock;
@@ -955,10 +966,10 @@ static __inline UINT64 unix_time_to_win(BTRFS_TIME* t) {
}
static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME* out) {
- ULONGLONG l = t.QuadPart - 116444736000000000;
+ ULONGLONG l = (ULONGLONG)t.QuadPart - 116444736000000000;
out->seconds = l / 10000000;
- out->nanoseconds = (l % 10000000) * 100;
+ out->nanoseconds = (UINT32)((l % 10000000) * 100);
}
_Post_satisfies_(*stripe>=0&&*stripe<num_stripes)
@@ -1083,13 +1094,21 @@ void protect_superblocks(_Inout_ chunk* c);
BOOL is_top_level(_In_ PIRP Irp);
NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock)
device_extension* Vcb, _In_ UINT64 id,
_Out_ root** rootptr, _In_ BOOL no_tree, _In_ UINT64 offset,
_In_opt_ PIRP Irp);
-void uninit(_In_ device_extension* Vcb, _In_ BOOL flush);
+void uninit(_In_ device_extension* Vcb);
NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode,
_In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize,
_Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_
ULONG OutputBufferSize, _In_ BOOLEAN Override, _Out_opt_ IO_STATUS_BLOCK* iosb);
BOOL is_file_name_valid(_In_ PUNICODE_STRING us, _In_ BOOL posix);
void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
ULONG action, _In_opt_ PUNICODE_STRING stream);
void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG
action, _In_opt_ PUNICODE_STRING stream);
+#ifdef DEBUG_CHUNK_LOCKS
+#define acquire_chunk_lock(c, Vcb) { ExAcquireResourceExclusiveLite(&c->lock,
TRUE); InterlockedIncrement(&Vcb->chunk_locks_held); }
+#define release_chunk_lock(c, Vcb) { InterlockedDecrement(&Vcb->chunk_locks_held);
ExReleaseResourceLite(&c->lock); }
+#else
+#define acquire_chunk_lock(c, Vcb) ExAcquireResourceExclusiveLite(&(c)->lock,
TRUE)
+#define release_chunk_lock(c, Vcb) ExReleaseResourceLite(&(c)->lock)
+#endif
+
_Ret_z_
WCHAR* file_desc(_In_ PFILE_OBJECT FileObject);
WCHAR* file_desc_fileref(_In_ file_ref* fileref);
@@ -1123,6 +1142,7 @@ extern UINT32 mount_compress;
extern UINT32 mount_compress_force;
extern UINT32 mount_compress_type;
extern UINT32 mount_zlib_level;
+extern UINT32 mount_zstd_level;
extern UINT32 mount_flush_interval;
extern UINT32 mount_max_inline;
extern UINT32 mount_skip_balance;
@@ -1208,6 +1228,18 @@ typedef struct {
LIST_ENTRY list_entry;
} rollback_item;
+typedef struct {
+ ANSI_STRING name;
+ ANSI_STRING value;
+ UCHAR flags;
+ LIST_ENTRY list_entry;
+} ea_item;
+
+static const char lxuid[] = "$LXUID";
+static const char lxgid[] = "$LXGID";
+static const char lxmod[] = "$LXMOD";
+static const char lxdev[] = "$LXDEV";
+
// in treefuncs.c
NTSTATUS find_item(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb,
_In_ root* r, _Out_ traverse_ptr* tp,
_In_ const KEY* searchkey, _In_ BOOL ignore, _In_opt_ PIRP Irp);
@@ -1307,6 +1339,7 @@ _Function_class_(DRIVER_DISPATCH)
NTSTATUS NTAPI drv_directory_control(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
ULONG get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type,
ULONG atts, BOOL lxss, PIRP Irp);
+ULONG get_reparse_tag_fcb(fcb* fcb);
// in security.c
@@ -1353,6 +1386,7 @@ void remove_dir_child_from_hash_lists(fcb* fcb, dir_child* dc);
// in reparse.c
NTSTATUS get_reparse_point(PDEVICE_OBJECT DeviceObject, PFILE_OBJECT FileObject, void*
buffer, DWORD buflen, ULONG_PTR* retlen);
+NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, ccb* ccb,
file_ref* fileref, PIRP Irp, LIST_ENTRY* rollback);
NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp);
@@ -1479,6 +1513,7 @@ void watch_registry(HANDLE regh);
// in compress.c
NTSTATUS zlib_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen);
NTSTATUS lzo_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen, UINT32
inpageoff);
+NTSTATUS zstd_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen);
NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data, void* data,
BOOL* compressed, PIRP Irp, LIST_ENTRY* rollback);
// in galois.c
@@ -1720,6 +1755,10 @@ static __inline void do_xor(UINT8* buf1, UINT8* buf2, UINT32 len)
{
#define S_ISVTX 0001000
#endif
+// based on functions in sys/sysmacros.h
+#define major(rdev) ((((rdev) >> 8) & 0xFFF) | ((UINT32)((rdev) >> 32)
& ~0xFFF))
+#define minor(rdev) (((rdev) & 0xFF) | ((UINT32)((rdev) >> 12) & ~0xFF))
+
static __inline UINT64 fcb_alloc_size(fcb* fcb) {
if (S_ISDIR(fcb->inode_item.st_mode))
return 0;
diff --git a/drivers/filesystems/btrfs/btrfsioctl.h
b/drivers/filesystems/btrfs/btrfsioctl.h
index 9c57c9cb60..a7f53b3317 100644
--- a/drivers/filesystems/btrfs/btrfsioctl.h
+++ b/drivers/filesystems/btrfs/btrfsioctl.h
@@ -63,6 +63,7 @@ typedef struct {
#define BTRFS_COMPRESSION_ANY 0
#define BTRFS_COMPRESSION_ZLIB 1
#define BTRFS_COMPRESSION_LZO 2
+#define BTRFS_COMPRESSION_ZSTD 3
typedef struct {
UINT64 subvol;
@@ -79,6 +80,25 @@ typedef struct {
UINT8 compression_type;
} btrfs_inode_info;
+typedef struct {
+ UINT64 subvol;
+ UINT64 inode;
+ BOOL top;
+ UINT8 type;
+ UINT32 st_uid;
+ UINT32 st_gid;
+ UINT32 st_mode;
+ UINT64 st_rdev;
+ UINT64 flags;
+ UINT32 inline_length;
+ UINT64 disk_size_uncompressed;
+ UINT64 disk_size_zlib;
+ UINT64 disk_size_lzo;
+ UINT8 compression_type;
+ UINT64 disk_size_zstd;
+ UINT64 sparse_size;
+} btrfs_inode_info2;
+
typedef struct {
UINT64 flags;
BOOL flags_changed;
diff --git a/drivers/filesystems/btrfs/compress.c b/drivers/filesystems/btrfs/compress.c
index 0a8a1f7269..598171b678 100644
--- a/drivers/filesystems/btrfs/compress.c
+++ b/drivers/filesystems/btrfs/compress.c
@@ -39,6 +39,10 @@
#include <zlib.h>
#endif
+#define ZSTD_STATIC_LINKING_ONLY
+
+#include "zstd/zstd.h"
+
#define LINUX_PAGE_SIZE 4096
typedef struct {
@@ -82,6 +86,16 @@ typedef struct {
#define LZO_BYTE(x) ((unsigned char) (x))
+#define ZSTD_ALLOC_TAG 0x6474737a // "zstd"
+
+// needs to be the same as Linux (fs/btrfs/zstd.c)
+#define ZSTD_BTRFS_MAX_WINDOWLOG 17
+
+static void* zstd_malloc(void* opaque, size_t size);
+static void zstd_free(void* opaque, void* address);
+
+ZSTD_customMem zstd_mem = { .customAlloc = zstd_malloc, .customFree = zstd_free, .opaque
= NULL };
+
static UINT8 lzo_nextbyte(lzo_stream* stream) {
UINT8 c;
@@ -449,7 +463,7 @@ static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data,
UINT64 en
c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == fcb->Vcb->data_flags &&
(c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length,
FALSE, comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) {
@@ -462,7 +476,7 @@ static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data,
UINT64 en
}
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, fcb->Vcb);
}
le = le->Flink;
@@ -486,7 +500,7 @@ static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data,
UINT64 en
}
if (c) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == fcb->Vcb->data_flags &&
(c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE,
comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) {
@@ -497,7 +511,7 @@ static NTSTATUS zlib_write_compressed_bit(fcb* fcb, UINT64 start_data,
UINT64 en
}
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, fcb->Vcb);
}
WARN("couldn't find any data chunks with %llx bytes free\n",
comp_length);
@@ -847,7 +861,7 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data,
UINT64 end
c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == fcb->Vcb->data_flags &&
(c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length,
FALSE, comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) {
@@ -860,7 +874,7 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data,
UINT64 end
}
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, fcb->Vcb);
}
le = le->Flink;
@@ -884,7 +898,7 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64 start_data,
UINT64 end
}
if (c) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == fcb->Vcb->data_flags &&
(c->chunk_item->size - c->used) >= comp_length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE,
comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) {
@@ -895,7 +909,173 @@ static NTSTATUS lzo_write_compressed_bit(fcb* fcb, UINT64
start_data, UINT64 end
}
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, fcb->Vcb);
+ }
+
+ WARN("couldn't find any data chunks with %llx bytes free\n",
comp_length);
+
+ if (compression != BTRFS_COMPRESSION_NONE)
+ ExFreePool(comp_data);
+
+ return STATUS_DISK_FULL;
+}
+
+static NTSTATUS zstd_write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64 end_data,
void* data, BOOL* compressed, PIRP Irp, LIST_ENTRY* rollback) {
+ NTSTATUS Status;
+ UINT8 compression;
+ UINT32 comp_length;
+ UINT8* comp_data;
+ UINT32 out_left;
+ LIST_ENTRY* le;
+ chunk* c;
+ ZSTD_CStream* stream;
+ size_t init_res, written;
+ ZSTD_inBuffer input;
+ ZSTD_outBuffer output;
+ ZSTD_parameters params;
+
+ comp_data = ExAllocatePoolWithTag(PagedPool, (UINT32)(end_data - start_data),
ALLOC_TAG);
+ if (!comp_data) {
+ ERR("out of memory\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ Status = excise_extents(fcb->Vcb, fcb, start_data, end_data, Irp, rollback);
+ if (!NT_SUCCESS(Status)) {
+ ERR("excise_extents returned %08x\n", Status);
+ ExFreePool(comp_data);
+ return Status;
+ }
+
+ stream = ZSTD_createCStream_advanced(zstd_mem);
+
+ if (!stream) {
+ ERR("ZSTD_createCStream failed.\n");
+ ExFreePool(comp_data);
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ params = ZSTD_getParams(fcb->Vcb->options.zstd_level, (UINT32)(end_data -
start_data), 0);
+
+ if (params.cParams.windowLog > ZSTD_BTRFS_MAX_WINDOWLOG)
+ params.cParams.windowLog = ZSTD_BTRFS_MAX_WINDOWLOG;
+
+ init_res = ZSTD_initCStream_advanced(stream, NULL, 0, params, (UINT32)(end_data -
start_data));
+
+ if (ZSTD_isError(init_res)) {
+ ERR("ZSTD_initCStream_advanced failed: %s\n",
ZSTD_getErrorName(init_res));
+ ZSTD_freeCStream(stream);
+ ExFreePool(comp_data);
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ input.src = data;
+ input.size = (UINT32)(end_data - start_data);
+ input.pos = 0;
+
+ output.dst = comp_data;
+ output.size = (UINT32)(end_data - start_data);
+ output.pos = 0;
+
+ while (input.pos < input.size && output.pos < output.size) {
+ written = ZSTD_compressStream(stream, &output, &input);
+
+ if (ZSTD_isError(written)) {
+ ERR("ZSTD_compressStream failed: %s\n",
ZSTD_getErrorName(written));
+ ZSTD_freeCStream(stream);
+ ExFreePool(comp_data);
+ return STATUS_INTERNAL_ERROR;
+ }
+ }
+
+ written = ZSTD_endStream(stream, &output);
+ if (ZSTD_isError(written)) {
+ ERR("ZSTD_endStream failed: %s\n", ZSTD_getErrorName(written));
+ ZSTD_freeCStream(stream);
+ ExFreePool(comp_data);
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ ZSTD_freeCStream(stream);
+
+ out_left = output.size - output.pos;
+
+ if (out_left < fcb->Vcb->superblock.sector_size) { // compressed extent
would be larger than or same size as uncompressed extent
+ ExFreePool(comp_data);
+
+ comp_length = (UINT32)(end_data - start_data);
+ comp_data = data;
+ compression = BTRFS_COMPRESSION_NONE;
+
+ *compressed = FALSE;
+ } else {
+ UINT32 cl;
+
+ compression = BTRFS_COMPRESSION_ZSTD;
+ cl = (UINT32)(end_data - start_data - out_left);
+ comp_length = (UINT32)sector_align(cl, fcb->Vcb->superblock.sector_size);
+
+ RtlZeroMemory(comp_data + cl, comp_length - cl);
+
+ *compressed = TRUE;
+ }
+
+ ExAcquireResourceSharedLite(&fcb->Vcb->chunk_lock, TRUE);
+
+ le = fcb->Vcb->chunks.Flink;
+ while (le != &fcb->Vcb->chunks) {
+ c = CONTAINING_RECORD(le, chunk, list_entry);
+
+ if (!c->readonly && !c->reloc) {
+ acquire_chunk_lock(c, fcb->Vcb);
+
+ if (c->chunk_item->type == fcb->Vcb->data_flags &&
(c->chunk_item->size - c->used) >= comp_length) {
+ if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length,
FALSE, comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) {
+ ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
+
+ if (compression != BTRFS_COMPRESSION_NONE)
+ ExFreePool(comp_data);
+
+ return STATUS_SUCCESS;
+ }
+ }
+
+ release_chunk_lock(c, fcb->Vcb);
+ }
+
+ le = le->Flink;
+ }
+
+ ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
+
+ ExAcquireResourceExclusiveLite(&fcb->Vcb->chunk_lock, TRUE);
+
+ Status = alloc_chunk(fcb->Vcb, fcb->Vcb->data_flags, &c, FALSE);
+
+ ExReleaseResourceLite(&fcb->Vcb->chunk_lock);
+
+ if (!NT_SUCCESS(Status)) {
+ ERR("alloc_chunk returned %08x\n", Status);
+
+ if (compression != BTRFS_COMPRESSION_NONE)
+ ExFreePool(comp_data);
+
+ return Status;
+ }
+
+ if (c) {
+ acquire_chunk_lock(c, fcb->Vcb);
+
+ if (c->chunk_item->type == fcb->Vcb->data_flags &&
(c->chunk_item->size - c->used) >= comp_length) {
+ if (insert_extent_chunk(fcb->Vcb, fcb, c, start_data, comp_length, FALSE,
comp_data, Irp, rollback, compression, end_data - start_data, FALSE, 0)) {
+ if (compression != BTRFS_COMPRESSION_NONE)
+ ExFreePool(comp_data);
+
+ return STATUS_SUCCESS;
+ }
+ }
+
+ release_chunk_lock(c, fcb->Vcb);
}
WARN("couldn't find any data chunks with %llx bytes free\n",
comp_length);
@@ -912,18 +1092,82 @@ NTSTATUS write_compressed_bit(fcb* fcb, UINT64 start_data, UINT64
end_data, void
if (fcb->Vcb->options.compress_type != 0 && fcb->prop_compression ==
PropCompression_None)
type = fcb->Vcb->options.compress_type;
else {
- if (!(fcb->Vcb->superblock.incompat_flags &
BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO) && fcb->prop_compression ==
PropCompression_LZO) {
- fcb->Vcb->superblock.incompat_flags |=
BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO;
+ if (!(fcb->Vcb->superblock.incompat_flags &
BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD) && fcb->prop_compression ==
PropCompression_ZSTD)
+ type = BTRFS_COMPRESSION_ZSTD;
+ else if (fcb->Vcb->superblock.incompat_flags &
BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD && fcb->prop_compression !=
PropCompression_Zlib && fcb->prop_compression != PropCompression_LZO)
+ type = BTRFS_COMPRESSION_ZSTD;
+ else if (!(fcb->Vcb->superblock.incompat_flags &
BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO) && fcb->prop_compression ==
PropCompression_LZO)
type = BTRFS_COMPRESSION_LZO;
- } else if (fcb->Vcb->superblock.incompat_flags &
BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO && fcb->prop_compression !=
PropCompression_Zlib)
+ else if (fcb->Vcb->superblock.incompat_flags &
BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO && fcb->prop_compression !=
PropCompression_Zlib)
type = BTRFS_COMPRESSION_LZO;
else
type = BTRFS_COMPRESSION_ZLIB;
}
- if (type == BTRFS_COMPRESSION_LZO) {
+ if (type == BTRFS_COMPRESSION_ZSTD) {
+ fcb->Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_COMPRESS_ZSTD;
+ return zstd_write_compressed_bit(fcb, start_data, end_data, data, compressed,
Irp, rollback);
+ } else if (type == BTRFS_COMPRESSION_LZO) {
fcb->Vcb->superblock.incompat_flags |= BTRFS_INCOMPAT_FLAGS_COMPRESS_LZO;
return lzo_write_compressed_bit(fcb, start_data, end_data, data, compressed, Irp,
rollback);
} else
return zlib_write_compressed_bit(fcb, start_data, end_data, data, compressed,
Irp, rollback);
}
+
+static void* zstd_malloc(void* opaque, size_t size) {
+ UNUSED(opaque);
+
+ return ExAllocatePoolWithTag(PagedPool, size, ZSTD_ALLOC_TAG);
+}
+
+static void zstd_free(void* opaque, void* address) {
+ UNUSED(opaque);
+
+ ExFreePool(address);
+}
+
+NTSTATUS zstd_decompress(UINT8* inbuf, UINT32 inlen, UINT8* outbuf, UINT32 outlen) {
+ NTSTATUS Status;
+ ZSTD_DStream* stream;
+ size_t init_res, read;
+ ZSTD_inBuffer input;
+ ZSTD_outBuffer output;
+
+ stream = ZSTD_createDStream_advanced(zstd_mem);
+
+ if (!stream) {
+ ERR("ZSTD_createDStream failed.\n");
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ init_res = ZSTD_initDStream(stream);
+
+ if (ZSTD_isError(init_res)) {
+ ERR("ZSTD_initDStream failed: %s\n", ZSTD_getErrorName(init_res));
+ Status = STATUS_INTERNAL_ERROR;
+ goto end;
+ }
+
+ input.src = inbuf;
+ input.size = inlen;
+ input.pos = 0;
+
+ output.dst = outbuf;
+ output.size = outlen;
+ output.pos = 0;
+
+ read = ZSTD_decompressStream(stream, &output, &input);
+
+ if (ZSTD_isError(read)) {
+ ERR("ZSTD_decompressStream failed: %s\n", ZSTD_getErrorName(read));
+ Status = STATUS_INTERNAL_ERROR;
+ goto end;
+ }
+
+ Status = STATUS_SUCCESS;
+
+end:
+ ZSTD_freeDStream(stream);
+
+ return Status;
+}
diff --git a/drivers/filesystems/btrfs/create.c b/drivers/filesystems/btrfs/create.c
index 4c4c5dd984..1b4417e802 100644
--- a/drivers/filesystems/btrfs/create.c
+++ b/drivers/filesystems/btrfs/create.c
@@ -23,7 +23,24 @@
extern PDEVICE_OBJECT master_devobj;
-static WCHAR datastring[] = L"::$DATA";
+static const WCHAR datastring[] = L"::$DATA";
+
+// Windows 10
+#define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002
+#define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100
+#define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET 0x0002
+
+typedef struct _ATOMIC_CREATE_ECP_CONTEXT {
+ USHORT Size;
+ USHORT InFlags;
+ USHORT OutFlags;
+ USHORT ReparseBufferLength;
+ PREPARSE_DATA_BUFFER ReparseBuffer;
+ LONGLONG FileSize;
+ LONGLONG ValidDataLength;
+} ATOMIC_CREATE_ECP_CONTEXT, *PATOMIC_CREATE_ECP_CONTEXT;
+
+static const GUID GUID_ECP_ATOMIC_CREATE = { 0x4720bd83, 0x52ac, 0x4104, { 0xa1, 0x30,
0xd1, 0xec, 0x6a, 0x8c, 0xc8, 0xe5 } };
fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) {
fcb* fcb;
@@ -308,11 +325,11 @@ static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING
path, LIST_ENT
InsertTailList(parts, &nb->list_entry);
if (has_stream) {
- static WCHAR datasuf[] =
{':','$','D','A','T','A',0};
+ static const WCHAR datasuf[] =
{':','$','D','A','T','A',0};
UNICODE_STRING dsus;
- dsus.Buffer = datasuf;
- dsus.Length = dsus.MaximumLength = (UINT16)wcslen(datasuf) * sizeof(WCHAR);
+ dsus.Buffer = (WCHAR*)datasuf;
+ dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
for (i = 0; i < nb->us.Length / sizeof(WCHAR); i++) {
if (nb->us.Buffer[i] == ':') {
@@ -799,7 +816,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusive_lo
ULONG len;
DIR_ITEM* di;
- static char xapref[] = "user.";
+ static const char xapref[] = "user.";
if (tp.item->size < offsetof(DIR_ITEM, name[0])) {
ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n",
tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
tp.item->size, offsetof(DIR_ITEM, name[0]));
@@ -813,7 +830,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusive_lo
if (len < offsetof(DIR_ITEM, name[0]) + di->m + di->n)
break;
- if (tp.item->key.offset == EA_REPARSE_HASH && di->n ==
strlen(EA_REPARSE) && RtlCompareMemory(EA_REPARSE, di->name, di->n) ==
di->n) {
+ if (tp.item->key.offset == EA_REPARSE_HASH && di->n ==
sizeof(EA_REPARSE) - 1 && RtlCompareMemory(EA_REPARSE, di->name, di->n) ==
di->n) {
if (di->m > 0) {
fcb->reparse_xattr.Buffer = ExAllocatePoolWithTag(PagedPool,
di->m, ALLOC_TAG);
if (!fcb->reparse_xattr.Buffer) {
@@ -827,7 +844,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusive_lo
fcb->reparse_xattr.Buffer = NULL;
fcb->reparse_xattr.Length = fcb->reparse_xattr.MaximumLength =
di->m;
- } else if (tp.item->key.offset == EA_EA_HASH && di->n ==
strlen(EA_EA) && RtlCompareMemory(EA_EA, di->name, di->n) == di->n) {
+ } else if (tp.item->key.offset == EA_EA_HASH && di->n ==
sizeof(EA_EA) - 1 && RtlCompareMemory(EA_EA, di->name, di->n) == di->n)
{
if (di->m > 0) {
ULONG offset;
@@ -863,7 +880,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusive_lo
} while (TRUE);
}
}
- } else if (tp.item->key.offset == EA_DOSATTRIB_HASH &&
di->n == strlen(EA_DOSATTRIB) && RtlCompareMemory(EA_DOSATTRIB, di->name,
di->n) == di->n) {
+ } else if (tp.item->key.offset == EA_DOSATTRIB_HASH &&
di->n == sizeof(EA_DOSATTRIB) - 1 && RtlCompareMemory(EA_DOSATTRIB,
di->name, di->n) == di->n) {
if (di->m > 0) {
if (get_file_attributes_from_xattr(&di->name[di->n],
di->m, &fcb->atts)) {
atts_set = TRUE;
@@ -884,7 +901,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusive_lo
}
}
}
- } else if (tp.item->key.offset == EA_NTACL_HASH && di->n ==
strlen(EA_NTACL) && RtlCompareMemory(EA_NTACL, di->name, di->n) == di->n)
{
+ } else if (tp.item->key.offset == EA_NTACL_HASH && di->n ==
sizeof(EA_NTACL) - 1 && RtlCompareMemory(EA_NTACL, di->name, di->n) ==
di->n) {
if (di->m > 0) {
fcb->sd = ExAllocatePoolWithTag(PagedPool, di->m,
ALLOC_TAG);
if (!fcb->sd) {
@@ -902,23 +919,26 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusive_lo
else
sd_set = TRUE;
}
- } else if (tp.item->key.offset == EA_PROP_COMPRESSION_HASH &&
di->n == strlen(EA_PROP_COMPRESSION) && RtlCompareMemory(EA_PROP_COMPRESSION,
di->name, di->n) == di->n) {
+ } else if (tp.item->key.offset == EA_PROP_COMPRESSION_HASH &&
di->n == sizeof(EA_PROP_COMPRESSION) - 1 &&
RtlCompareMemory(EA_PROP_COMPRESSION, di->name, di->n) == di->n) {
if (di->m > 0) {
- const char lzo[] = "lzo";
- const char zlib[] = "zlib";
+ static const char lzo[] = "lzo";
+ static const char zlib[] = "zlib";
+ static const char zstd[] = "zstd";
- if (di->m == strlen(lzo) &&
RtlCompareMemory(&di->name[di->n], lzo, di->m) == di->m)
+ if (di->m == sizeof(lzo) - 1 &&
RtlCompareMemory(&di->name[di->n], lzo, di->m) == di->m)
fcb->prop_compression = PropCompression_LZO;
- else if (di->m == strlen(zlib) &&
RtlCompareMemory(&di->name[di->n], zlib, di->m) == di->m)
+ else if (di->m == sizeof(zlib) - 1 &&
RtlCompareMemory(&di->name[di->n], zlib, di->m) == di->m)
fcb->prop_compression = PropCompression_Zlib;
+ else if (di->m == sizeof(zstd) - 1 &&
RtlCompareMemory(&di->name[di->n], zstd, di->m) == di->m)
+ fcb->prop_compression = PropCompression_ZSTD;
else
fcb->prop_compression = PropCompression_None;
}
- } else if (di->n > strlen(xapref) &&
RtlCompareMemory(xapref, di->name, strlen(xapref)) == strlen(xapref)) {
+ } else if (di->n > sizeof(xapref) - 1 &&
RtlCompareMemory(xapref, di->name, sizeof(xapref) - 1) == sizeof(xapref) - 1) {
dir_child* dc;
ULONG utf16len;
- Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len,
&di->name[strlen(xapref)], di->n - (ULONG)strlen(xapref));
+ Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len,
&di->name[sizeof(xapref) - 1], di->n + 1 - sizeof(xapref));
if (!NT_SUCCESS(Status)) {
ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
free_fcb(Vcb, fcb);
@@ -934,7 +954,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusive_lo
RtlZeroMemory(dc, sizeof(dir_child));
- dc->utf8.MaximumLength = dc->utf8.Length = di->n -
(UINT16)strlen(xapref);
+ dc->utf8.MaximumLength = dc->utf8.Length = di->n + 1 -
sizeof(xapref);
dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool,
dc->utf8.MaximumLength, ALLOC_TAG);
if (!dc->utf8.Buffer) {
ERR("out of memory\n");
@@ -943,7 +963,7 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusive_lo
return STATUS_INSUFFICIENT_RESOURCES;
}
- RtlCopyMemory(dc->utf8.Buffer, &di->name[strlen(xapref)],
dc->utf8.Length);
+ RtlCopyMemory(dc->utf8.Buffer, &di->name[sizeof(xapref) -
1], dc->utf8.Length);
dc->name.MaximumLength = dc->name.Length = (UINT16)utf16len;
dc->name.Buffer = ExAllocatePoolWithTag(PagedPool,
dc->name.MaximumLength, ALLOC_TAG);
@@ -1113,11 +1133,11 @@ static NTSTATUS
open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Require
NTSTATUS Status;
KEY searchkey;
traverse_ptr tp;
- static char xapref[] = "user.";
+ static const char xapref[] = "user.";
ANSI_STRING xattr;
UINT32 crc32;
- xattr.Length = (UINT16)strlen(xapref) + dc->utf8.Length;
+ xattr.Length = sizeof(xapref) - 1 + dc->utf8.Length;
xattr.MaximumLength = xattr.Length + 1;
xattr.Buffer = ExAllocatePoolWithTag(PagedPool, xattr.MaximumLength, ALLOC_TAG);
if (!xattr.Buffer) {
@@ -1125,8 +1145,8 @@ static NTSTATUS
open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Require
return STATUS_INSUFFICIENT_RESOURCES;
}
- RtlCopyMemory(xattr.Buffer, xapref, strlen(xapref));
- RtlCopyMemory(&xattr.Buffer[strlen(xapref)], dc->utf8.Buffer,
dc->utf8.Length);
+ RtlCopyMemory(xattr.Buffer, xapref, sizeof(xapref) - 1);
+ RtlCopyMemory(&xattr.Buffer[sizeof(xapref) - 1], dc->utf8.Buffer,
dc->utf8.Length);
xattr.Buffer[xattr.Length] = 0;
fcb = create_fcb(Vcb, PagedPool);
@@ -1454,7 +1474,7 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusiv
InitializeListHead(&parts);
if (fnus->Length != 0 &&
- (fnus->Length != wcslen(datastring) * sizeof(WCHAR) ||
RtlCompareMemory(fnus->Buffer, datastring, wcslen(datastring) * sizeof(WCHAR)) !=
wcslen(datastring) * sizeof(WCHAR))) {
+ (fnus->Length != sizeof(datastring) - sizeof(WCHAR) ||
RtlCompareMemory(fnus->Buffer, datastring, sizeof(datastring) - sizeof(WCHAR)) !=
sizeof(datastring) - sizeof(WCHAR))) {
Status = split_path(Vcb, &fnus2, &parts, &has_stream);
if (!NT_SUCCESS(Status)) {
ERR("split_path returned %08x\n", Status);
@@ -1649,6 +1669,218 @@ UINT32 inherit_mode(fcb* parfcb, BOOL is_dir) {
return mode;
}
+static NTSTATUS file_create_parse_ea(fcb* fcb, FILE_FULL_EA_INFORMATION* ea) {
+ NTSTATUS Status;
+ LIST_ENTRY ealist, *le;
+ UINT16 size = 0;
+ char* buf;
+
+ InitializeListHead(&ealist);
+
+ do {
+ STRING s;
+ BOOL found = FALSE;
+
+ s.Length = s.MaximumLength = ea->EaNameLength;
+ s.Buffer = ea->EaName;
+
+ RtlUpperString(&s, &s);
+
+ le = ealist.Flink;
+ while (le != &ealist) {
+ ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
+
+ if (item->name.Length == s.Length &&
RtlCompareMemory(item->name.Buffer, s.Buffer, s.Length) == s.Length) {
+ item->flags = ea->Flags;
+ item->value.Length = item->value.MaximumLength =
ea->EaValueLength;
+ item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
+ found = TRUE;
+ break;
+ }
+
+ le = le->Flink;
+ }
+
+ if (!found) {
+ ea_item* item = ExAllocatePoolWithTag(PagedPool, sizeof(ea_item),
ALLOC_TAG);
+ if (!item) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto end;
+ }
+
+ item->name.Length = item->name.MaximumLength = ea->EaNameLength;
+ item->name.Buffer = ea->EaName;
+
+ item->value.Length = item->value.MaximumLength = ea->EaValueLength;
+ item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
+
+ item->flags = ea->Flags;
+
+ InsertTailList(&ealist, &item->list_entry);
+ }
+
+ if (ea->NextEntryOffset == 0)
+ break;
+
+ ea = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ea) + ea->NextEntryOffset);
+ } while (TRUE);
+
+ // handle LXSS values
+ le = ealist.Flink;
+ while (le != &ealist) {
+ LIST_ENTRY* le2 = le->Flink;
+ ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
+
+ if (item->name.Length == sizeof(lxuid) - 1 &&
RtlCompareMemory(item->name.Buffer, lxuid, item->name.Length) ==
item->name.Length) {
+ if (item->value.Length < sizeof(UINT32)) {
+ ERR("uid value was shorter than expected\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ RtlCopyMemory(&fcb->inode_item.st_uid, item->value.Buffer,
sizeof(UINT32));
+ fcb->sd_dirty = TRUE;
+ fcb->sd_deleted = FALSE;
+
+ RemoveEntryList(&item->list_entry);
+ ExFreePool(item);
+ } else if (item->name.Length == sizeof(lxgid) - 1 &&
RtlCompareMemory(item->name.Buffer, lxgid, item->name.Length) ==
item->name.Length) {
+ if (item->value.Length < sizeof(UINT32)) {
+ ERR("gid value was shorter than expected\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ RtlCopyMemory(&fcb->inode_item.st_gid, item->value.Buffer,
sizeof(UINT32));
+
+ RemoveEntryList(&item->list_entry);
+ ExFreePool(item);
+ } else if (item->name.Length == sizeof(lxmod) - 1 &&
RtlCompareMemory(item->name.Buffer, lxmod, item->name.Length) ==
item->name.Length) {
+ UINT32 allowed = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP |
S_IROTH | S_IWOTH | S_IXOTH | S_ISGID | S_ISVTX | S_ISUID;
+ UINT32 val;
+
+ if (item->value.Length < sizeof(UINT32)) {
+ ERR("mode value was shorter than expected\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ RtlCopyMemory(&val, item->value.Buffer, sizeof(UINT32));
+
+ if (fcb->type != BTRFS_TYPE_DIRECTORY)
+ allowed |= __S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK;
+
+ fcb->inode_item.st_mode &= ~allowed;
+ fcb->inode_item.st_mode |= val & allowed;
+
+ if (fcb->type != BTRFS_TYPE_DIRECTORY) {
+ if ((fcb->inode_item.st_mode & __S_IFCHR) == __S_IFCHR)
+ fcb->type = BTRFS_TYPE_CHARDEV;
+ else if ((fcb->inode_item.st_mode & __S_IFBLK) == __S_IFBLK)
+ fcb->type = BTRFS_TYPE_BLOCKDEV;
+ else if ((fcb->inode_item.st_mode & __S_IFIFO) == __S_IFIFO)
+ fcb->type = BTRFS_TYPE_FIFO;
+ else if ((fcb->inode_item.st_mode & __S_IFSOCK) == __S_IFSOCK)
+ fcb->type = BTRFS_TYPE_SOCKET;
+ }
+
+ RemoveEntryList(&item->list_entry);
+ ExFreePool(item);
+ } else if (item->name.Length == sizeof(lxdev) - 1 &&
RtlCompareMemory(item->name.Buffer, lxdev, item->name.Length) ==
item->name.Length) {
+ UINT32 major, minor;
+
+ if (item->value.Length < sizeof(UINT64)) {
+ ERR("dev value was shorter than expected\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ major = *(UINT32*)item->value.Buffer;
+ minor = *(UINT32*)&item->value.Buffer[sizeof(UINT32)];
+
+ fcb->inode_item.st_rdev = (minor & 0xFFFFF) | ((major &
0xFFFFFFFFFFF) << 20);
+
+ RemoveEntryList(&item->list_entry);
+ ExFreePool(item);
+ }
+
+ le = le2;
+ }
+
+ if (fcb->type != BTRFS_TYPE_CHARDEV && fcb->type !=
BTRFS_TYPE_BLOCKDEV)
+ fcb->inode_item.st_rdev = 0;
+
+ if (IsListEmpty(&ealist))
+ return STATUS_SUCCESS;
+
+ le = ealist.Flink;
+ while (le != &ealist) {
+ ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
+
+ if (size % 4 > 0)
+ size += 4 - (size % 4);
+
+ size += (UINT16)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) +
item->name.Length + 1 + item->value.Length;
+
+ le = le->Flink;
+ }
+
+ buf = ExAllocatePoolWithTag(PagedPool, size, ALLOC_TAG);
+ if (!buf) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto end;
+ }
+
+ fcb->ea_xattr.Length = fcb->ea_xattr.MaximumLength = size;
+ fcb->ea_xattr.Buffer = buf;
+
+ fcb->ealen = 4;
+ ea = NULL;
+
+ le = ealist.Flink;
+ while (le != &ealist) {
+ ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
+
+ if (ea) {
+ ea->NextEntryOffset = (ULONG)offsetof(FILE_FULL_EA_INFORMATION, EaName[0])
+ ea->EaNameLength + ea->EaValueLength;
+
+ if (ea->NextEntryOffset % 4 > 0)
+ ea->NextEntryOffset += 4 - (ea->NextEntryOffset % 4);
+
+ ea = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ea) + ea->NextEntryOffset);
+ } else
+ ea = (FILE_FULL_EA_INFORMATION*)fcb->ea_xattr.Buffer;
+
+ ea->NextEntryOffset = 0;
+ ea->Flags = item->flags;
+ ea->EaNameLength = (UCHAR)item->name.Length;
+ ea->EaValueLength = item->value.Length;
+
+ RtlCopyMemory(ea->EaName, item->name.Buffer, item->name.Length);
+ ea->EaName[item->name.Length] = 0;
+ RtlCopyMemory(&ea->EaName[item->name.Length + 1],
item->value.Buffer, item->value.Length);
+
+ fcb->ealen += 5 + item->name.Length + item->value.Length;
+
+ le = le->Flink;
+ }
+
+ fcb->ea_changed = TRUE;
+
+ Status = STATUS_SUCCESS;
+
+end:
+ while (!IsListEmpty(&ealist)) {
+ ea_item* item = CONTAINING_RECORD(RemoveHeadList(&ealist), ea_item,
list_entry);
+
+ ExFreePool(item);
+ }
+
+ return Status;
+}
+
static NTSTATUS file_create2(_In_ PIRP Irp,
_Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _In_
PUNICODE_STRING fpus,
_In_ file_ref* parfileref, _In_ ULONG options,
_In_reads_bytes_opt_(ealen) FILE_FULL_EA_INFORMATION* ea, _In_ ULONG ealen,
_Out_ file_ref** pfr, _In_ LIST_ENTRY* rollback) {
@@ -1843,44 +2075,17 @@ static NTSTATUS file_create2(_In_ PIRP Irp,
_Requires_exclusive_lock_held_(_Curr
fcb->sd_dirty = TRUE;
if (ea && ealen > 0) {
- FILE_FULL_EA_INFORMATION* eainfo;
-
- fcb->ealen = 4;
-
- // capitalize EA names
- eainfo = ea;
- do {
- STRING s;
-
- s.Length = s.MaximumLength = eainfo->EaNameLength;
- s.Buffer = eainfo->EaName;
-
- RtlUpperString(&s, &s);
-
- fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
-
- if (eainfo->NextEntryOffset == 0)
- break;
-
- eainfo = (FILE_FULL_EA_INFORMATION*)(((UINT8*)eainfo) +
eainfo->NextEntryOffset);
- } while (TRUE);
-
- fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(pool_type, ealen, ALLOC_TAG);
- if (!fcb->ea_xattr.Buffer) {
- ERR("out of memory\n");
+ Status = file_create_parse_ea(fcb, ea);
+ if (!NT_SUCCESS(Status)) {
+ ERR("file_create_parse_ea returned %08x\n", Status);
free_fcb(Vcb, fcb);
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource,
TRUE);
parfileref->fcb->inode_item.st_size -= utf8len * 2;
ExReleaseResourceLite(parfileref->fcb->Header.Resource);
- return STATUS_INSUFFICIENT_RESOURCES;
+ return Status;
}
-
- fcb->ea_xattr.Length = fcb->ea_xattr.MaximumLength = (UINT16)ealen;
- RtlCopyMemory(fcb->ea_xattr.Buffer, ea, fcb->ea_xattr.Length);
-
- fcb->ea_changed = TRUE;
}
fileref = create_fileref(Vcb);
@@ -1989,11 +2194,10 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
file_ref *fileref, *newpar, *parfileref;
fcb* fcb;
- static char xapref[] = "user.";
- static WCHAR DOSATTRIB[] = L"DOSATTRIB";
- static WCHAR EA[] = L"EA";
- static WCHAR reparse[] = L"reparse";
- UINT16 xapreflen = (UINT16)strlen(xapref);
+ static const char xapref[] = "user.";
+ static const WCHAR DOSATTRIB[] = L"DOSATTRIB";
+ static const WCHAR EA[] = L"EA";
+ static const WCHAR reparse[] = L"reparse";
LARGE_INTEGER time;
BTRFS_TIME now;
ULONG utf8len, overhead;
@@ -2086,9 +2290,9 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
- if ((stream->Length == wcslen(DOSATTRIB) * sizeof(WCHAR) &&
RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length)
||
- (stream->Length == wcslen(EA) * sizeof(WCHAR) &&
RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) ||
- (stream->Length == wcslen(reparse) * sizeof(WCHAR) &&
RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length)) {
+ if ((stream->Length == sizeof(DOSATTRIB) - sizeof(WCHAR) &&
RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length)
||
+ (stream->Length == sizeof(EA) - sizeof(WCHAR) &&
RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) ||
+ (stream->Length == sizeof(reparse) - sizeof(WCHAR) &&
RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length)) {
return STATUS_OBJECT_NAME_INVALID;
}
@@ -2124,7 +2328,7 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
return Status;
}
- fcb->adsxattr.Length = (UINT16)utf8len + xapreflen;
+ fcb->adsxattr.Length = (UINT16)utf8len + sizeof(xapref) - 1;
fcb->adsxattr.MaximumLength = fcb->adsxattr.Length + 1;
fcb->adsxattr.Buffer = ExAllocatePoolWithTag(pool_type,
fcb->adsxattr.MaximumLength, ALLOC_TAG);
if (!fcb->adsxattr.Buffer) {
@@ -2133,9 +2337,9 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
return STATUS_INSUFFICIENT_RESOURCES;
}
- RtlCopyMemory(fcb->adsxattr.Buffer, xapref, xapreflen);
+ RtlCopyMemory(fcb->adsxattr.Buffer, xapref, sizeof(xapref) - 1);
- Status = RtlUnicodeToUTF8N(&fcb->adsxattr.Buffer[xapreflen], utf8len,
&utf8len, stream->Buffer, stream->Length);
+ Status = RtlUnicodeToUTF8N(&fcb->adsxattr.Buffer[sizeof(xapref) - 1], utf8len,
&utf8len, stream->Buffer, stream->Length);
if (!NT_SUCCESS(Status)) {
ERR("RtlUnicodeToUTF8N 2 returned %08x\n", Status);
free_fcb(Vcb, fcb);
@@ -2167,12 +2371,12 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) -
sizeof(leaf_node) - (sizeof(DIR_ITEM) - 1);
- if (utf8len + xapreflen + overhead > fcb->adsmaxlen) {
- WARN("not enough room for new DIR_ITEM (%u + %u > %u)", utf8len +
xapreflen, overhead, fcb->adsmaxlen);
+ if (utf8len + sizeof(xapref) - 1 + overhead > fcb->adsmaxlen) {
+ WARN("not enough room for new DIR_ITEM (%u + %u > %u)", utf8len +
sizeof(xapref) - 1, overhead, fcb->adsmaxlen);
free_fcb(Vcb, fcb);
return STATUS_DISK_FULL;
} else
- fcb->adsmaxlen -= overhead + utf8len + xapreflen;
+ fcb->adsmaxlen -= overhead + utf8len + sizeof(xapref) - 1;
fileref = create_fileref(Vcb);
if (!fileref) {
@@ -2192,7 +2396,7 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
RtlZeroMemory(dc, sizeof(dir_child));
- dc->utf8.MaximumLength = dc->utf8.Length = fcb->adsxattr.Length -
xapreflen;
+ dc->utf8.MaximumLength = dc->utf8.Length = fcb->adsxattr.Length + 1 -
sizeof(xapref);
dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength,
ALLOC_TAG);
if (!dc->utf8.Buffer) {
ERR("out of memory\n");
@@ -2201,7 +2405,7 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
return STATUS_INSUFFICIENT_RESOURCES;
}
- RtlCopyMemory(dc->utf8.Buffer, &fcb->adsxattr.Buffer[xapreflen],
fcb->adsxattr.Length - xapreflen);
+ RtlCopyMemory(dc->utf8.Buffer, &fcb->adsxattr.Buffer[sizeof(xapref) - 1],
fcb->adsxattr.Length + 1 - sizeof(xapref));
dc->name.MaximumLength = dc->name.Length = stream->Length;
dc->name.Buffer = ExAllocatePoolWithTag(pool_type, dc->name.MaximumLength,
ALLOC_TAG);
@@ -2302,10 +2506,14 @@ static NTSTATUS file_create(PIRP Irp,
_Requires_lock_held_(_Curr_->tree_lock) _R
file_ref *fileref, *parfileref = NULL;
ULONG i, j;
ccb* ccb;
- static WCHAR datasuf[] =
{':','$','D','A','T','A',0};
+ static const WCHAR datasuf[] =
{':','$','D','A','T','A',0};
UNICODE_STRING dsus, fpus, stream;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool :
PagedPool;
+#ifndef __REACTOS__
+ ECP_LIST* ecp_list;
+ ATOMIC_CREATE_ECP_CONTEXT* acec = NULL;
+#endif
#ifdef DEBUG_FCB_REFCOUNTS
LONG oc;
#endif
@@ -2318,8 +2526,27 @@ static NTSTATUS file_create(PIRP Irp,
_Requires_lock_held_(_Curr_->tree_lock) _R
if (options & FILE_DELETE_ON_CLOSE &&
IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_READONLY)
return STATUS_CANNOT_DELETE;
- dsus.Buffer = datasuf;
- dsus.Length = dsus.MaximumLength = (USHORT)wcslen(datasuf) * sizeof(WCHAR);
+#ifndef __REACTOS__
+ if (NT_SUCCESS(FsRtlGetEcpListFromIrp(Irp, &ecp_list)) && ecp_list) {
+ void* ctx = NULL;
+ GUID type;
+ ULONG ctxsize;
+
+ do {
+ Status = FsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type, &ctx,
&ctxsize);
+
+ if (NT_SUCCESS(Status)) {
+ if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE,
sizeof(GUID)) == sizeof(GUID) && ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT))
{
+ acec = ctx;
+ break;
+ }
+ }
+ } while (NT_SUCCESS(Status));
+ }
+#endif
+
+ dsus.Buffer = (WCHAR*)datasuf;
+ dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
fpus.Buffer = NULL;
if (!loaded_related) {
@@ -2451,6 +2678,15 @@ static NTSTATUS file_create(PIRP Irp,
_Requires_lock_held_(_Curr_->tree_lock) _R
if (!ccb) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
+ fileref->deleted = TRUE;
+ fileref->fcb->deleted = TRUE;
+
+ if (stream.Length == 0) {
+ ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource,
TRUE);
+ parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length *
2;
+ ExReleaseResourceLite(parfileref->fcb->Header.Resource);
+ }
+
free_fileref(Vcb, fileref);
goto end;
}
@@ -2484,6 +2720,41 @@ static NTSTATUS file_create(PIRP Irp,
_Requires_lock_held_(_Curr_->tree_lock) _R
FileObject->SectionObjectPointer =
&fileref->fcb->nonpaged->segment_object;
+#ifndef __REACTOS__
+ // FIXME - ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT
+ if (acec && acec->InFlags &
ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED) {
+ if (acec->ReparseBufferLength > sizeof(UINT32) &&
*(UINT32*)acec->ReparseBuffer == IO_REPARSE_TAG_SYMLINK) {
+ fileref->fcb->inode_item.st_mode &= ~(__S_IFIFO | __S_IFCHR |
__S_IFBLK | __S_IFSOCK);
+ fileref->fcb->type = BTRFS_TYPE_FILE;
+ }
+
+ if (fileref->fcb->type == BTRFS_TYPE_SOCKET || fileref->fcb->type ==
BTRFS_TYPE_FIFO ||
+ fileref->fcb->type == BTRFS_TYPE_CHARDEV || fileref->fcb->type ==
BTRFS_TYPE_BLOCKDEV) {
+ // NOP. If called from LXSS, humour it - we hardcode the values elsewhere.
+ } else {
+ Status = set_reparse_point2(fileref->fcb, acec->ReparseBuffer,
acec->ReparseBufferLength, NULL, NULL, Irp, rollback);
+ if (!NT_SUCCESS(Status)) {
+ ERR("set_reparse_point2 returned %08x\n", Status);
+ fileref->deleted = TRUE;
+ fileref->fcb->deleted = TRUE;
+
+ if (stream.Length == 0) {
+
ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
+ parfileref->fcb->inode_item.st_size -=
fileref->dc->utf8.Length * 2;
+ ExReleaseResourceLite(parfileref->fcb->Header.Resource);
+ }
+
+ free_fileref(Vcb, fileref);
+ return Status;
+ }
+ }
+
+ acec->OutFlags |= ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET;
+ }
+#endif
+
+ fileref->dc->type = fileref->fcb->type;
+
goto end2;
end:
@@ -2738,7 +3009,8 @@ static NTSTATUS get_reparse_block(fcb* fcb, UINT8** data) {
}
RtlCopyMemory(*data, fcb->reparse_xattr.Buffer,
fcb->reparse_xattr.Length);
- }
+ } else
+ return STATUS_INVALID_PARAMETER;
return STATUS_SUCCESS;
}
diff --git a/drivers/filesystems/btrfs/dirctrl.c b/drivers/filesystems/btrfs/dirctrl.c
index 64ab60f15a..4d8df559d0 100644
--- a/drivers/filesystems/btrfs/dirctrl.c
+++ b/drivers/filesystems/btrfs/dirctrl.c
@@ -31,16 +31,46 @@ typedef struct {
dir_child* dc;
} dir_entry;
+ULONG get_reparse_tag_fcb(fcb* fcb) {
+ ULONG tag;
+
+ if (fcb->type == BTRFS_TYPE_SYMLINK)
+ return IO_REPARSE_TAG_SYMLINK;
+ else if (fcb->type == BTRFS_TYPE_DIRECTORY) {
+ if (!fcb->reparse_xattr.Buffer || fcb->reparse_xattr.Length <
sizeof(ULONG))
+ return 0;
+
+ RtlCopyMemory(&tag, fcb->reparse_xattr.Buffer, sizeof(ULONG));
+ } else {
+ NTSTATUS Status;
+ ULONG br;
+
+ Status = read_file(fcb, (UINT8*)&tag, 0, sizeof(ULONG), &br, NULL);
+ if (!NT_SUCCESS(Status)) {
+ ERR("read_file returned %08x\n", Status);
+ return 0;
+ }
+ }
+
+ return tag;
+}
+
ULONG get_reparse_tag(device_extension* Vcb, root* subvol, UINT64 inode, UINT8 type,
ULONG atts, BOOL lxss, PIRP Irp) {
fcb* fcb;
- ULONG tag = 0, br;
+ ULONG tag = 0;
NTSTATUS Status;
- if (type == BTRFS_TYPE_SYMLINK) {
- if (lxss)
- return IO_REPARSE_TAG_LXSS_SYMLINK;
- else
- return IO_REPARSE_TAG_SYMLINK;
+ if (type == BTRFS_TYPE_SYMLINK)
+ return IO_REPARSE_TAG_SYMLINK;
+ else if (lxss) {
+ if (type == BTRFS_TYPE_SOCKET)
+ return IO_REPARSE_TAG_LXSS_SOCKET;
+ else if (type == BTRFS_TYPE_FIFO)
+ return IO_REPARSE_TAG_LXSS_FIFO;
+ else if (type == BTRFS_TYPE_CHARDEV)
+ return IO_REPARSE_TAG_LXSS_CHARDEV;
+ else if (type == BTRFS_TYPE_BLOCKDEV)
+ return IO_REPARSE_TAG_LXSS_BLOCKDEV;
}
if (type != BTRFS_TYPE_FILE && type != BTRFS_TYPE_DIRECTORY)
@@ -57,23 +87,8 @@ ULONG get_reparse_tag(device_extension* Vcb, root* subvol, UINT64
inode, UINT8 t
ExAcquireResourceSharedLite(fcb->Header.Resource, TRUE);
- if (type == BTRFS_TYPE_DIRECTORY) {
- if (!fcb->reparse_xattr.Buffer || fcb->reparse_xattr.Length <
sizeof(ULONG))
- goto end;
-
- RtlCopyMemory(&tag, fcb->reparse_xattr.Buffer, sizeof(ULONG));
- } else {
- Status = read_file(fcb, (UINT8*)&tag, 0, sizeof(ULONG), &br, NULL);
- if (!NT_SUCCESS(Status)) {
- ERR("read_file returned %08x\n", Status);
- goto end;
- }
-
- if (br < sizeof(ULONG))
- goto end;
- }
+ tag = get_reparse_tag_fcb(fcb);
-end:
ExReleaseResourceLite(fcb->Header.Resource);
free_fcb(Vcb, fcb);
@@ -675,11 +690,7 @@ static NTSTATUS query_directory(PIRP Irp) {
if (IrpSp->Parameters.QueryDirectory.FileName &&
IrpSp->Parameters.QueryDirectory.FileName->Length > 1) {
TRACE("QD filename: %.*S\n",
IrpSp->Parameters.QueryDirectory.FileName->Length / sizeof(WCHAR),
IrpSp->Parameters.QueryDirectory.FileName->Buffer);
-#ifndef __REACTOS__
- if (IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != '*') {
-#else
if (IrpSp->Parameters.QueryDirectory.FileName->Length > sizeof(WCHAR) ||
IrpSp->Parameters.QueryDirectory.FileName->Buffer[0] != L'*') {
-#endif
specific_file = TRUE;
if
(FsRtlDoesNameContainWildCards(IrpSp->Parameters.QueryDirectory.FileName)) {
diff --git a/drivers/filesystems/btrfs/fastio.c b/drivers/filesystems/btrfs/fastio.c
index 9f4c504a12..9ee282d04c 100644
--- a/drivers/filesystems/btrfs/fastio.c
+++ b/drivers/filesystems/btrfs/fastio.c
@@ -296,11 +296,21 @@ static NTSTATUS fast_io_acquire_for_mod_write(PFILE_OBJECT
FileObject, PLARGE_IN
if (!fcb)
return STATUS_INVALID_PARAMETER;
- *ResourceToRelease = fcb->Header.PagingIoResource;
+ // Make sure we don't get interrupted by the flush thread, which can cause a
deadlock
- if (!ExAcquireResourceSharedLite(*ResourceToRelease, FALSE))
+ if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, FALSE))
return STATUS_CANT_WAIT;
+ // Ideally this would be PagingIoResource, but that doesn't play well with
copy-on-write,
+ // as we can't guarantee that we won't need to do any reallocations.
+
+ *ResourceToRelease = fcb->Header.Resource;
+
+ if (!ExAcquireResourceExclusiveLite(*ResourceToRelease, FALSE)) {
+ ExReleaseResourceLite(&fcb->Vcb->tree_lock);
+ return STATUS_CANT_WAIT;
+ }
+
return STATUS_SUCCESS;
}
@@ -310,11 +320,16 @@ static NTSTATUS NTAPI fast_io_release_for_mod_write(PFILE_OBJECT
FileObject, str
#else
static NTSTATUS fast_io_release_for_mod_write(PFILE_OBJECT FileObject, struct _ERESOURCE
*ResourceToRelease, PDEVICE_OBJECT DeviceObject) {
#endif
- UNUSED(FileObject);
+ fcb* fcb;
+
UNUSED(DeviceObject);
+ fcb = FileObject->FsContext;
+
ExReleaseResourceLite(ResourceToRelease);
+ ExReleaseResourceLite(&fcb->Vcb->tree_lock);
+
return STATUS_SUCCESS;
}
diff --git a/drivers/filesystems/btrfs/fileinfo.c b/drivers/filesystems/btrfs/fileinfo.c
index 1d03a669f4..1c342b0f55 100644
--- a/drivers/filesystems/btrfs/fileinfo.c
+++ b/drivers/filesystems/btrfs/fileinfo.c
@@ -21,6 +21,34 @@
// not currently in mingw - introduced with Windows 10
#ifndef FileIdInformation
#define FileIdInformation (enum _FILE_INFORMATION_CLASS)59
+#define FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70
+
+typedef struct _FILE_STAT_LX_INFORMATION {
+ LARGE_INTEGER FileId;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER AllocationSize;
+ LARGE_INTEGER EndOfFile;
+ ULONG FileAttributes;
+ ULONG ReparseTag;
+ ULONG NumberOfLinks;
+ ACCESS_MASK EffectiveAccess;
+ ULONG LxFlags;
+ ULONG LxUid;
+ ULONG LxGid;
+ ULONG LxMode;
+ ULONG LxDeviceIdMajor;
+ ULONG LxDeviceIdMinor;
+} FILE_STAT_LX_INFORMATION, *PFILE_STAT_LX_INFORMATION;
+
+#define LX_FILE_METADATA_HAS_UID 0x01
+#define LX_FILE_METADATA_HAS_GID 0x02
+#define LX_FILE_METADATA_HAS_MODE 0x04
+#define LX_FILE_METADATA_HAS_DEVICE_ID 0x08
+#define LX_FILE_CASE_SENSITIVE_DIR 0x10
+
#endif
#endif
@@ -70,6 +98,20 @@ static NTSTATUS set_basic_information(device_extension* Vcb, PIRP Irp,
PFILE_OBJ
goto end;
}
+ // times of -2 are some sort of undocumented behaviour to do with LXSS
+
+ if (fbi->CreationTime.QuadPart == -2)
+ fbi->CreationTime.QuadPart = 0;
+
+ if (fbi->LastAccessTime.QuadPart == -2)
+ fbi->LastAccessTime.QuadPart = 0;
+
+ if (fbi->LastWriteTime.QuadPart == -2)
+ fbi->LastWriteTime.QuadPart = 0;
+
+ if (fbi->ChangeTime.QuadPart == -2)
+ fbi->ChangeTime.QuadPart = 0;
+
if (fbi->CreationTime.QuadPart == -1)
ccb->user_set_creation_time = TRUE;
else if (fbi->CreationTime.QuadPart != 0) {
@@ -2946,8 +2988,8 @@ static NTSTATUS fill_in_file_name_information(FILE_NAME_INFORMATION*
fni, fcb* f
ULONG reqlen;
UNICODE_STRING fn;
NTSTATUS Status;
- static WCHAR datasuf[] =
{':','$','D','A','T','A',0};
- UINT16 datasuflen = (UINT16)wcslen(datasuf) * sizeof(WCHAR);
+ static const WCHAR datasuf[] =
{':','$','D','A','T','A',0};
+ UINT16 datasuflen = sizeof(datasuf) - sizeof(WCHAR);
if (!fileref) {
ERR("called without fileref\n");
@@ -2999,7 +3041,7 @@ static NTSTATUS fill_in_file_name_information(FILE_NAME_INFORMATION*
fni, fcb* f
return Status;
}
-static NTSTATUS fill_in_file_attribute_information(FILE_ATTRIBUTE_TAG_INFORMATION* ati,
fcb* fcb, ccb* ccb, PIRP Irp, LONG* length) {
+static NTSTATUS fill_in_file_attribute_information(FILE_ATTRIBUTE_TAG_INFORMATION* ati,
fcb* fcb, ccb* ccb, LONG* length) {
*length -= sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
if (fcb->ads) {
@@ -3015,7 +3057,7 @@ static NTSTATUS
fill_in_file_attribute_information(FILE_ATTRIBUTE_TAG_INFORMATIO
if (!(ati->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
ati->ReparseTag = 0;
else
- ati->ReparseTag = get_reparse_tag(fcb->Vcb, fcb->subvol, fcb->inode,
fcb->type, fcb->atts, ccb->lxss, Irp);
+ ati->ReparseTag = get_reparse_tag_fcb(fcb);
return STATUS_SUCCESS;
}
@@ -3026,7 +3068,7 @@ static NTSTATUS
fill_in_file_stream_information(FILE_STREAM_INFORMATION* fsi, fi
FILE_STREAM_INFORMATION *entry, *lastentry;
NTSTATUS Status;
- static WCHAR datasuf[] = L":$DATA";
+ static const WCHAR datasuf[] = L":$DATA";
UNICODE_STRING suf;
if (!fileref) {
@@ -3034,8 +3076,8 @@ static NTSTATUS
fill_in_file_stream_information(FILE_STREAM_INFORMATION* fsi, fi
return STATUS_INVALID_PARAMETER;
}
- suf.Buffer = datasuf;
- suf.Length = suf.MaximumLength = (UINT16)wcslen(datasuf) * sizeof(WCHAR);
+ suf.Buffer = (WCHAR*)datasuf;
+ suf.Length = suf.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY)
reqsize = sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR) + suf.Length +
sizeof(WCHAR);
@@ -3606,6 +3648,80 @@ static NTSTATUS fill_in_file_id_information(FILE_ID_INFORMATION*
fii, fcb* fcb,
}
#endif
+#ifndef __REACTOS__
+static NTSTATUS fill_in_file_stat_lx_information(FILE_STAT_LX_INFORMATION* fsli, fcb*
fcb, ccb* ccb, LONG* length) {
+ INODE_ITEM* ii;
+
+ fsli->FileId.LowPart = (UINT32)fcb->inode;
+ fsli->FileId.HighPart = (UINT32)fcb->subvol->id;
+
+ if (fcb->ads)
+ ii = &ccb->fileref->parent->fcb->inode_item;
+ else
+ ii = &fcb->inode_item;
+
+ if (fcb == fcb->Vcb->dummy_fcb) {
+ LARGE_INTEGER time;
+
+ KeQuerySystemTime(&time);
+ fsli->CreationTime = fsli->LastAccessTime = fsli->LastWriteTime =
fsli->ChangeTime = time;
+ } else {
+ fsli->CreationTime.QuadPart = unix_time_to_win(&ii->otime);
+ fsli->LastAccessTime.QuadPart = unix_time_to_win(&ii->st_atime);
+ fsli->LastWriteTime.QuadPart = unix_time_to_win(&ii->st_mtime);
+ fsli->ChangeTime.QuadPart = unix_time_to_win(&ii->st_ctime);
+ }
+
+ if (fcb->ads) {
+ fsli->AllocationSize.QuadPart = fsli->EndOfFile.QuadPart =
fcb->adsdata.Length;
+ fsli->FileAttributes = ccb->fileref->parent->fcb->atts == 0 ?
FILE_ATTRIBUTE_NORMAL : ccb->fileref->parent->fcb->atts;
+ } else {
+ fsli->AllocationSize.QuadPart = fcb_alloc_size(fcb);
+ fsli->EndOfFile.QuadPart = S_ISDIR(fcb->inode_item.st_mode) ? 0 :
fcb->inode_item.st_size;
+ fsli->FileAttributes = fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL :
fcb->atts;
+ }
+
+ if (fcb->type == BTRFS_TYPE_SOCKET)
+ fsli->ReparseTag = IO_REPARSE_TAG_LXSS_SOCKET;
+ else if (fcb->type == BTRFS_TYPE_FIFO)
+ fsli->ReparseTag = IO_REPARSE_TAG_LXSS_FIFO;
+ else if (fcb->type == BTRFS_TYPE_CHARDEV)
+ fsli->ReparseTag = IO_REPARSE_TAG_LXSS_CHARDEV;
+ else if (fcb->type == BTRFS_TYPE_BLOCKDEV)
+ fsli->ReparseTag = IO_REPARSE_TAG_LXSS_BLOCKDEV;
+ else if (!(fsli->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
+ fsli->ReparseTag = 0;
+ else
+ fsli->ReparseTag = get_reparse_tag_fcb(fcb);
+
+ if (fcb->type == BTRFS_TYPE_SOCKET || fcb->type == BTRFS_TYPE_FIFO ||
fcb->type == BTRFS_TYPE_CHARDEV || fcb->type == BTRFS_TYPE_BLOCKDEV)
+ fsli->FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
+
+ if (fcb->ads)
+ fsli->NumberOfLinks =
ccb->fileref->parent->fcb->inode_item.st_nlink;
+ else
+ fsli->NumberOfLinks = fcb->inode_item.st_nlink;
+
+ fsli->EffectiveAccess = ccb->access;
+ fsli->LxFlags = LX_FILE_METADATA_HAS_UID | LX_FILE_METADATA_HAS_GID |
LX_FILE_METADATA_HAS_MODE | LX_FILE_METADATA_HAS_DEVICE_ID; // FIXME -
LX_FILE_CASE_SENSITIVE_DIR
+ fsli->LxUid = ii->st_uid;
+ fsli->LxGid = ii->st_gid;
+ fsli->LxMode = ii->st_mode;
+
+ if (ii->st_mode & __S_IFBLK || ii->st_mode & __S_IFCHR) {
+ fsli->LxDeviceIdMajor = (ii->st_rdev & 0xFFFFFFFFFFF00000) >>
20;
+ fsli->LxDeviceIdMinor = (ii->st_rdev & 0xFFFFF);
+ } else {
+ fsli->LxDeviceIdMajor = 0;
+ fsli->LxDeviceIdMinor = 0;
+ }
+
+ *length -= sizeof(FILE_STAT_LX_INFORMATION);
+
+ return STATUS_SUCCESS;
+}
+#endif
+
static NTSTATUS query_info(device_extension* Vcb, PFILE_OBJECT FileObject, PIRP Irp) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
LONG length = IrpSp->Parameters.QueryFile.Length;
@@ -3694,7 +3810,7 @@ static NTSTATUS query_info(device_extension* Vcb, PFILE_OBJECT
FileObject, PIRP
}
ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
- Status = fill_in_file_attribute_information(ati, fcb, ccb, Irp,
&length);
+ Status = fill_in_file_attribute_information(ati, fcb, ccb, &length);
ExReleaseResourceLite(&Vcb->tree_lock);
break;
@@ -3893,6 +4009,23 @@ static NTSTATUS query_info(device_extension* Vcb, PFILE_OBJECT
FileObject, PIRP
break;
}
+
+ case FileStatLxInformation:
+ {
+ FILE_STAT_LX_INFORMATION* fsli = Irp->AssociatedIrp.SystemBuffer;
+
+ if (IrpSp->Parameters.QueryFile.Length <
sizeof(FILE_STAT_LX_INFORMATION)) {
+ WARN("overflow\n");
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto exit;
+ }
+
+ TRACE("FileStatLxInformation\n");
+
+ Status = fill_in_file_stat_lx_information(fsli, fcb, ccb, &length);
+
+ break;
+ }
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
@@ -4194,13 +4327,6 @@ end:
return Status;
}
-typedef struct {
- ANSI_STRING name;
- ANSI_STRING value;
- UCHAR flags;
- LIST_ENTRY list_entry;
-} ea_item;
-
_Dispatch_type_(IRP_MJ_SET_EA)
_Function_class_(DRIVER_DISPATCH)
NTSTATUS NTAPI drv_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
@@ -4386,6 +4512,64 @@ NTSTATUS NTAPI drv_set_ea(IN PDEVICE_OBJECT DeviceObject, IN PIRP
Irp) {
le = le2;
}
+ // handle LXSS values
+ le = ealist.Flink;
+ while (le != &ealist) {
+ LIST_ENTRY* le2 = le->Flink;
+
+ item = CONTAINING_RECORD(le, ea_item, list_entry);
+
+ if (item->name.Length == sizeof(lxuid) - 1 &&
RtlCompareMemory(item->name.Buffer, lxuid, item->name.Length) ==
item->name.Length) {
+ if (item->value.Length < sizeof(UINT32)) {
+ ERR("uid value was shorter than expected\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto end2;
+ }
+
+ if (Irp->RequestorMode == KernelMode) {
+ RtlCopyMemory(&fcb->inode_item.st_uid, item->value.Buffer,
sizeof(UINT32));
+ fcb->sd_dirty = TRUE;
+ fcb->sd_deleted = FALSE;
+ }
+
+ RemoveEntryList(&item->list_entry);
+ ExFreePool(item);
+ } else if (item->name.Length == sizeof(lxgid) - 1 &&
RtlCompareMemory(item->name.Buffer, lxgid, item->name.Length) ==
item->name.Length) {
+ if (item->value.Length < sizeof(UINT32)) {
+ ERR("gid value was shorter than expected\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto end2;
+ }
+
+ if (Irp->RequestorMode == KernelMode)
+ RtlCopyMemory(&fcb->inode_item.st_gid, item->value.Buffer,
sizeof(UINT32));
+
+ RemoveEntryList(&item->list_entry);
+ ExFreePool(item);
+ } else if (item->name.Length == sizeof(lxmod) - 1 &&
RtlCompareMemory(item->name.Buffer, lxmod, item->name.Length) ==
item->name.Length) {
+ if (item->value.Length < sizeof(UINT32)) {
+ ERR("mode value was shorter than expected\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto end2;
+ }
+
+ if (Irp->RequestorMode == KernelMode) {
+ UINT32 allowed = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP |
S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH | S_ISGID | S_ISVTX | S_ISUID;
+ UINT32 val;
+
+ RtlCopyMemory(&val, item->value.Buffer, sizeof(UINT32));
+
+ fcb->inode_item.st_mode &= ~allowed;
+ fcb->inode_item.st_mode |= val & allowed;
+ }
+
+ RemoveEntryList(&item->list_entry);
+ ExFreePool(item);
+ }
+
+ le = le2;
+ }
+
if (IsListEmpty(&ealist)) {
fcb->ealen = 0;
diff --git a/drivers/filesystems/btrfs/flushthread.c
b/drivers/filesystems/btrfs/flushthread.c
index 9e95f82834..6353abb583 100644
--- a/drivers/filesystems/btrfs/flushthread.c
+++ b/drivers/filesystems/btrfs/flushthread.c
@@ -316,14 +316,14 @@ static void clean_space_cache(device_extension* Vcb) {
c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->space_changed) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if (c->space_changed)
clean_space_cache_chunk(Vcb, c);
c->space_changed = FALSE;
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
}
le = le->Flink;
@@ -599,11 +599,11 @@ static BOOL insert_tree_extent_skinny(device_extension* Vcb, UINT8
level, UINT64
return FALSE;
}
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
space_list_subtract(c, FALSE, address, Vcb->superblock.node_size, rollback);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
add_parents_to_cache(insert_tp.tree);
@@ -731,11 +731,11 @@ static BOOL insert_tree_extent(device_extension* Vcb, UINT8 level,
UINT64 root_i
return FALSE;
}
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
space_list_subtract(c, FALSE, address, Vcb->superblock.node_size, rollback);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
add_parents_to_cache(insert_tp.tree);
@@ -773,11 +773,11 @@ NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP
Irp, LIST_ENT
c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if (c != origchunk && c->chunk_item->type == flags &&
(c->chunk_item->size - c->used) >= Vcb->superblock.node_size) {
if (insert_tree_extent(Vcb, t->header.level, t->root->id, c,
&addr, Irp, rollback)) {
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
t->new_address = addr;
t->has_new_address = TRUE;
@@ -785,7 +785,7 @@ NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP
Irp, LIST_ENT
}
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
}
le = le->Flink;
@@ -801,11 +801,11 @@ NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP
Irp, LIST_ENT
return Status;
}
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if ((c->chunk_item->size - c->used) >= Vcb->superblock.node_size) {
if (insert_tree_extent(Vcb, t->header.level, t->root->id, c, &addr,
Irp, rollback)) {
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
t->new_address = addr;
t->has_new_address = TRUE;
@@ -813,7 +813,7 @@ NTSTATUS get_tree_new_address(device_extension* Vcb, tree* t, PIRP
Irp, LIST_ENT
}
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
@@ -849,14 +849,14 @@ static NTSTATUS reduce_tree_extent(device_extension* Vcb, UINT64
address, tree*
chunk* c = get_chunk_from_address(Vcb, address);
if (c) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if (!c->cache_loaded) {
Status = load_cache_chunk(Vcb, c, NULL);
if (!NT_SUCCESS(Status)) {
ERR("load_cache_chunk returned %08x\n", Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
return Status;
}
}
@@ -865,7 +865,7 @@ static NTSTATUS reduce_tree_extent(device_extension* Vcb, UINT64
address, tree*
space_list_add(c, address, Vcb->superblock.node_size, rollback);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
} else
ERR("could not find chunk for address %llx\n", address);
}
@@ -1351,19 +1351,19 @@ static NTSTATUS allocate_tree_extents(device_extension* Vcb, PIRP
Irp, LIST_ENTR
if (c) {
if (!c->cache_loaded) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if (!c->cache_loaded) {
Status = load_cache_chunk(Vcb, c, NULL);
if (!NT_SUCCESS(Status)) {
ERR("load_cache_chunk returned %08x\n",
Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
return Status;
}
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
}
}
}
@@ -2644,14 +2644,14 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP
Irp, LIST_ENTRY*
while (le != &Vcb->chunks) {
c = CONTAINING_RECORD(le, chunk, list_entry);
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if (!c->cache_loaded && (!IsListEmpty(&c->changed_extents) ||
c->used != c->oldused)) {
Status = load_cache_chunk(Vcb, c, NULL);
if (!NT_SUCCESS(Status)) {
ERR("load_cache_chunk returned %08x\n", Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
goto end;
}
}
@@ -2664,7 +2664,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp,
LIST_ENTRY*
Status = flush_changed_extent(Vcb, c, ce, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("flush_changed_extent returned %08x\n", Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
goto end;
}
@@ -2677,7 +2677,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp,
LIST_ENTRY*
Status = create_chunk(Vcb, c, Irp);
if (!NT_SUCCESS(Status)) {
ERR("create_chunk returned %08x\n", Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
goto end;
}
}
@@ -2691,7 +2691,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp,
LIST_ENTRY*
Status = flush_fcb(c->old_cache, FALSE, &batchlist, Irp);
if (!NT_SUCCESS(Status)) {
ERR("flush_fcb returned %08x\n", Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
clear_batch_list(Vcb, &batchlist);
goto end;
}
@@ -2699,7 +2699,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp,
LIST_ENTRY*
Status = commit_batch_list(Vcb, &batchlist, Irp);
if (!NT_SUCCESS(Status)) {
ERR("commit_batch_list returned %08x\n", Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
goto end;
}
}
@@ -2716,21 +2716,21 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP
Irp, LIST_ENTRY*
Status = find_item(Vcb, Vcb->extent_root, &tp, &searchkey, FALSE,
Irp);
if (!NT_SUCCESS(Status)) {
ERR("error - find_item returned %08x\n", Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
goto end;
}
if (keycmp(searchkey, tp.item->key)) {
ERR("could not find (%llx,%x,%llx) in extent_root\n",
searchkey.obj_id, searchkey.obj_type, searchkey.offset);
Status = STATUS_INTERNAL_ERROR;
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
goto end;
}
if (tp.item->size < sizeof(BLOCK_GROUP_ITEM)) {
ERR("(%llx,%x,%llx) was %u bytes, expected %u\n",
tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
tp.item->size, sizeof(BLOCK_GROUP_ITEM));
Status = STATUS_INTERNAL_ERROR;
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
goto end;
}
@@ -2738,7 +2738,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp,
LIST_ENTRY*
if (!bgi) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
goto end;
}
@@ -2751,7 +2751,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp,
LIST_ENTRY*
if (!NT_SUCCESS(Status)) {
ERR("delete_tree_item returned %08x\n", Status);
ExFreePool(bgi);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
goto end;
}
@@ -2759,7 +2759,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp,
LIST_ENTRY*
if (!NT_SUCCESS(Status)) {
ERR("insert_tree_item returned %08x\n", Status);
ExFreePool(bgi);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
goto end;
}
@@ -2772,7 +2772,7 @@ static NTSTATUS update_chunk_usage(device_extension* Vcb, PIRP Irp,
LIST_ENTRY*
c->oldused = c->used;
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
le = le->Flink;
}
@@ -4414,14 +4414,14 @@ cont:
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM))
add_checksum_entry(fcb->Vcb, er->address,
(ULONG)(er->skip_start / fcb->Vcb->superblock.sector_size), NULL, NULL);
- ExAcquireResourceExclusiveLite(&er->chunk->lock, TRUE);
+ acquire_chunk_lock(er->chunk, fcb->Vcb);
if (!er->chunk->cache_loaded) {
NTSTATUS Status = load_cache_chunk(fcb->Vcb, er->chunk, NULL);
if (!NT_SUCCESS(Status)) {
ERR("load_cache_chunk returned %08x\n", Status);
- ExReleaseResourceLite(&er->chunk->lock);
+ release_chunk_lock(er->chunk, fcb->Vcb);
goto end;
}
}
@@ -4430,7 +4430,7 @@ cont:
space_list_add(er->chunk, er->address, er->skip_start, NULL);
- ExReleaseResourceLite(&er->chunk->lock);
+ release_chunk_lock(er->chunk, fcb->Vcb);
er->address += er->skip_start;
er->length -= er->skip_start;
@@ -4468,14 +4468,14 @@ cont:
if (!(fcb->inode_item.flags & BTRFS_INODE_NODATASUM))
add_checksum_entry(fcb->Vcb, er->address + er->length -
er->skip_end, (ULONG)(er->skip_end / fcb->Vcb->superblock.sector_size), NULL,
NULL);
- ExAcquireResourceExclusiveLite(&er->chunk->lock, TRUE);
+ acquire_chunk_lock(er->chunk, fcb->Vcb);
if (!er->chunk->cache_loaded) {
NTSTATUS Status = load_cache_chunk(fcb->Vcb, er->chunk, NULL);
if (!NT_SUCCESS(Status)) {
ERR("load_cache_chunk returned %08x\n", Status);
- ExReleaseResourceLite(&er->chunk->lock);
+ release_chunk_lock(er->chunk, fcb->Vcb);
goto end;
}
}
@@ -4484,7 +4484,7 @@ cont:
space_list_add(er->chunk, er->address + er->length -
er->skip_end, er->skip_end, NULL);
- ExReleaseResourceLite(&er->chunk->lock);
+ release_chunk_lock(er->chunk, fcb->Vcb);
er->length -= er->skip_end;
}
@@ -4924,14 +4924,14 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist,
PIRP Irp) {
if (fcb->sd_dirty) {
if (!fcb->sd_deleted) {
- Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_NTACL, (UINT16)strlen(EA_NTACL),
+ Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_NTACL, sizeof(EA_NTACL) - 1,
EA_NTACL_HASH, (UINT8*)fcb->sd,
(UINT16)RtlLengthSecurityDescriptor(fcb->sd));
if (!NT_SUCCESS(Status)) {
ERR("set_xattr returned %08x\n", Status);
goto end;
}
} else {
- Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_NTACL, (UINT16)strlen(EA_NTACL), EA_NTACL_HASH);
+ Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_NTACL, sizeof(EA_NTACL) - 1, EA_NTACL_HASH);
if (!NT_SUCCESS(Status)) {
ERR("delete_xattr returned %08x\n", Status);
goto end;
@@ -4966,14 +4966,14 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist,
PIRP Irp) {
val2--;
*val2 = '0';
- Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_DOSATTRIB, (UINT16)strlen(EA_DOSATTRIB),
+ Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_DOSATTRIB, sizeof(EA_DOSATTRIB) - 1,
EA_DOSATTRIB_HASH, val2, (UINT16)(val + sizeof(val) -
val2));
if (!NT_SUCCESS(Status)) {
ERR("set_xattr returned %08x\n", Status);
goto end;
}
} else {
- Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_DOSATTRIB, (UINT16)strlen(EA_DOSATTRIB), EA_DOSATTRIB_HASH);
+ Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_DOSATTRIB, sizeof(EA_DOSATTRIB) - 1, EA_DOSATTRIB_HASH);
if (!NT_SUCCESS(Status)) {
ERR("delete_xattr returned %08x\n", Status);
goto end;
@@ -4986,14 +4986,14 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist,
PIRP Irp) {
if (fcb->reparse_xattr_changed) {
if (fcb->reparse_xattr.Buffer && fcb->reparse_xattr.Length > 0)
{
- Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_REPARSE, (UINT16)strlen(EA_REPARSE),
+ Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_REPARSE, sizeof(EA_REPARSE) - 1,
EA_REPARSE_HASH, (UINT8*)fcb->reparse_xattr.Buffer,
(UINT16)fcb->reparse_xattr.Length);
if (!NT_SUCCESS(Status)) {
ERR("set_xattr returned %08x\n", Status);
goto end;
}
} else {
- Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_REPARSE, (UINT16)strlen(EA_REPARSE), EA_REPARSE_HASH);
+ Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_REPARSE, sizeof(EA_REPARSE) - 1, EA_REPARSE_HASH);
if (!NT_SUCCESS(Status)) {
ERR("delete_xattr returned %08x\n", Status);
goto end;
@@ -5005,14 +5005,14 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist,
PIRP Irp) {
if (fcb->ea_changed) {
if (fcb->ea_xattr.Buffer && fcb->ea_xattr.Length > 0) {
- Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_EA, (UINT16)strlen(EA_EA),
+ Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_EA, sizeof(EA_EA) - 1,
EA_EA_HASH, (UINT8*)fcb->ea_xattr.Buffer,
(UINT16)fcb->ea_xattr.Length);
if (!NT_SUCCESS(Status)) {
ERR("set_xattr returned %08x\n", Status);
goto end;
}
} else {
- Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_EA, (UINT16)strlen(EA_EA), EA_EA_HASH);
+ Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_EA, sizeof(EA_EA) - 1, EA_EA_HASH);
if (!NT_SUCCESS(Status)) {
ERR("delete_xattr returned %08x\n", Status);
goto end;
@@ -5024,25 +5024,34 @@ NTSTATUS flush_fcb(fcb* fcb, BOOL cache, LIST_ENTRY* batchlist,
PIRP Irp) {
if (fcb->prop_compression_changed) {
if (fcb->prop_compression == PropCompression_None) {
- Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_PROP_COMPRESSION, (UINT16)strlen(EA_PROP_COMPRESSION), EA_PROP_COMPRESSION_HASH);
+ Status = delete_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1, EA_PROP_COMPRESSION_HASH);
if (!NT_SUCCESS(Status)) {
ERR("delete_xattr returned %08x\n", Status);
goto end;
}
} else if (fcb->prop_compression == PropCompression_Zlib) {
- const char zlib[] = "zlib";
+ static const char zlib[] = "zlib";
- Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_PROP_COMPRESSION, (UINT16)strlen(EA_PROP_COMPRESSION),
- EA_PROP_COMPRESSION_HASH, (UINT8*)zlib,
(UINT16)strlen(zlib));
+ Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1,
+ EA_PROP_COMPRESSION_HASH, (UINT8*)zlib, sizeof(zlib) -
1);
if (!NT_SUCCESS(Status)) {
ERR("set_xattr returned %08x\n", Status);
goto end;
}
} else if (fcb->prop_compression == PropCompression_LZO) {
- const char lzo[] = "lzo";
+ static const char lzo[] = "lzo";
- Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_PROP_COMPRESSION, (UINT16)strlen(EA_PROP_COMPRESSION),
- EA_PROP_COMPRESSION_HASH, (UINT8*)lzo,
(UINT16)strlen(lzo));
+ Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1,
+ EA_PROP_COMPRESSION_HASH, (UINT8*)lzo, sizeof(lzo) - 1);
+ if (!NT_SUCCESS(Status)) {
+ ERR("set_xattr returned %08x\n", Status);
+ goto end;
+ }
+ } else if (fcb->prop_compression == PropCompression_ZSTD) {
+ static const char zstd[] = "zstd";
+
+ Status = set_xattr(fcb->Vcb, batchlist, fcb->subvol, fcb->inode,
EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1,
+ EA_PROP_COMPRESSION_HASH, (UINT8*)zstd, sizeof(zstd) -
1);
if (!NT_SUCCESS(Status)) {
ERR("set_xattr returned %08x\n", Status);
goto end;
@@ -5282,29 +5291,26 @@ static NTSTATUS drop_chunk(device_extension* Vcb, chunk* c,
LIST_ENTRY* batchlis
return Status;
}
- if (keycmp(tp.item->key, searchkey)) {
- ERR("error - could not find DEV_ITEM for device %llx\n",
searchkey.offset);
- return STATUS_INTERNAL_ERROR;
- }
-
- Status = delete_tree_item(Vcb, &tp);
- if (!NT_SUCCESS(Status)) {
- ERR("delete_tree_item returned %08x\n", Status);
- return Status;
- }
+ if (!keycmp(tp.item->key, searchkey)) {
+ Status = delete_tree_item(Vcb, &tp);
+ if (!NT_SUCCESS(Status)) {
+ ERR("delete_tree_item returned %08x\n", Status);
+ return Status;
+ }
- di = ExAllocatePoolWithTag(PagedPool, sizeof(DEV_ITEM), ALLOC_TAG);
- if (!di) {
- ERR("out of memory\n");
- return STATUS_INSUFFICIENT_RESOURCES;
- }
+ di = ExAllocatePoolWithTag(PagedPool, sizeof(DEV_ITEM), ALLOC_TAG);
+ if (!di) {
+ ERR("out of memory\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
- RtlCopyMemory(di, &c->devices[i]->devitem, sizeof(DEV_ITEM));
+ RtlCopyMemory(di, &c->devices[i]->devitem, sizeof(DEV_ITEM));
- Status = insert_tree_item(Vcb, Vcb->chunk_root, 1, TYPE_DEV_ITEM,
c->devices[i]->devitem.dev_id, di, sizeof(DEV_ITEM), NULL, Irp);
- if (!NT_SUCCESS(Status)) {
- ERR("insert_tree_item returned %08x\n", Status);
- return Status;
+ Status = insert_tree_item(Vcb, Vcb->chunk_root, 1, TYPE_DEV_ITEM,
c->devices[i]->devitem.dev_id, di, sizeof(DEV_ITEM), NULL, Irp);
+ if (!NT_SUCCESS(Status)) {
+ ERR("insert_tree_item returned %08x\n", Status);
+ return Status;
+ }
}
for (j = i + 1; j < c->chunk_item->num_stripes; j++) {
@@ -5404,6 +5410,8 @@ static NTSTATUS drop_chunk(device_extension* Vcb, chunk* c,
LIST_ENTRY* batchlis
ExFreePool(s);
}
+ release_chunk_lock(c, Vcb);
+
ExDeleteResourceLite(&c->partial_stripes_lock);
ExDeleteResourceLite(&c->range_locks_lock);
ExDeleteResourceLite(&c->lock);
@@ -5718,7 +5726,7 @@ static NTSTATUS update_chunks(device_extension* Vcb, LIST_ENTRY*
batchlist, PIRP
le2 = le->Flink;
if (c->changed) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
// flush partial stripes
if (!Vcb->readonly && (c->chunk_item->type &
BLOCK_FLAG_RAID5 || c->chunk_item->type & BLOCK_FLAG_RAID6)) {
@@ -5737,7 +5745,7 @@ static NTSTATUS update_chunks(device_extension* Vcb, LIST_ENTRY*
batchlist, PIRP
if (!NT_SUCCESS(Status)) {
ERR("flush_partial_stripe returned %08x\n", Status);
ExReleaseResourceLite(&c->partial_stripes_lock);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
return Status;
}
@@ -5747,12 +5755,14 @@ static NTSTATUS update_chunks(device_extension* Vcb, LIST_ENTRY*
batchlist, PIRP
}
if (c->list_entry_balance.Flink) {
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
le = le2;
continue;
}
if (c->space_changed || c->created) {
+ BOOL created = c->created;
+
used_minus_cache = c->used;
// subtract self-hosted cache
@@ -5781,23 +5791,28 @@ static NTSTATUS update_chunks(device_extension* Vcb, LIST_ENTRY*
batchlist, PIRP
Status = drop_chunk(Vcb, c, batchlist, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("drop_chunk returned %08x\n", Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
return Status;
}
+
+ // c is now freed, so avoid releasing non-existent lock
+ le = le2;
+ continue;
} else if (c->created) {
Status = create_chunk(Vcb, c, Irp);
if (!NT_SUCCESS(Status)) {
ERR("create_chunk returned %08x\n", Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
return Status;
}
}
- if (used_minus_cache > 0)
- ExReleaseResourceLite(&c->lock);
- }
+ if (used_minus_cache > 0 || created)
+ release_chunk_lock(c, Vcb);
+ } else
+ release_chunk_lock(c, Vcb);
}
le = le2;
diff --git a/drivers/filesystems/btrfs/free-space.c
b/drivers/filesystems/btrfs/free-space.c
index 1ed2da9361..f6248e9038 100644
--- a/drivers/filesystems/btrfs/free-space.c
+++ b/drivers/filesystems/btrfs/free-space.c
@@ -161,12 +161,12 @@ NTSTATUS clear_free_space_cache(device_extension* Vcb, LIST_ENTRY*
batchlist, PI
chunk* c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->cache_loaded) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
Status = load_cache_chunk(Vcb, c, NULL);
if (!NT_SUCCESS(Status)) {
ERR("load_cache_chunk(%llx) returned %08x\n", c->offset,
Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
ExReleaseResourceLite(&Vcb->chunk_lock);
return Status;
}
@@ -174,7 +174,7 @@ NTSTATUS clear_free_space_cache(device_extension* Vcb, LIST_ENTRY*
batchlist, PI
c->changed = TRUE;
c->space_changed = TRUE;
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
}
le = le->Flink;
@@ -975,14 +975,14 @@ static NTSTATUS insert_cache_extent(fcb* fcb, UINT64 start, UINT64
length, LIST_
c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == flags && (c->chunk_item->size
- c->used) >= length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL,
NULL, rollback, BTRFS_COMPRESSION_NONE, length, FALSE, 0))
return STATUS_SUCCESS;
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, fcb->Vcb);
}
le = le->Flink;
@@ -995,14 +995,14 @@ static NTSTATUS insert_cache_extent(fcb* fcb, UINT64 start, UINT64
length, LIST_
return Status;
}
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == flags && (c->chunk_item->size -
c->used) >= length) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, length, FALSE, NULL, NULL,
rollback, BTRFS_COMPRESSION_NONE, length, FALSE, 0))
return STATUS_SUCCESS;
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, fcb->Vcb);
return STATUS_DISK_FULL;
}
@@ -1360,9 +1360,9 @@ NTSTATUS allocate_cache(device_extension* Vcb, BOOL* changed, PIRP
Irp, LIST_ENT
if (c->space_changed) {
BOOL b;
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
Status = allocate_cache_chunk(Vcb, c, &b, &batchlist, Irp,
rollback);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
if (b)
*changed = TRUE;
@@ -1828,9 +1828,9 @@ NTSTATUS update_chunk_caches(device_extension* Vcb, PIRP Irp,
LIST_ENTRY* rollba
c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->space_changed) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
Status = update_chunk_cache(Vcb, c, &now, &batchlist, Irp,
rollback);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
if (!NT_SUCCESS(Status)) {
ERR("update_chunk_cache(%llx) returned %08x\n", c->offset,
Status);
@@ -1897,9 +1897,9 @@ NTSTATUS update_chunk_caches_tree(device_extension* Vcb, PIRP Irp)
{
c = CONTAINING_RECORD(le, chunk, list_entry);
if (c->space_changed) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
Status = update_chunk_cache_tree(Vcb, c, &batchlist);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
if (!NT_SUCCESS(Status)) {
ERR("update_chunk_cache_tree(%llx) returned %08x\n",
c->offset, Status);
diff --git a/drivers/filesystems/btrfs/fsctl.c b/drivers/filesystems/btrfs/fsctl.c
index 6cc0f45ab1..3b13e89766 100644
--- a/drivers/filesystems/btrfs/fsctl.c
+++ b/drivers/filesystems/btrfs/fsctl.c
@@ -1024,7 +1024,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT
FileObject, vo
// add INODE_REF
- irsize = (UINT16)(offsetof(INODE_REF, name[0]) + strlen(DOTDOT));
+ irsize = (UINT16)(offsetof(INODE_REF, name[0]) + sizeof(DOTDOT) - 1);
ir = ExAllocatePoolWithTag(PagedPool, irsize, ALLOC_TAG);
if (!ir) {
ERR("out of memory\n");
@@ -1033,7 +1033,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT
FileObject, vo
}
ir->index = 0;
- ir->n = (USHORT)strlen(DOTDOT);
+ ir->n = sizeof(DOTDOT) - 1;
RtlCopyMemory(ir->name, DOTDOT, ir->n);
Status = insert_tree_item(Vcb, r, r->root_item.objid, TYPE_INODE_REF,
r->root_item.objid, ir, irsize, NULL, Irp);
@@ -1164,9 +1164,10 @@ end2:
}
static NTSTATUS get_inode_info(PFILE_OBJECT FileObject, void* data, ULONG length) {
- btrfs_inode_info* bii = data;
+ btrfs_inode_info2* bii = data;
fcb* fcb;
ccb* ccb;
+ BOOL old_style;
if (length < sizeof(btrfs_inode_info))
return STATUS_BUFFER_OVERFLOW;
@@ -1192,6 +1193,8 @@ static NTSTATUS get_inode_info(PFILE_OBJECT FileObject, void* data,
ULONG length
if (fcb->ads)
fcb = ccb->fileref->parent->fcb;
+ old_style = length < sizeof(btrfs_inode_info2);
+
ExAcquireResourceSharedLite(fcb->Header.Resource, TRUE);
bii->subvol = fcb->subvol->id;
@@ -1210,52 +1213,84 @@ static NTSTATUS get_inode_info(PFILE_OBJECT FileObject, void*
data, ULONG length
bii->flags = fcb->inode_item.flags;
bii->inline_length = 0;
- bii->disk_size[0] = 0;
- bii->disk_size[1] = 0;
- bii->disk_size[2] = 0;
+ bii->disk_size_uncompressed = 0;
+ bii->disk_size_zlib = 0;
+ bii->disk_size_lzo = 0;
+
+ if (!old_style) {
+ bii->disk_size_zstd = 0;
+ bii->sparse_size = 0;
+ }
if (fcb->type != BTRFS_TYPE_DIRECTORY) {
+ UINT64 last_end = 0;
LIST_ENTRY* le;
+ BOOL extents_inline = FALSE;
le = fcb->extents.Flink;
while (le != &fcb->extents) {
extent* ext = CONTAINING_RECORD(le, extent, list_entry);
if (!ext->ignore) {
+ if (!old_style && ext->offset > last_end)
+ bii->sparse_size += ext->offset - last_end;
+
if (ext->extent_data.type == EXTENT_TYPE_INLINE) {
bii->inline_length += ext->datalen -
(UINT16)offsetof(EXTENT_DATA, data[0]);
+ last_end = ext->offset + ext->extent_data.decoded_size;
+ extents_inline = TRUE;
} else {
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
// FIXME - compressed extents with a hole in them are counted more
than once
if (ed2->size != 0) {
- if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE) {
- bii->disk_size[0] += ed2->num_bytes;
- } else if (ext->extent_data.compression ==
BTRFS_COMPRESSION_ZLIB) {
- bii->disk_size[1] += ed2->size;
- } else if (ext->extent_data.compression ==
BTRFS_COMPRESSION_LZO) {
- bii->disk_size[2] += ed2->size;
+ switch (ext->extent_data.compression) {
+ case BTRFS_COMPRESSION_NONE:
+ bii->disk_size_uncompressed += ed2->num_bytes;
+ break;
+
+ case BTRFS_COMPRESSION_ZLIB:
+ bii->disk_size_zlib += ed2->size;
+ break;
+
+ case BTRFS_COMPRESSION_LZO:
+ bii->disk_size_lzo += ed2->size;
+ break;
+
+ case BTRFS_COMPRESSION_ZSTD:
+ if (!old_style)
+ bii->disk_size_zstd += ed2->size;
+ break;
}
}
+
+ last_end = ext->offset + ed2->num_bytes;
}
}
le = le->Flink;
}
+
+ if (!extents_inline && !old_style &&
sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size) >
last_end)
+ bii->sparse_size += sector_align(fcb->inode_item.st_size,
fcb->Vcb->superblock.sector_size) - last_end;
}
switch (fcb->prop_compression) {
case PropCompression_Zlib:
bii->compression_type = BTRFS_COMPRESSION_ZLIB;
- break;
+ break;
case PropCompression_LZO:
bii->compression_type = BTRFS_COMPRESSION_LZO;
- break;
+ break;
+
+ case PropCompression_ZSTD:
+ bii->compression_type = BTRFS_COMPRESSION_ZSTD;
+ break;
default:
bii->compression_type = BTRFS_COMPRESSION_ANY;
- break;
+ break;
}
ExReleaseResourceLite(fcb->Header.Resource);
@@ -1295,7 +1330,7 @@ static NTSTATUS set_inode_info(PFILE_OBJECT FileObject, void* data,
ULONG length
return STATUS_ACCESS_DENIED;
}
- if (bsii->compression_type_changed && bsii->compression_type >
BTRFS_COMPRESSION_LZO)
+ if (bsii->compression_type_changed && bsii->compression_type >
BTRFS_COMPRESSION_ZSTD)
return STATUS_INVALID_PARAMETER;
if (fcb->ads)
@@ -1358,6 +1393,10 @@ static NTSTATUS set_inode_info(PFILE_OBJECT FileObject, void* data,
ULONG length
case BTRFS_COMPRESSION_LZO:
fcb->prop_compression = PropCompression_LZO;
break;
+
+ case BTRFS_COMPRESSION_ZSTD:
+ fcb->prop_compression = PropCompression_ZSTD;
+ break;
}
fcb->prop_compression_changed = TRUE;
@@ -2351,10 +2390,6 @@ static NTSTATUS invalidate_volumes(PIRP Irp) {
RtlZeroMemory(newvpb, sizeof(VPB));
- IoAcquireVpbSpinLock(&irql);
- devobj->Vpb->Flags &= ~VPB_MOUNTED;
- IoReleaseVpbSpinLock(irql);
-
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
Vcb->removing = TRUE;
@@ -2403,7 +2438,7 @@ static NTSTATUS invalidate_volumes(PIRP Irp) {
ExFreePool(newvpb);
if (Vcb->open_files == 0)
- uninit(Vcb, FALSE);
+ uninit(Vcb);
}
break;
@@ -2517,7 +2552,6 @@ static void update_volumes(device_extension* Vcb) {
static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) {
NTSTATUS Status;
- KIRQL irql;
TRACE("FSCTL_DISMOUNT_VOLUME\n");
@@ -2558,11 +2592,6 @@ static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) {
ExReleaseResourceLite(&Vcb->tree_lock);
- IoAcquireVpbSpinLock(&irql);
- Vcb->Vpb->Flags &= ~VPB_MOUNTED;
- Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED;
- IoReleaseVpbSpinLock(irql);
-
return STATUS_SUCCESS;
}
@@ -3631,10 +3660,6 @@ end:
return Status;
}
-// based on functions in sys/sysmacros.h
-#define major(rdev) ((((rdev) >> 8) & 0xFFF) | ((UINT32)((rdev) >> 32)
& ~0xFFF))
-#define minor(rdev) (((rdev) & 0xFF) | ((UINT32)((rdev) >> 12) & ~0xFF))
-
static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data, ULONG
datalen, PIRP Irp) {
NTSTATUS Status;
btrfs_mknod* bmn;
@@ -4161,7 +4186,7 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT
FileObject,
ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
- if (bsxa->namelen == strlen(EA_NTACL) && RtlCompareMemory(bsxa->data,
EA_NTACL, strlen(EA_NTACL)) == strlen(EA_NTACL)) {
+ if (bsxa->namelen == sizeof(EA_NTACL) - 1 &&
RtlCompareMemory(bsxa->data, EA_NTACL, sizeof(EA_NTACL) - 1) == sizeof(EA_NTACL) - 1)
{
if ((!(ccb->access & WRITE_DAC) || !(ccb->access & WRITE_OWNER))
&& Irp->RequestorMode == UserMode) {
WARN("insufficient privileges\n");
Status = STATUS_ACCESS_DENIED;
@@ -4199,7 +4224,7 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT
FileObject,
Status = STATUS_SUCCESS;
goto end;
- } else if (bsxa->namelen == strlen(EA_DOSATTRIB) &&
RtlCompareMemory(bsxa->data, EA_DOSATTRIB, strlen(EA_DOSATTRIB)) ==
strlen(EA_DOSATTRIB)) {
+ } else if (bsxa->namelen == sizeof(EA_DOSATTRIB) - 1 &&
RtlCompareMemory(bsxa->data, EA_DOSATTRIB, sizeof(EA_DOSATTRIB) - 1) ==
sizeof(EA_DOSATTRIB) - 1) {
ULONG atts;
if (bsxa->valuelen > 0 &&
get_file_attributes_from_xattr(bsxa->data + bsxa->namelen, bsxa->valuelen,
&atts)) {
@@ -4230,7 +4255,7 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT
FileObject,
Status = STATUS_SUCCESS;
goto end;
- } else if (bsxa->namelen == strlen(EA_REPARSE) &&
RtlCompareMemory(bsxa->data, EA_REPARSE, strlen(EA_REPARSE)) == strlen(EA_REPARSE)) {
+ } else if (bsxa->namelen == sizeof(EA_REPARSE) - 1 &&
RtlCompareMemory(bsxa->data, EA_REPARSE, sizeof(EA_REPARSE) - 1) == sizeof(EA_REPARSE)
- 1) {
if (fcb->reparse_xattr.Buffer) {
ExFreePool(fcb->reparse_xattr.Buffer);
fcb->reparse_xattr.Buffer = NULL;
@@ -4254,7 +4279,7 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT
FileObject,
Status = STATUS_SUCCESS;
goto end;
- } else if (bsxa->namelen == strlen(EA_EA) &&
RtlCompareMemory(bsxa->data, EA_EA, strlen(EA_EA)) == strlen(EA_EA)) {
+ } else if (bsxa->namelen == sizeof(EA_EA) - 1 &&
RtlCompareMemory(bsxa->data, EA_EA, sizeof(EA_EA) - 1) == sizeof(EA_EA) - 1) {
if (!(ccb->access & FILE_WRITE_EA) && Irp->RequestorMode ==
UserMode) {
WARN("insufficient privileges\n");
Status = STATUS_ACCESS_DENIED;
@@ -4310,13 +4335,16 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb,
PFILE_OBJECT FileObject,
Status = STATUS_SUCCESS;
goto end;
- } else if (bsxa->namelen == strlen(EA_PROP_COMPRESSION) &&
RtlCompareMemory(bsxa->data, EA_PROP_COMPRESSION, strlen(EA_PROP_COMPRESSION)) ==
strlen(EA_PROP_COMPRESSION)) {
- const char lzo[] = "lzo";
- const char zlib[] = "zlib";
-
- if (bsxa->valuelen == strlen(lzo) && RtlCompareMemory(bsxa->data +
bsxa->namelen, lzo, bsxa->valuelen) == bsxa->valuelen)
+ } else if (bsxa->namelen == sizeof(EA_PROP_COMPRESSION) - 1 &&
RtlCompareMemory(bsxa->data, EA_PROP_COMPRESSION, sizeof(EA_PROP_COMPRESSION) - 1) ==
sizeof(EA_PROP_COMPRESSION) - 1) {
+ static const char lzo[] = "lzo";
+ static const char zlib[] = "zlib";
+ static const char zstd[] = "zstd";
+
+ if (bsxa->valuelen == sizeof(zstd) - 1 &&
RtlCompareMemory(bsxa->data + bsxa->namelen, zstd, bsxa->valuelen) ==
bsxa->valuelen)
+ fcb->prop_compression = PropCompression_ZSTD;
+ else if (bsxa->valuelen == sizeof(lzo) - 1 &&
RtlCompareMemory(bsxa->data + bsxa->namelen, lzo, bsxa->valuelen) ==
bsxa->valuelen)
fcb->prop_compression = PropCompression_LZO;
- else if (bsxa->valuelen == strlen(zlib) &&
RtlCompareMemory(bsxa->data + bsxa->namelen, zlib, bsxa->valuelen) ==
bsxa->valuelen)
+ else if (bsxa->valuelen == sizeof(zlib) - 1 &&
RtlCompareMemory(bsxa->data + bsxa->namelen, zlib, bsxa->valuelen) ==
bsxa->valuelen)
fcb->prop_compression = PropCompression_Zlib;
else
fcb->prop_compression = PropCompression_None;
@@ -4331,7 +4359,7 @@ static NTSTATUS fsctl_set_xattr(device_extension* Vcb, PFILE_OBJECT
FileObject,
Status = STATUS_SUCCESS;
goto end;
- } else if (bsxa->namelen >= strlen(stream_pref) &&
RtlCompareMemory(bsxa->data, stream_pref, strlen(stream_pref)) == strlen(stream_pref))
{
+ } else if (bsxa->namelen >= (sizeof(stream_pref) - 1) &&
RtlCompareMemory(bsxa->data, stream_pref, sizeof(stream_pref) - 1) ==
sizeof(stream_pref) - 1) {
// don't allow xattrs beginning with user., as these appear as streams
instead
Status = STATUS_OBJECT_NAME_INVALID;
goto end;
diff --git a/drivers/filesystems/btrfs/pnp.c b/drivers/filesystems/btrfs/pnp.c
index 5a7e91b410..fbb535f070 100644
--- a/drivers/filesystems/btrfs/pnp.c
+++ b/drivers/filesystems/btrfs/pnp.c
@@ -247,12 +247,10 @@ static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) {
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, TRUE);
Vcb->removing = TRUE;
- Vcb->Vpb->Flags &= ~VPB_MOUNTED;
- Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED;
ExReleaseResourceLite(&Vcb->tree_lock);
if (Vcb->open_files == 0)
- uninit(Vcb, FALSE);
+ uninit(Vcb);
}
return STATUS_SUCCESS;
@@ -270,13 +268,11 @@ NTSTATUS pnp_surprise_removal(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
Vcb->vde->mounted_device = NULL;
Vcb->removing = TRUE;
- Vcb->Vpb->Flags &= ~VPB_MOUNTED;
- Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED;
ExReleaseResourceLite(&Vcb->tree_lock);
if (Vcb->open_files == 0)
- uninit(Vcb, FALSE);
+ uninit(Vcb);
}
return STATUS_SUCCESS;
@@ -349,7 +345,7 @@ end:
static NTSTATUS bus_query_hardware_ids(PIRP Irp) {
WCHAR* out;
- static WCHAR ids[] = L"ROOT\\btrfs\0";
+ static const WCHAR ids[] = L"ROOT\\btrfs\0";
out = ExAllocatePoolWithTag(PagedPool, sizeof(ids), ALLOC_TAG);
if (!out) {
@@ -402,11 +398,11 @@ static NTSTATUS pdo_query_device_id(pdo_device_extension* pdode,
PIRP Irp) {
WCHAR name[100], *noff, *out;
int i;
- static WCHAR pref[] = L"Btrfs\\";
+ static const WCHAR pref[] = L"Btrfs\\";
- RtlCopyMemory(name, pref, wcslen(pref) * sizeof(WCHAR));
+ RtlCopyMemory(name, pref, sizeof(pref) - sizeof(WCHAR));
- noff = &name[wcslen(pref)];
+ noff = &name[(sizeof(pref) / sizeof(WCHAR)) - 1];
for (i = 0; i < 16; i++) {
*noff = hex_digit(pdode->uuid.uuid[i] >> 4); noff++;
*noff = hex_digit(pdode->uuid.uuid[i] & 0xf); noff++;
@@ -434,7 +430,7 @@ static NTSTATUS pdo_query_device_id(pdo_device_extension* pdode, PIRP
Irp) {
static NTSTATUS pdo_query_hardware_ids(PIRP Irp) {
WCHAR* out;
- static WCHAR ids[] = L"BtrfsVolume\0";
+ static const WCHAR ids[] = L"BtrfsVolume\0";
out = ExAllocatePoolWithTag(PagedPool, sizeof(ids), ALLOC_TAG);
if (!out) {
diff --git a/drivers/filesystems/btrfs/read.c b/drivers/filesystems/btrfs/read.c
index 4384d65784..2eb19b1a80 100644
--- a/drivers/filesystems/btrfs/read.c
+++ b/drivers/filesystems/btrfs/read.c
@@ -1645,6 +1645,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
if (!context.stripes[i].mdl) {
ERR("IoAllocateMdl failed\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -1654,6 +1656,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(UINT32) *
ci->num_stripes, ALLOC_TAG);
if (!stripeoff) {
ERR("out of memory\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -1760,6 +1764,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
stripes = ExAllocatePoolWithTag(NonPagedPool, sizeof(read_data_stripe*) *
ci->num_stripes / ci->sub_stripes, ALLOC_TAG);
if (!stripes) {
ERR("out of memory\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -1795,6 +1801,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
if (!context.stripes[i+j].mdl) {
ERR("IoAllocateMdl failed\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -1818,6 +1826,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
if (!context.stripes[i+j].mdl) {
ERR("IoAllocateMdl failed\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -1839,6 +1849,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(UINT32) *
ci->num_stripes / ci->sub_stripes, ALLOC_TAG);
if (!stripeoff) {
ERR("out of memory\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -2075,6 +2087,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
if (!context.stripes[i].mdl) {
ERR("IoAllocateMdl failed\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -2085,6 +2099,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
dummypage = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, ALLOC_TAG);
if (!dummypage) {
ERR("out of memory\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -2092,6 +2108,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
dummy_mdl = IoAllocateMdl(dummypage, PAGE_SIZE, FALSE, FALSE, NULL);
if (!dummy_mdl) {
ERR("IoAllocateMdl failed\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -2104,6 +2122,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(UINT32) *
ci->num_stripes, ALLOC_TAG);
if (!stripeoff) {
ERR("out of memory\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -2328,6 +2348,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
if (!context.stripes[i].mdl) {
ERR("IoAllocateMdl failed\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -2338,6 +2360,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
dummypage = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, ALLOC_TAG);
if (!dummypage) {
ERR("out of memory\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -2345,6 +2369,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
dummy_mdl = IoAllocateMdl(dummypage, PAGE_SIZE, FALSE, FALSE, NULL);
if (!dummy_mdl) {
ERR("IoAllocateMdl failed\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -2357,6 +2383,8 @@ NTSTATUS read_data(_In_ device_extension* Vcb, _In_ UINT64 addr,
_In_ UINT32 len
stripeoff = ExAllocatePoolWithTag(NonPagedPool, sizeof(UINT32) *
ci->num_stripes, ALLOC_TAG);
if (!stripeoff) {
ERR("out of memory\n");
+ MmUnlockPages(master_mdl);
+ IoFreeMdl(master_mdl);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto exit;
}
@@ -2785,7 +2813,7 @@ NTSTATUS read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64
length, ULONG* pb
read = (UINT32)min(min(len, ext->datalen) - off, length);
RtlCopyMemory(data + bytes_read, &ed->data[off], read);
- } else if (ed->compression == BTRFS_COMPRESSION_ZLIB ||
ed->compression == BTRFS_COMPRESSION_LZO) {
+ } else if (ed->compression == BTRFS_COMPRESSION_ZLIB ||
ed->compression == BTRFS_COMPRESSION_LZO || ed->compression ==
BTRFS_COMPRESSION_ZSTD) {
UINT8* decomp;
BOOL decomp_alloc;
UINT16 inlen = ext->datalen - (UINT16)offsetof(EXTENT_DATA,
data[0]);
@@ -2834,6 +2862,13 @@ NTSTATUS read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64
length, ULONG* pb
if (decomp_alloc) ExFreePool(decomp);
goto exit;
}
+ } else if (ed->compression == BTRFS_COMPRESSION_ZSTD) {
+ Status = zstd_decompress(ed->data, inlen, decomp,
(UINT32)(read + off));
+ if (!NT_SUCCESS(Status)) {
+ ERR("zstd_decompress returned %08x\n",
Status);
+ if (decomp_alloc) ExFreePool(decomp);
+ goto exit;
+ }
}
if (decomp_alloc) {
@@ -3000,6 +3035,18 @@ NTSTATUS read_file(fcb* fcb, UINT8* data, UINT64 start, UINT64
length, ULONG* pb
ERR("lzo_decompress returned %08x\n", Status);
ExFreePool(buf);
+ if (decomp)
+ ExFreePool(decomp);
+
+ goto exit;
+ }
+ } else if (ed->compression == BTRFS_COMPRESSION_ZSTD) {
+ Status = zstd_decompress(buf2, inlen, decomp ? decomp : (data
+ bytes_read), outlen);
+
+ if (!NT_SUCCESS(Status)) {
+ ERR("zstd_decompress returned %08x\n",
Status);
+ ExFreePool(buf);
+
if (decomp)
ExFreePool(decomp);
diff --git a/drivers/filesystems/btrfs/registry.c b/drivers/filesystems/btrfs/registry.c
index 05f66f5df2..84196df002 100644
--- a/drivers/filesystems/btrfs/registry.c
+++ b/drivers/filesystems/btrfs/registry.c
@@ -16,6 +16,7 @@
* along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
#include "btrfs_drv.h"
+#include "zstd/zstd.h"
extern UNICODE_STRING log_device, log_file, registry_path;
extern LIST_ENTRY uid_map_list, gid_map_list;
@@ -30,13 +31,13 @@ extern PDEVICE_OBJECT comdo;
WORK_QUEUE_ITEM wqi;
-static WCHAR option_mounted[] = L"Mounted";
+static const WCHAR option_mounted[] = L"Mounted";
NTSTATUS registry_load_volume_options(device_extension* Vcb) {
BTRFS_UUID* uuid = &Vcb->superblock.uuid;
mount_options* options = &Vcb->options;
UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus,
readonlyus, zliblevelus, flushintervalus,
- maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus,
clearcacheus, allowdegradedus;
+ maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus,
clearcacheus, allowdegradedus, zstdlevelus;
OBJECT_ATTRIBUTES oa;
NTSTATUS Status;
ULONG i, j, kvfilen, index, retlen;
@@ -45,9 +46,10 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
options->compress = mount_compress;
options->compress_force = mount_compress_force;
- options->compress_type = mount_compress_type > BTRFS_COMPRESSION_LZO ? 0 :
mount_compress_type;
+ options->compress_type = mount_compress_type > BTRFS_COMPRESSION_ZSTD ? 0 :
mount_compress_type;
options->readonly = mount_readonly;
options->zlib_level = mount_zlib_level;
+ options->zstd_level = mount_zstd_level;
options->flush_interval = mount_flush_interval;
options->max_inline = min(mount_max_inline, Vcb->superblock.node_size -
sizeof(tree_header) - sizeof(leaf_node) - sizeof(EXTENT_DATA) + 1);
options->skip_balance = mount_skip_balance;
@@ -118,6 +120,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
RtlInitUnicodeString(¬rimus, L"NoTrim");
RtlInitUnicodeString(&clearcacheus, L"ClearCache");
RtlInitUnicodeString(&allowdegradedus, L"AllowDegraded");
+ RtlInitUnicodeString(&zstdlevelus, L"ZstdLevel");
do {
Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen,
&retlen);
@@ -145,7 +148,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
} else if (FsRtlAreNamesEqual(&compresstypeus, &us, TRUE, NULL)
&& kvfi->DataOffset > 0 && kvfi->DataLength > 0 &&
kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
- options->compress_type = (UINT8)(*val > BTRFS_COMPRESSION_LZO ? 0 :
*val);
+ options->compress_type = (UINT8)(*val > BTRFS_COMPRESSION_ZSTD ? 0
: *val);
} else if (FsRtlAreNamesEqual(&readonlyus, &us, TRUE, NULL)
&& kvfi->DataOffset > 0 && kvfi->DataLength > 0 &&
kvfi->Type == REG_DWORD) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
@@ -186,6 +189,10 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
options->allow_degraded = *val;
+ } else if (FsRtlAreNamesEqual(&zstdlevelus, &us, TRUE, NULL)
&& kvfi->DataOffset > 0 && kvfi->DataLength > 0 &&
kvfi->Type == REG_DWORD) {
+ DWORD* val = (DWORD*)((UINT8*)kvfi + kvfi->DataOffset);
+
+ options->zstd_level = *val;
}
} else if (Status != STATUS_NO_MORE_ENTRIES) {
ERR("ZwEnumerateValueKey returned %08x\n", Status);
@@ -199,6 +206,9 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
if (options->zlib_level > 9)
options->zlib_level = 9;
+ if (options->zstd_level > (UINT32)ZSTD_maxCLevel())
+ options->zstd_level = ZSTD_maxCLevel();
+
if (options->flush_interval == 0)
options->flush_interval = mount_flush_interval;
@@ -258,8 +268,8 @@ NTSTATUS registry_mark_volume_mounted(BTRFS_UUID* uuid) {
goto end;
}
- mountedus.Buffer = option_mounted;
- mountedus.Length = mountedus.MaximumLength = (USHORT)wcslen(option_mounted) *
sizeof(WCHAR);
+ mountedus.Buffer = (WCHAR*)option_mounted;
+ mountedus.Length = mountedus.MaximumLength = sizeof(option_mounted) - sizeof(WCHAR);
data = 1;
@@ -308,8 +318,8 @@ static NTSTATUS registry_mark_volume_unmounted_path(PUNICODE_STRING
path) {
index = 0;
- mountedus.Buffer = option_mounted;
- mountedus.Length = mountedus.MaximumLength = (USHORT)wcslen(option_mounted) *
sizeof(WCHAR);
+ mountedus.Buffer = (WCHAR*)option_mounted;
+ mountedus.Length = mountedus.MaximumLength = sizeof(option_mounted) - sizeof(WCHAR);
do {
Status = ZwEnumerateValueKey(h, index, KeyValueBasicInformation, kvbi, kvbilen,
&retlen);
@@ -526,7 +536,7 @@ static void read_mappings(PUNICODE_STRING regpath) {
ULONG dispos;
NTSTATUS Status;
- const WCHAR mappings[] = L"\\Mappings";
+ static const WCHAR mappings[] = L"\\Mappings";
while (!IsListEmpty(&uid_map_list)) {
uid_map* um = CONTAINING_RECORD(RemoveHeadList(&uid_map_list), uid_map,
listentry);
@@ -535,17 +545,17 @@ static void read_mappings(PUNICODE_STRING regpath) {
ExFreePool(um);
}
- path = ExAllocatePoolWithTag(PagedPool, regpath->Length + (wcslen(mappings) *
sizeof(WCHAR)), ALLOC_TAG);
+ path = ExAllocatePoolWithTag(PagedPool, regpath->Length + sizeof(mappings) -
sizeof(WCHAR), ALLOC_TAG);
if (!path) {
ERR("out of memory\n");
return;
}
RtlCopyMemory(path, regpath->Buffer, regpath->Length);
- RtlCopyMemory((UINT8*)path + regpath->Length, mappings, wcslen(mappings) *
sizeof(WCHAR));
+ RtlCopyMemory((UINT8*)path + regpath->Length, mappings, sizeof(mappings) -
sizeof(WCHAR));
us.Buffer = path;
- us.Length = us.MaximumLength = regpath->Length + ((USHORT)wcslen(mappings) *
sizeof(WCHAR));
+ us.Length = us.MaximumLength = regpath->Length + sizeof(mappings) -
sizeof(WCHAR);
InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE |
OBJ_KERNEL_HANDLE, NULL, NULL);
@@ -604,7 +614,7 @@ static void read_group_mappings(PUNICODE_STRING regpath) {
ULONG dispos;
NTSTATUS Status;
- const WCHAR mappings[] = L"\\GroupMappings";
+ static const WCHAR mappings[] = L"\\GroupMappings";
while (!IsListEmpty(&gid_map_list)) {
gid_map* gm = CONTAINING_RECORD(RemoveHeadList(&gid_map_list), gid_map,
listentry);
@@ -613,17 +623,17 @@ static void read_group_mappings(PUNICODE_STRING regpath) {
ExFreePool(gm);
}
- path = ExAllocatePoolWithTag(PagedPool, regpath->Length + (wcslen(mappings) *
sizeof(WCHAR)), ALLOC_TAG);
+ path = ExAllocatePoolWithTag(PagedPool, regpath->Length + sizeof(mappings) -
sizeof(WCHAR), ALLOC_TAG);
if (!path) {
ERR("out of memory\n");
return;
}
RtlCopyMemory(path, regpath->Buffer, regpath->Length);
- RtlCopyMemory((UINT8*)path + regpath->Length, mappings, wcslen(mappings) *
sizeof(WCHAR));
+ RtlCopyMemory((UINT8*)path + regpath->Length, mappings, sizeof(mappings) -
sizeof(WCHAR));
us.Buffer = path;
- us.Length = us.MaximumLength = regpath->Length + ((USHORT)wcslen(mappings) *
sizeof(WCHAR));
+ us.Length = us.MaximumLength = regpath->Length + sizeof(mappings) -
sizeof(WCHAR);
InitializeObjectAttributes(&oa, &us, OBJ_CASE_INSENSITIVE |
OBJ_KERNEL_HANDLE, NULL, NULL);
@@ -676,7 +686,7 @@ static void read_group_mappings(PUNICODE_STRING regpath) {
// If we're creating the key for the first time, we add a default mapping of
// BUILTIN\Users to gid 100, which ought to correspond to the "users"
group on Linux.
- us2.Length = us2.MaximumLength = (USHORT)wcslen(builtin_users) * sizeof(WCHAR);
+ us2.Length = us2.MaximumLength = sizeof(builtin_users) - sizeof(WCHAR);
us2.Buffer = ExAllocatePoolWithTag(PagedPool, us2.MaximumLength, ALLOC_TAG);
if (us2.Buffer) {
@@ -760,7 +770,7 @@ void read_registry(PUNICODE_STRING regpath, BOOL refresh) {
ULONG kvfilen, old_debug_log_level = debug_log_level;
UNICODE_STRING us, old_log_file, old_log_device;
- static WCHAR def_log_file[] = L"\\??\\C:\\btrfs.log";
+ static const WCHAR def_log_file[] = L"\\??\\C:\\btrfs.log";
#endif
ExAcquireResourceExclusiveLite(&mapping_lock, TRUE);
@@ -794,6 +804,7 @@ void read_registry(PUNICODE_STRING regpath, BOOL refresh) {
get_registry_value(h, L"ClearCache", REG_DWORD, &mount_clear_cache,
sizeof(mount_clear_cache));
get_registry_value(h, L"AllowDegraded", REG_DWORD,
&mount_allow_degraded, sizeof(mount_allow_degraded));
get_registry_value(h, L"Readonly", REG_DWORD, &mount_readonly,
sizeof(mount_readonly));
+ get_registry_value(h, L"ZstdLevel", REG_DWORD, &mount_zstd_level,
sizeof(mount_zstd_level));
if (!refresh)
get_registry_value(h, L"NoPNP", REG_DWORD, &no_pnp,
sizeof(no_pnp));
@@ -935,7 +946,7 @@ void read_registry(PUNICODE_STRING regpath, BOOL refresh) {
ExFreePool(kvfi);
} else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
- Status = ZwSetValueKey(h, &us, 0, REG_SZ, def_log_file,
(ULONG)(wcslen(def_log_file) + 1) * sizeof(WCHAR));
+ Status = ZwSetValueKey(h, &us, 0, REG_SZ, (void*)def_log_file,
sizeof(def_log_file));
if (!NT_SUCCESS(Status))
ERR("ZwSetValueKey returned %08x\n", Status);
@@ -947,7 +958,7 @@ void read_registry(PUNICODE_STRING regpath, BOOL refresh) {
}
if (log_file.Length == 0) {
- log_file.Length = log_file.MaximumLength = (UINT16)wcslen(def_log_file) *
sizeof(WCHAR);
+ log_file.Length = log_file.MaximumLength = sizeof(def_log_file) - sizeof(WCHAR);
log_file.Buffer = ExAllocatePoolWithTag(PagedPool, log_file.MaximumLength,
ALLOC_TAG);
if (!log_file.Buffer) {
diff --git a/drivers/filesystems/btrfs/reparse.c b/drivers/filesystems/btrfs/reparse.c
index 8e8d319b58..957ad07305 100644
--- a/drivers/filesystems/btrfs/reparse.c
+++ b/drivers/filesystems/btrfs/reparse.c
@@ -169,7 +169,7 @@ end:
return Status;
}
-static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, ccb* ccb, REPARSE_DATA_BUFFER*
rdb, ULONG buflen, BOOL write, LIST_ENTRY* rollback) {
+static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, fcb* fcb, ccb* ccb,
REPARSE_DATA_BUFFER* rdb, ULONG buflen, BOOL write, LIST_ENTRY* rollback) {
NTSTATUS Status;
ULONG minlen;
ULONG tlength;
@@ -197,15 +197,15 @@ static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, ccb* ccb,
REPARSE_DATA_
TRACE("substitute name = %.*S\n", subname.Length / sizeof(WCHAR),
subname.Buffer);
}
- fileref->fcb->type = BTRFS_TYPE_SYMLINK;
- fileref->fcb->inode_item.st_mode |= __S_IFLNK;
- fileref->fcb->inode_item.generation =
fileref->fcb->Vcb->superblock.generation; // so we don't confuse btrfs send
on Linux
+ fcb->type = BTRFS_TYPE_SYMLINK;
+ fcb->inode_item.st_mode |= __S_IFLNK;
+ fcb->inode_item.generation = fcb->Vcb->superblock.generation; // so we
don't confuse btrfs send on Linux
- if (fileref->dc)
- fileref->dc->type = fileref->fcb->type;
+ if (fileref && fileref->dc)
+ fileref->dc->type = fcb->type;
if (write) {
- Status = truncate_file(fileref->fcb, 0, Irp, rollback);
+ Status = truncate_file(fcb, 0, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("truncate_file returned %08x\n", Status);
return Status;
@@ -238,7 +238,7 @@ static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, ccb* ccb,
REPARSE_DATA_
offset.QuadPart = 0;
tlength = target.Length;
- Status = write_file2(fileref->fcb->Vcb, Irp, offset, target.Buffer,
&tlength, FALSE, TRUE,
+ Status = write_file2(fcb->Vcb, Irp, offset, target.Buffer, &tlength,
FALSE, TRUE,
TRUE, FALSE, FALSE, rollback);
ExFreePool(target.Buffer);
} else
@@ -247,86 +247,34 @@ static NTSTATUS set_symlink(PIRP Irp, file_ref* fileref, ccb* ccb,
REPARSE_DATA_
KeQuerySystemTime(&time);
win_time_to_unix(time, &now);
- fileref->fcb->inode_item.transid =
fileref->fcb->Vcb->superblock.generation;
- fileref->fcb->inode_item.sequence++;
+ fcb->inode_item.transid = fcb->Vcb->superblock.generation;
+ fcb->inode_item.sequence++;
- if (!ccb->user_set_change_time)
- fileref->fcb->inode_item.st_ctime = now;
+ if (!ccb || !ccb->user_set_change_time)
+ fcb->inode_item.st_ctime = now;
- if (!ccb->user_set_write_time)
- fileref->fcb->inode_item.st_mtime = now;
+ if (!ccb || !ccb->user_set_write_time)
+ fcb->inode_item.st_mtime = now;
- fileref->fcb->subvol->root_item.ctransid =
fileref->fcb->Vcb->superblock.generation;
- fileref->fcb->subvol->root_item.ctime = now;
+ fcb->subvol->root_item.ctransid = fcb->Vcb->superblock.generation;
+ fcb->subvol->root_item.ctime = now;
- fileref->fcb->inode_item_changed = TRUE;
- mark_fcb_dirty(fileref->fcb);
+ fcb->inode_item_changed = TRUE;
+ mark_fcb_dirty(fcb);
- mark_fileref_dirty(fileref);
+ if (fileref)
+ mark_fileref_dirty(fileref);
return Status;
}
-NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
- PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
- PFILE_OBJECT FileObject = IrpSp->FileObject;
- void* buffer = Irp->AssociatedIrp.SystemBuffer;
- REPARSE_DATA_BUFFER* rdb = buffer;
- DWORD buflen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
- NTSTATUS Status = STATUS_SUCCESS;
- fcb* fcb;
- ccb* ccb;
- file_ref* fileref;
+NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, ccb* ccb,
file_ref* fileref, PIRP Irp, LIST_ENTRY* rollback) {
+ NTSTATUS Status;
ULONG tag;
- LIST_ENTRY rollback;
-
- TRACE("(%p, %p)\n", DeviceObject, Irp);
-
- InitializeListHead(&rollback);
-
- if (!FileObject) {
- ERR("FileObject was NULL\n");
- return STATUS_INVALID_PARAMETER;
- }
-
- // IFSTest insists on this, for some reason...
- if (Irp->UserBuffer)
- return STATUS_INVALID_PARAMETER;
-
- fcb = FileObject->FsContext;
- ccb = FileObject->FsContext2;
-
- if (!ccb) {
- ERR("ccb was NULL\n");
- return STATUS_INVALID_PARAMETER;
- }
-
- if (Irp->RequestorMode == UserMode && !(ccb->access &
(FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA))) {
- WARN("insufficient privileges\n");
- return STATUS_ACCESS_DENIED;
- }
-
- fileref = ccb->fileref;
-
- if (!fileref) {
- ERR("fileref was NULL\n");
- return STATUS_INVALID_PARAMETER;
- }
-
- if (fcb->ads) {
- fileref = fileref->parent;
- fcb = fileref->fcb;
- }
-
- TRACE("%S\n", file_desc(FileObject));
-
- ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
- ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
if (fcb->type == BTRFS_TYPE_SYMLINK) {
WARN("tried to set a reparse point on an existing symlink\n");
- Status = STATUS_INVALID_PARAMETER;
- goto end;
+ return STATUS_INVALID_PARAMETER;
}
// FIXME - fail if we already have the attribute FILE_ATTRIBUTE_REPARSE_POINT
@@ -335,34 +283,32 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
if (buflen < sizeof(ULONG)) {
WARN("buffer was not long enough to hold tag\n");
- Status = STATUS_INVALID_BUFFER_SIZE;
- goto end;
+ return STATUS_INVALID_BUFFER_SIZE;
}
Status = FsRtlValidateReparsePointBuffer(buflen, rdb);
if (!NT_SUCCESS(Status)) {
ERR("FsRtlValidateReparsePointBuffer returned %08x\n", Status);
- goto end;
+ return Status;
}
- RtlCopyMemory(&tag, buffer, sizeof(ULONG));
+ RtlCopyMemory(&tag, rdb, sizeof(ULONG));
if (fcb->type == BTRFS_TYPE_FILE &&
((tag == IO_REPARSE_TAG_SYMLINK &&
rdb->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) || tag ==
IO_REPARSE_TAG_LXSS_SYMLINK)) {
- Status = set_symlink(Irp, fileref, ccb, rdb, buflen, tag ==
IO_REPARSE_TAG_SYMLINK, &rollback);
+ Status = set_symlink(Irp, fileref, fcb, ccb, rdb, buflen, tag ==
IO_REPARSE_TAG_SYMLINK, rollback);
fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT;
} else {
LARGE_INTEGER offset, time;
BTRFS_TIME now;
- if (fcb->type == BTRFS_TYPE_DIRECTORY) { // for directories, store as xattr
+ if (fcb->type == BTRFS_TYPE_DIRECTORY || fcb->type == BTRFS_TYPE_CHARDEV ||
fcb->type == BTRFS_TYPE_BLOCKDEV) { // store as xattr
ANSI_STRING buf;
buf.Buffer = ExAllocatePoolWithTag(PagedPool, buflen, ALLOC_TAG);
if (!buf.Buffer) {
ERR("out of memory\n");
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto end;
+ return STATUS_INSUFFICIENT_RESOURCES;
}
buf.Length = buf.MaximumLength = (UINT16)buflen;
@@ -370,24 +316,24 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
ExFreePool(fcb->reparse_xattr.Buffer);
fcb->reparse_xattr = buf;
- RtlCopyMemory(buf.Buffer, buffer, buflen);
+ RtlCopyMemory(buf.Buffer, rdb, buflen);
fcb->reparse_xattr_changed = TRUE;
Status = STATUS_SUCCESS;
} else { // otherwise, store as file data
- Status = truncate_file(fcb, 0, Irp, &rollback);
+ Status = truncate_file(fcb, 0, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("truncate_file returned %08x\n", Status);
- goto end;
+ return Status;
}
offset.QuadPart = 0;
- Status = write_file2(fcb->Vcb, Irp, offset, buffer, &buflen, FALSE,
TRUE, TRUE, FALSE, FALSE, &rollback);
+ Status = write_file2(fcb->Vcb, Irp, offset, rdb, &buflen, FALSE, TRUE,
TRUE, FALSE, FALSE, rollback);
if (!NT_SUCCESS(Status)) {
ERR("write_file2 returned %08x\n", Status);
- goto end;
+ return Status;
}
}
@@ -397,10 +343,10 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
fcb->inode_item.transid = fcb->Vcb->superblock.generation;
fcb->inode_item.sequence++;
- if (!ccb->user_set_change_time)
+ if (!ccb || !ccb->user_set_change_time)
fcb->inode_item.st_ctime = now;
- if (!ccb->user_set_write_time)
+ if (!ccb || !ccb->user_set_write_time)
fcb->inode_item.st_mtime = now;
fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT;
@@ -413,6 +359,70 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
mark_fcb_dirty(fcb);
}
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ void* buffer = Irp->AssociatedIrp.SystemBuffer;
+ REPARSE_DATA_BUFFER* rdb = buffer;
+ DWORD buflen = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+ NTSTATUS Status = STATUS_SUCCESS;
+ fcb* fcb;
+ ccb* ccb;
+ file_ref* fileref;
+ LIST_ENTRY rollback;
+
+ TRACE("(%p, %p)\n", DeviceObject, Irp);
+
+ InitializeListHead(&rollback);
+
+ if (!FileObject) {
+ ERR("FileObject was NULL\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // IFSTest insists on this, for some reason...
+ if (Irp->UserBuffer)
+ return STATUS_INVALID_PARAMETER;
+
+ fcb = FileObject->FsContext;
+ ccb = FileObject->FsContext2;
+
+ if (!ccb) {
+ ERR("ccb was NULL\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (Irp->RequestorMode == UserMode && !(ccb->access &
(FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA))) {
+ WARN("insufficient privileges\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ fileref = ccb->fileref;
+
+ if (!fileref) {
+ ERR("fileref was NULL\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (fcb->ads) {
+ fileref = fileref->parent;
+ fcb = fileref->fcb;
+ }
+
+ TRACE("%S\n", file_desc(FileObject));
+
+ ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, TRUE);
+ ExAcquireResourceExclusiveLite(fcb->Header.Resource, TRUE);
+
+ Status = set_reparse_point2(fcb, rdb, buflen, ccb, fileref, Irp, &rollback);
+ if (!NT_SUCCESS(Status)) {
+ ERR("set_reparse_point2 returned %08x\n", Status);
+ goto end;
+ }
+
send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL);
end:
diff --git a/drivers/filesystems/btrfs/scrub.c b/drivers/filesystems/btrfs/scrub.c
index 9dd7c2008d..f2d3d5e9ed 100644
--- a/drivers/filesystems/btrfs/scrub.c
+++ b/drivers/filesystems/btrfs/scrub.c
@@ -3190,7 +3190,7 @@ static void scrub_thread(void* context) {
while (le != &Vcb->chunks) {
chunk* c = CONTAINING_RECORD(le, chunk, list_entry);
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if (!c->readonly) {
InsertTailList(&chunks, &c->list_entry_balance);
@@ -3198,7 +3198,7 @@ static void scrub_thread(void* context) {
Vcb->scrub.chunks_left++;
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
le = le->Flink;
}
diff --git a/drivers/filesystems/btrfs/search.c b/drivers/filesystems/btrfs/search.c
index bec1aba420..7333a1e1df 100644
--- a/drivers/filesystems/btrfs/search.c
+++ b/drivers/filesystems/btrfs/search.c
@@ -496,7 +496,7 @@ void remove_volume_child(_Inout_
_Requires_exclusive_lock_held_(_Curr_->child_lo
pdo = vde->pdo;
IoDeleteDevice(vde->device);
- if (no_pnp)
+ if (!no_pnp)
IoDeleteDevice(pdo);
}
} else
@@ -540,7 +540,7 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING
devpath) {
TRACE("DeviceType = %u, DeviceNumber = %u, PartitionNumber = %u\n",
sdn.DeviceType, sdn.DeviceNumber, sdn.PartitionNumber);
// If we've just added a partition to a whole-disk filesystem, unmount it
- if (sdn.DeviceNumber != 0xffffffff) {
+ if (sdn.DeviceNumber != 0xffffffff && sdn.PartitionNumber != 0) {
LIST_ENTRY* le;
ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE);
@@ -823,7 +823,7 @@ static void mountmgr_process_drive(PDEVICE_OBJECT mountmgr,
PUNICODE_STRING devi
static void mountmgr_updated(PDEVICE_OBJECT mountmgr, MOUNTMGR_MOUNT_POINTS* mmps) {
ULONG i;
- static WCHAR pref[] = L"\\DosDevices\\";
+ static const WCHAR pref[] = L"\\DosDevices\\";
for (i = 0; i < mmps->NumberOfMountPoints; i++) {
UNICODE_STRING symlink, device_name;
@@ -844,8 +844,8 @@ static void mountmgr_updated(PDEVICE_OBJECT mountmgr,
MOUNTMGR_MOUNT_POINTS* mmp
device_name.Length = device_name.MaximumLength = 0;
}
- if (symlink.Length > wcslen(pref) * sizeof(WCHAR) &&
- RtlCompareMemory(symlink.Buffer, pref, wcslen(pref) * sizeof(WCHAR)) ==
wcslen(pref) * sizeof(WCHAR))
+ if (symlink.Length > sizeof(pref) - sizeof(WCHAR) &&
+ RtlCompareMemory(symlink.Buffer, pref, sizeof(pref) - sizeof(WCHAR)) ==
sizeof(pref) - sizeof(WCHAR))
mountmgr_process_drive(mountmgr, &device_name);
}
}
diff --git a/drivers/filesystems/btrfs/send.c b/drivers/filesystems/btrfs/send.c
index a865c62c3e..260612a155 100644
--- a/drivers/filesystems/btrfs/send.c
+++ b/drivers/filesystems/btrfs/send.c
@@ -1648,7 +1648,7 @@ static NTSTATUS wait_for_flush(send_context* context, traverse_ptr*
tp1, travers
return STATUS_SUCCESS;
}
-static NTSTATUS add_ext_holes(LIST_ENTRY* exts, UINT64 size) {
+static NTSTATUS add_ext_holes(device_extension* Vcb, LIST_ENTRY* exts, UINT64 size) {
UINT64 lastoff = 0;
LIST_ENTRY* le;
@@ -1699,7 +1699,7 @@ static NTSTATUS add_ext_holes(LIST_ENTRY* exts, UINT64 size) {
ext2->offset = lastoff;
ext2->datalen = offsetof(EXTENT_DATA, data) + sizeof(EXTENT_DATA2);
- ext2->data.decoded_size = ed2->num_bytes = size - lastoff;
+ ext2->data.decoded_size = ed2->num_bytes = sector_align(size - lastoff,
Vcb->superblock.sector_size);
ext2->data.type = EXTENT_TYPE_REGULAR;
ed2->address = ed2->size = ed2->offset = 0;
@@ -2130,13 +2130,13 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr*
tp1, traverse
return STATUS_SUCCESS;
if (context->parent) {
- Status = add_ext_holes(&context->lastinode.exts,
context->lastinode.size);
+ Status = add_ext_holes(context->Vcb, &context->lastinode.exts,
context->lastinode.size);
if (!NT_SUCCESS(Status)) {
ERR("add_ext_holes returned %08x\n", Status);
return Status;
}
- Status = add_ext_holes(&context->lastinode.oldexts,
context->lastinode.size);
+ Status = add_ext_holes(context->Vcb, &context->lastinode.oldexts,
context->lastinode.size);
if (!NT_SUCCESS(Status)) {
ERR("add_ext_holes returned %08x\n", Status);
return Status;
@@ -2187,7 +2187,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr*
tp1, traverse
if (se->data.compression == BTRFS_COMPRESSION_NONE)
send_add_tlv(context, BTRFS_SEND_TLV_DATA, se->data.data,
(UINT16)se->data.decoded_size);
- else if (se->data.compression == BTRFS_COMPRESSION_ZLIB ||
se->data.compression == BTRFS_COMPRESSION_LZO) {
+ else if (se->data.compression == BTRFS_COMPRESSION_ZLIB ||
se->data.compression == BTRFS_COMPRESSION_LZO || se->data.compression ==
BTRFS_COMPRESSION_ZSTD) {
ULONG inlen = se->datalen - (ULONG)offsetof(EXTENT_DATA, data[0]);
send_add_tlv(context, BTRFS_SEND_TLV_DATA, NULL,
(UINT16)se->data.decoded_size);
@@ -2217,6 +2217,14 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr*
tp1, traverse
if (se2) ExFreePool(se2);
return Status;
}
+ } else if (se->data.compression == BTRFS_COMPRESSION_ZSTD) {
+ Status = zstd_decompress(se->data.data, inlen,
&context->data[context->datalen - se->data.decoded_size],
(UINT32)se->data.decoded_size);
+ if (!NT_SUCCESS(Status)) {
+ ERR("zlib_decompress returned %08x\n", Status);
+ ExFreePool(se);
+ if (se2) ExFreePool(se2);
+ return Status;
+ }
}
} else {
ERR("unhandled compression type %x\n",
se->data.compression);
@@ -2367,7 +2375,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr*
tp1, traverse
offset = se->offset + off;
send_add_tlv(context, BTRFS_SEND_TLV_OFFSET, &offset,
sizeof(UINT64));
- length = min((UINT16)(context->lastinode.size - se->offset - off),
length);
+ length = (UINT16)min(context->lastinode.size - se->offset - off,
length);
send_add_tlv(context, BTRFS_SEND_TLV_DATA, buf + skip_start, length);
send_command_finish(context, pos);
@@ -2459,6 +2467,16 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr*
tp1, traverse
if (se2) ExFreePool(se2);
return Status;
}
+ } else if (se->data.compression == BTRFS_COMPRESSION_ZSTD) {
+ Status = zstd_decompress(compbuf, (UINT32)ed2->size, buf,
(UINT32)se->data.decoded_size);
+ if (!NT_SUCCESS(Status)) {
+ ERR("zstd_decompress returned %08x\n", Status);
+ ExFreePool(compbuf);
+ ExFreePool(buf);
+ ExFreePool(se);
+ if (se2) ExFreePool(se2);
+ return Status;
+ }
}
ExFreePool(compbuf);
@@ -2494,7 +2512,7 @@ static NTSTATUS flush_extents(send_context* context, traverse_ptr*
tp1, traverse
offset = se->offset + off;
send_add_tlv(context, BTRFS_SEND_TLV_OFFSET, &offset,
sizeof(UINT64));
- length = min((UINT16)(context->lastinode.size - se->offset - off),
length);
+ length = (UINT16)min(context->lastinode.size - se->offset - off,
length);
send_add_tlv(context, BTRFS_SEND_TLV_DATA, &buf[off], length);
send_command_finish(context, pos);
@@ -2639,7 +2657,8 @@ static NTSTATUS send_extent_data(send_context* context,
traverse_ptr* tp, traver
return STATUS_INTERNAL_ERROR;
}
- if (ed->compression != BTRFS_COMPRESSION_NONE && ed->compression !=
BTRFS_COMPRESSION_ZLIB && ed->compression != BTRFS_COMPRESSION_LZO) {
+ if (ed->compression != BTRFS_COMPRESSION_NONE && ed->compression !=
BTRFS_COMPRESSION_ZLIB &&
+ ed->compression != BTRFS_COMPRESSION_LZO && ed->compression !=
BTRFS_COMPRESSION_ZSTD) {
ERR("unknown compression type %u\n", ed->compression);
return STATUS_INTERNAL_ERROR;
}
@@ -2697,7 +2716,8 @@ static NTSTATUS send_extent_data(send_context* context,
traverse_ptr* tp, traver
return STATUS_INTERNAL_ERROR;
}
- if (ed->compression != BTRFS_COMPRESSION_NONE && ed->compression !=
BTRFS_COMPRESSION_ZLIB && ed->compression != BTRFS_COMPRESSION_LZO) {
+ if (ed->compression != BTRFS_COMPRESSION_NONE && ed->compression !=
BTRFS_COMPRESSION_ZLIB &&
+ ed->compression != BTRFS_COMPRESSION_LZO && ed->compression !=
BTRFS_COMPRESSION_ZSTD) {
ERR("unknown compression type %u\n", ed->compression);
return STATUS_INTERNAL_ERROR;
}
@@ -3730,6 +3750,10 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG
datalen, PFILE_OBJ
context = ExAllocatePoolWithTag(NonPagedPool, sizeof(send_context), ALLOC_TAG);
if (!context) {
ERR("out of memory\n");
+
+ if (clones)
+ ExFreePool(clones);
+
ExReleaseResourceLite(&Vcb->send_load_lock);
return STATUS_INSUFFICIENT_RESOURCES;
}
@@ -3769,6 +3793,10 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG
datalen, PFILE_OBJ
ERR("out of memory\n");
ExFreePool(context->data);
ExFreePool(context);
+
+ if (clones)
+ ExFreePool(clones);
+
ExReleaseResourceLite(&Vcb->send_load_lock);
return STATUS_INSUFFICIENT_RESOURCES;
}
@@ -3794,6 +3822,10 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG
datalen, PFILE_OBJ
ExFreePool(send);
ExFreePool(context->data);
ExFreePool(context);
+
+ if (clones)
+ ExFreePool(clones);
+
ExReleaseResourceLite(&Vcb->send_load_lock);
return Status;
}
diff --git a/drivers/filesystems/btrfs/treefuncs.c
b/drivers/filesystems/btrfs/treefuncs.c
index e2f6001e65..9785e12713 100644
--- a/drivers/filesystems/btrfs/treefuncs.c
+++ b/drivers/filesystems/btrfs/treefuncs.c
@@ -72,6 +72,7 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
pt, UINT6
if ((t->header.num_items * sizeof(leaf_node)) + sizeof(tree_header) >
Vcb->superblock.node_size) {
ERR("tree at %llx has more items than expected (%x)\n",
t->header.num_items);
+ ExFreePool(t);
ExFreePool(buf);
return STATUS_INSUFFICIENT_RESOURCES;
}
@@ -80,6 +81,7 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
pt, UINT6
td = ExAllocateFromPagedLookasideList(&Vcb->tree_data_lookaside);
if (!td) {
ERR("out of memory\n");
+ ExFreePool(t);
ExFreePool(buf);
return STATUS_INSUFFICIENT_RESOURCES;
}
@@ -93,6 +95,8 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
pt, UINT6
if (ln[i].size + sizeof(tree_header) + sizeof(leaf_node) >
Vcb->superblock.node_size) {
ERR("overlarge item in tree %llx: %u > %u\n", addr,
ln[i].size, Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node));
+ ExFreeToPagedLookasideList(&t->Vcb->tree_data_lookaside, td);
+ ExFreePool(t);
ExFreePool(buf);
return STATUS_INTERNAL_ERROR;
}
@@ -114,6 +118,7 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
pt, UINT6
if ((t->header.num_items * sizeof(internal_node)) + sizeof(tree_header) >
Vcb->superblock.node_size) {
ERR("tree at %llx has more items than expected (%x)\n",
t->header.num_items);
+ ExFreePool(t);
ExFreePool(buf);
return STATUS_INSUFFICIENT_RESOURCES;
}
@@ -122,6 +127,7 @@ NTSTATUS load_tree(device_extension* Vcb, UINT64 addr, root* r, tree**
pt, UINT6
td = ExAllocateFromPagedLookasideList(&Vcb->tree_data_lookaside);
if (!td) {
ERR("out of memory\n");
+ ExFreePool(t);
ExFreePool(buf);
return STATUS_INSUFFICIENT_RESOURCES;
}
@@ -1096,7 +1102,7 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
rollback_space* rs = ri->ptr;
if (rs->chunk)
- ExAcquireResourceExclusiveLite(&rs->chunk->lock, TRUE);
+ acquire_chunk_lock(rs->chunk, Vcb);
if (ri->type == ROLLBACK_ADD_SPACE)
space_list_subtract2(rs->list, rs->list_size, rs->address,
rs->length, NULL, NULL);
@@ -1138,7 +1144,7 @@ void do_rollback(device_extension* Vcb, LIST_ENTRY* rollback) {
le2 = le3;
}
- ExReleaseResourceLite(&rs->chunk->lock);
+ release_chunk_lock(rs->chunk, Vcb);
}
ExFreePool(rs);
@@ -1509,6 +1515,7 @@ static NTSTATUS handle_batch_collision(device_extension* Vcb,
batch_item* bi, tr
td2 =
ExAllocateFromPagedLookasideList(&Vcb->tree_data_lookaside);
if (!td2) {
ERR("out of memory\n");
+ ExFreePool(newdi);
return STATUS_INSUFFICIENT_RESOURCES;
}
@@ -1595,6 +1602,7 @@ static NTSTATUS handle_batch_collision(device_extension* Vcb,
batch_item* bi, tr
td2 =
ExAllocateFromPagedLookasideList(&Vcb->tree_data_lookaside);
if (!td2) {
ERR("out of memory\n");
+ ExFreePool(newir);
return STATUS_INSUFFICIENT_RESOURCES;
}
diff --git a/drivers/filesystems/btrfs/volume.c b/drivers/filesystems/btrfs/volume.c
index 5f7516a5c2..fa33221b7c 100644
--- a/drivers/filesystems/btrfs/volume.c
+++ b/drivers/filesystems/btrfs/volume.c
@@ -53,6 +53,8 @@ NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp->IoStatus.Information = 0;
+ ExAcquireResourceExclusiveLite(&pdo_list_lock, TRUE);
+
ExAcquireResourceSharedLite(&pdode->child_lock, TRUE);
if (InterlockedDecrement(&vde->open_count) == 0 && vde->removing)
{
@@ -83,16 +85,20 @@ NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
ExReleaseResourceLite(&pdode->child_lock);
ExDeleteResourceLite(&pdode->child_lock);
- IoDetachDevice(vde->pdo);
+
+ if (vde->pdo->AttachedDevice)
+ IoDetachDevice(vde->pdo);
pdo = vde->pdo;
IoDeleteDevice(vde->device);
- if (no_pnp)
+ if (!no_pnp)
IoDeleteDevice(pdo);
} else
ExReleaseResourceLite(&pdode->child_lock);
+ ExReleaseResourceLite(&pdo_list_lock);
+
return STATUS_SUCCESS;
}
@@ -971,7 +977,7 @@ static BOOL allow_degraded_mount(BTRFS_UUID* uuid) {
}
adus.Buffer = L"AllowDegraded";
- adus.Length = adus.MaximumLength = (USHORT)(wcslen(adus.Buffer) * sizeof(WCHAR));
+ adus.Length = adus.MaximumLength = sizeof(adus.Buffer) - sizeof(WCHAR);
if (NT_SUCCESS(ZwQueryValueKey(h, &adus, KeyValueFullInformation, kvfi, kvfilen,
&retlen))) {
if (kvfi->Type == REG_DWORD && kvfi->DataLength >=
sizeof(UINT32)) {
diff --git a/drivers/filesystems/btrfs/write.c b/drivers/filesystems/btrfs/write.c
index 6292d7efb0..ed1df4c897 100644
--- a/drivers/filesystems/btrfs/write.c
+++ b/drivers/filesystems/btrfs/write.c
@@ -404,10 +404,6 @@ NTSTATUS alloc_chunk(device_extension* Vcb, UINT64 flags, chunk** pc,
BOOL full_
return STATUS_INTERNAL_ERROR;
}
- max_chunk_size = min(max_chunk_size, total_size / 10); // cap at 10%
-
- TRACE("would allocate a new chunk of %llx bytes and stripe %llx\n",
max_chunk_size, max_stripe_size);
-
if (flags & BLOCK_FLAG_DUPLICATE) {
min_stripes = 2;
max_stripes = 2;
@@ -452,6 +448,13 @@ NTSTATUS alloc_chunk(device_extension* Vcb, UINT64 flags, chunk** pc,
BOOL full_
allowed_missing = 0;
}
+ if (max_chunk_size > total_size / 10) { // cap at 10%
+ max_chunk_size = total_size / 10;
+ max_stripe_size = max_chunk_size / min_stripes;
+ }
+
+ TRACE("would allocate a new chunk of %llx bytes and stripe %llx\n",
max_chunk_size, max_stripe_size);
+
stripes = ExAllocatePoolWithTag(PagedPool, sizeof(stripe) * max_stripes, ALLOC_TAG);
if (!stripes) {
ERR("out of memory\n");
@@ -511,6 +514,8 @@ NTSTATUS alloc_chunk(device_extension* Vcb, UINT64 flags, chunk** pc,
BOOL full_
goto end;
}
+ c->devices = NULL;
+
cisize = sizeof(CHUNK_ITEM) + (num_stripes * sizeof(CHUNK_ITEM_STRIPE));
c->chunk_item = ExAllocatePoolWithTag(NonPagedPool, cisize, ALLOC_TAG);
if (!c->chunk_item) {
@@ -549,7 +554,8 @@ NTSTATUS alloc_chunk(device_extension* Vcb, UINT64 flags, chunk** pc,
BOOL full_
stripe_size -= stripe_size % stripe_length;
if (stripe_size == 0) {
- Status = STATUS_INTERNAL_ERROR;
+ ERR("not enough free space found (stripe_size == 0)\n");
+ Status = STATUS_DISK_FULL;
goto end;
}
@@ -1287,7 +1293,8 @@ static NTSTATUS prepare_raid5_write(device_extension* Vcb, chunk* c,
UINT64 addr
stripes[i].mdl = IoAllocateMdl((UINT8*)MmGetMdlVirtualAddress(master_mdl) +
irp_offset, (ULONG)(stripes[i].end - stripes[i].start), FALSE, FALSE, NULL);
if (!stripes[i].mdl) {
ERR("IoAllocateMdl failed\n");
- return STATUS_INSUFFICIENT_RESOURCES;
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
}
}
}
@@ -1702,7 +1709,8 @@ static NTSTATUS prepare_raid6_write(device_extension* Vcb, chunk* c,
UINT64 addr
stripes[i].mdl = IoAllocateMdl((UINT8*)MmGetMdlVirtualAddress(master_mdl) +
irp_offset, (ULONG)(stripes[i].end - stripes[i].start), FALSE, FALSE, NULL);
if (!stripes[i].mdl) {
ERR("IoAllocateMdl failed\n");
- return STATUS_INSUFFICIENT_RESOURCES;
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto exit;
}
}
}
@@ -1880,7 +1888,6 @@ NTSTATUS write_data(_In_ device_extension* Vcb, _In_ UINT64 address,
_In_reads_b
NTSTATUS Status;
UINT32 i;
CHUNK_ITEM_STRIPE* cis;
- write_data_stripe* stripe;
write_stripe* stripes = NULL;
UINT64 total_writing = 0;
ULONG allowed_missing, missing;
@@ -2001,6 +2008,7 @@ NTSTATUS write_data(_In_ device_extension* Vcb, _In_ UINT64 address,
_In_reads_b
}
for (i = 0; i < c->chunk_item->num_stripes; i++) {
+ write_data_stripe* stripe;
PIO_STACK_LOCATION IrpSp;
stripe = ExAllocatePoolWithTag(NonPagedPool, sizeof(write_data_stripe),
ALLOC_TAG);
@@ -2028,6 +2036,7 @@ NTSTATUS write_data(_In_ device_extension* Vcb, _In_ UINT64 address,
_In_reads_b
if (!stripe->Irp) {
ERR("IoAllocateIrp failed\n");
+ ExFreePool(stripe);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
@@ -2036,6 +2045,7 @@ NTSTATUS write_data(_In_ device_extension* Vcb, _In_ UINT64 address,
_In_reads_b
if (!stripe->Irp) {
ERR("IoMakeAssociatedIrp failed\n");
+ ExFreePool(stripe);
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
@@ -2333,10 +2343,9 @@ void free_write_data_stripes(write_data_context* wtc) {
last_mdl = stripe->mdl;
-#ifdef __REACTOS__
if (stripe->Irp)
IoFreeIrp(stripe->Irp);
-#endif
+
le = le->Flink;
}
@@ -2888,7 +2897,7 @@ BOOL insert_extent_chunk(_In_ device_extension* Vcb, _In_ fcb* fcb,
_In_ chunk*
ExReleaseResourceLite(&c->changed_extents_lock);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
if (data) {
Status = write_data_complete(Vcb, address, data, (UINT32)length, Irp, NULL,
file_write, irp_offset,
@@ -2949,10 +2958,10 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb,
UINT64 start_data,
if (c->reloc || c->readonly || c->chunk_item->type !=
Vcb->data_flags)
return FALSE;
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if (length > c->chunk_item->size - c->used) {
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
return FALSE;
}
@@ -2961,7 +2970,7 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64
start_data,
if (!NT_SUCCESS(Status)) {
ERR("load_cache_chunk returned %08x\n", Status);
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
return FALSE;
}
}
@@ -2978,7 +2987,7 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64
start_data,
if (success)
*written += newlen;
else
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
return success;
} else if (s->address > ed2->address + ed2->size)
@@ -2987,7 +2996,7 @@ static BOOL try_extend_data(device_extension* Vcb, fcb* fcb, UINT64
start_data,
le = le->Flink;
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
return FALSE;
}
@@ -3017,7 +3026,7 @@ static NTSTATUS insert_chunk_fragmented(fcb* fcb, UINT64 start,
UINT64 length, U
c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == flags) {
while (!IsListEmpty(&c->space_size) && length > 0) {
@@ -3029,12 +3038,12 @@ static NTSTATUS insert_chunk_fragmented(fcb* fcb, UINT64 start,
UINT64 length, U
length -= extlen;
if (data) data += extlen;
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, fcb->Vcb);
}
}
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, fcb->Vcb);
if (length == 0)
break;
@@ -3067,7 +3076,7 @@ static NTSTATUS insert_prealloc_extent(fcb* fcb, UINT64 start,
UINT64 length, LI
c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == flags &&
(c->chunk_item->size - c->used) >= extlen) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, extlen,
!page_file, NULL, NULL, rollback, BTRFS_COMPRESSION_NONE, extlen, FALSE, 0)) {
@@ -3076,7 +3085,7 @@ static NTSTATUS insert_prealloc_extent(fcb* fcb, UINT64 start,
UINT64 length, LI
}
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, fcb->Vcb);
}
le = le->Flink;
@@ -3095,14 +3104,14 @@ static NTSTATUS insert_prealloc_extent(fcb* fcb, UINT64 start,
UINT64 length, LI
goto end;
}
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, fcb->Vcb);
if (c->chunk_item->type == flags && (c->chunk_item->size -
c->used) >= extlen) {
if (insert_extent_chunk(fcb->Vcb, fcb, c, start, extlen, !page_file, NULL,
NULL, rollback, BTRFS_COMPRESSION_NONE, extlen, FALSE, 0))
goto cont;
}
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, fcb->Vcb);
Status = insert_chunk_fragmented(fcb, start, length, NULL, TRUE, rollback);
if (!NT_SUCCESS(Status))
@@ -3159,7 +3168,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb,
UINT64 start_data
c = CONTAINING_RECORD(le, chunk, list_entry);
if (!c->readonly && !c->reloc) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if (c->chunk_item->type == flags &&
(c->chunk_item->size - c->used) >= newlen &&
insert_extent_chunk(Vcb, fcb, c, start_data, newlen, FALSE, data,
Irp, rollback, BTRFS_COMPRESSION_NONE, newlen, file_write, irp_offset)) {
@@ -3177,7 +3186,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb,
UINT64 start_data
break;
}
} else
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
}
le = le->Flink;
@@ -3201,7 +3210,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb,
UINT64 start_data
}
if (c) {
- ExAcquireResourceExclusiveLite(&c->lock, TRUE);
+ acquire_chunk_lock(c, Vcb);
if (c->chunk_item->type == flags && (c->chunk_item->size
- c->used) >= newlen &&
insert_extent_chunk(Vcb, fcb, c, start_data, newlen, FALSE, data, Irp,
rollback, BTRFS_COMPRESSION_NONE, newlen, file_write, irp_offset)) {
@@ -3217,7 +3226,7 @@ static NTSTATUS insert_extent(device_extension* Vcb, fcb* fcb,
UINT64 start_data
data = &((UINT8*)data)[newlen];
}
} else
- ExReleaseResourceLite(&c->lock);
+ release_chunk_lock(c, Vcb);
}
if (!done) {
@@ -3642,6 +3651,8 @@ static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, UINT64
start_data,
Irp, NULL, file_write, irp_offset + ext->offset -
start_data, priority);
if (!NT_SUCCESS(Status)) {
ERR("write_data_complete returned %08x\n", Status);
+ ExFreePool(newext1);
+ ExFreePool(newext2);
return Status;
}
@@ -3737,6 +3748,8 @@ static NTSTATUS do_write_file_prealloc(fcb* fcb, extent* ext, UINT64
start_data,
Status = write_data_complete(fcb->Vcb, ed2->address + ned2->offset,
data, (UINT32)ned2->num_bytes, Irp, NULL, file_write, irp_offset, priority);
if (!NT_SUCCESS(Status)) {
ERR("write_data_complete returned %08x\n", Status);
+ ExFreePool(newext1);
+ ExFreePool(newext2);
return Status;
}
diff --git a/drivers/filesystems/btrfs/zstd/bitstream.h
b/drivers/filesystems/btrfs/zstd/bitstream.h
new file mode 100644
index 0000000000..ef89b9878e
--- /dev/null
+++ b/drivers/filesystems/btrfs/zstd/bitstream.h
@@ -0,0 +1,455 @@
+/* ******************************************************************
+ bitstream
+ Part of FSE library
+ Copyright (C) 2013-present, Yann Collet.
+
+ BSD 2-Clause License (
http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - Source repository :
https://github.com/Cyan4973/FiniteStateEntropy
+****************************************************************** */
+#ifndef BITSTREAM_H_MODULE
+#define BITSTREAM_H_MODULE
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+/*
+* This API consists of small unitary functions, which must be inlined for best
performance.
+* Since link-time-optimization is not available for all compilers,
+* these functions are defined into a .h to be included.
+*/
+
+/*-****************************************
+* Dependencies
+******************************************/
+#include "mem.h" /* unaligned access routines */
+#include "debug.h" /* assert(), DEBUGLOG(), RAWLOG() */
+#include "error_private.h" /* error codes and messages */
+
+
+/*=========================================
+* Target specific
+=========================================*/
+#if defined(__BMI__) && defined(__GNUC__)
+# include <immintrin.h> /* support for bextr (experimental) */
+#endif
+
+#define STREAM_ACCUMULATOR_MIN_32 25
+#define STREAM_ACCUMULATOR_MIN_64 57
+#define STREAM_ACCUMULATOR_MIN ((U32)(MEM_32bits() ? STREAM_ACCUMULATOR_MIN_32 :
STREAM_ACCUMULATOR_MIN_64))
+
+
+/*-******************************************
+* bitStream encoding API (write forward)
+********************************************/
+/* bitStream can mix input from multiple sources.
+ * A critical property of these streams is that they encode and decode in **reverse**
direction.
+ * So the first bit sequence you add will be the last to be read, like a LIFO stack.
+ */
+typedef struct {
+ size_t bitContainer;
+ unsigned bitPos;
+ char* startPtr;
+ char* ptr;
+ char* endPtr;
+} BIT_CStream_t;
+
+MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* dstBuffer, size_t
dstCapacity);
+MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
+MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC);
+MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC);
+
+/* Start with initCStream, providing the size of buffer to write into.
+* bitStream will never write outside of this buffer.
+* `dstCapacity` must be >= sizeof(bitD->bitContainer), otherwise @return will be
an error code.
+*
+* bits are first added to a local register.
+* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits
systems.
+* Writing data into memory is an explicit operation, performed by the flushBits
function.
+* Hence keep track how many bits are potentially stored into local register to avoid
register overflow.
+* After a flushBits, a maximum of 7 bits might still be stored into local register.
+*
+* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits
bitstream readers.
+*
+* Last operation is to close the bitStream.
+* The function returns the final size of CStream in bytes.
+* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable)
+*/
+
+
+/*-********************************************
+* bitStream decoding API (read backward)
+**********************************************/
+typedef struct {
+ size_t bitContainer;
+ unsigned bitsConsumed;
+ const char* ptr;
+ const char* start;
+ const char* limitPtr;
+} BIT_DStream_t;
+
+typedef enum { BIT_DStream_unfinished = 0,
+ BIT_DStream_endOfBuffer = 1,
+ BIT_DStream_completed = 2,
+ BIT_DStream_overflow = 3 } BIT_DStream_status; /* result of
BIT_reloadDStream() */
+ /* 1,2,4,8 would be better for bitmap combinations, but slows down
performance a bit ... :( */
+
+MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t
srcSize);
+MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, unsigned nbBits);
+MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD);
+MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD);
+
+
+/* Start by invoking BIT_initDStream().
+* A chunk of the bitStream is then stored into a local register.
+* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems
(size_t).
+* You can then retrieve bitFields stored into the local register, **in reverse order**.
+* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method.
+* A reload guarantee a minimum of ((8*sizeof(bitD->bitContainer))-7) bits when its
result is BIT_DStream_unfinished.
+* Otherwise, it can be less than that, so proceed accordingly.
+* Checking if DStream has reached its end can be performed with BIT_endOfDStream().
+*/
+
+
+/*-****************************************
+* unsafe API
+******************************************/
+MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits);
+/* faster, but works only if value is "clean", meaning all high bits above
nbBits are 0 */
+
+MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC);
+/* unsafe version; does not check buffer overflow */
+
+MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, unsigned nbBits);
+/* faster, but works only if nbBits >= 1 */
+
+
+
+/*-**************************************************************
+* Internal functions
+****************************************************************/
+MEM_STATIC unsigned BIT_highbit32 (U32 val)
+{
+ assert(val != 0);
+ {
+# if defined(_MSC_VER) /* Visual */
+ unsigned long r=0;
+ _BitScanReverse ( &r, val );
+ return (unsigned) r;
+# elif defined(__GNUC__) && (__GNUC__ >= 3) /* Use GCC Intrinsic */
+ return 31 - __builtin_clz (val);
+# else /* Software version */
+ static const unsigned DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29,
+ 11, 14, 16, 18, 22, 25, 3, 30,
+ 8, 12, 20, 28, 15, 17, 24, 7,
+ 19, 27, 23, 6, 26, 5, 4, 31 };
+ U32 v = val;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ return DeBruijnClz[ (U32) (v * 0x07C4ACDDU) >> 27];
+# endif
+ }
+}
+
+/*===== Local Constants =====*/
+static const unsigned BIT_mask[] = {
+ 0, 1, 3, 7, 0xF, 0x1F,
+ 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF,
+ 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF,
+ 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF,
+ 0x3FFFFFFF, 0x7FFFFFFF}; /* up to 31 bits */
+#define BIT_MASK_SIZE (sizeof(BIT_mask) / sizeof(BIT_mask[0]))
+
+/*-**************************************************************
+* bitStream encoding
+****************************************************************/
+/*! BIT_initCStream() :
+ * `dstCapacity` must be > sizeof(size_t)
+ * @return : 0 if success,
+ * otherwise an error code (can be tested using ERR_isError()) */
+MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC,
+ void* startPtr, size_t dstCapacity)
+{
+ bitC->bitContainer = 0;
+ bitC->bitPos = 0;
+ bitC->startPtr = (char*)startPtr;
+ bitC->ptr = bitC->startPtr;
+ bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->bitContainer);
+ if (dstCapacity <= sizeof(bitC->bitContainer)) return ERROR(dstSize_tooSmall);
+ return 0;
+}
+
+/*! BIT_addBits() :
+ * can add up to 31 bits into `bitC`.
+ * Note : does not check for register overflow ! */
+MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC,
+ size_t value, unsigned nbBits)
+{
+ MEM_STATIC_ASSERT(BIT_MASK_SIZE == 32);
+ assert(nbBits < BIT_MASK_SIZE);
+ assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ bitC->bitContainer |= (value & BIT_mask[nbBits]) << bitC->bitPos;
+ bitC->bitPos += nbBits;
+}
+
+/*! BIT_addBitsFast() :
+ * works only if `value` is _clean_,
+ * meaning all high bits above nbBits are 0 */
+MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC,
+ size_t value, unsigned nbBits)
+{
+ assert((value>>nbBits) == 0);
+ assert(nbBits + bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ bitC->bitContainer |= value << bitC->bitPos;
+ bitC->bitPos += nbBits;
+}
+
+/*! BIT_flushBitsFast() :
+ * assumption : bitContainer has not overflowed
+ * unsafe version; does not check buffer overflow */
+MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC)
+{
+ size_t const nbBytes = bitC->bitPos >> 3;
+ assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ MEM_writeLEST(bitC->ptr, bitC->bitContainer);
+ bitC->ptr += nbBytes;
+ assert(bitC->ptr <= bitC->endPtr);
+ bitC->bitPos &= 7;
+ bitC->bitContainer >>= nbBytes*8;
+}
+
+/*! BIT_flushBits() :
+ * assumption : bitContainer has not overflowed
+ * safe version; check for buffer overflow, and prevents it.
+ * note : does not signal buffer overflow.
+ * overflow will be revealed later on using BIT_closeCStream() */
+MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC)
+{
+ size_t const nbBytes = bitC->bitPos >> 3;
+ assert(bitC->bitPos < sizeof(bitC->bitContainer) * 8);
+ MEM_writeLEST(bitC->ptr, bitC->bitContainer);
+ bitC->ptr += nbBytes;
+ if (bitC->ptr > bitC->endPtr) bitC->ptr = bitC->endPtr;
+ bitC->bitPos &= 7;
+ bitC->bitContainer >>= nbBytes*8;
+}
+
+/*! BIT_closeCStream() :
+ * @return : size of CStream, in bytes,
+ * or 0 if it could not fit into dstBuffer */
+MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC)
+{
+ BIT_addBitsFast(bitC, 1, 1); /* endMark */
+ BIT_flushBits(bitC);
+ if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */
+ return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0);
+}
+
+
+/*-********************************************************
+* bitStream decoding
+**********************************************************/
+/*! BIT_initDStream() :
+ * Initialize a BIT_DStream_t.
+ * `bitD` : a pointer to an already allocated BIT_DStream_t structure.
+ * `srcSize` must be the *exact* size of the bitStream, in bytes.
+ * @return : size of stream (== srcSize), or an errorCode if a problem is detected
+ */
+MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t
srcSize)
+{
+ if (srcSize < 1) { memset(bitD, 0, sizeof(*bitD)); return ERROR(srcSize_wrong); }
+
+ bitD->start = (const char*)srcBuffer;
+ bitD->limitPtr = bitD->start + sizeof(bitD->bitContainer);
+
+ if (srcSize >= sizeof(bitD->bitContainer)) { /* normal case */
+ bitD->ptr = (const char*)srcBuffer + srcSize -
sizeof(bitD->bitContainer);
+ bitD->bitContainer = MEM_readLEST(bitD->ptr);
+ { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
+ bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0; /* ensures
bitsConsumed is always set */
+ if (lastByte == 0) return ERROR(GENERIC); /* endMark not present */ }
+ } else {
+ bitD->ptr = bitD->start;
+ bitD->bitContainer = *(const BYTE*)(bitD->start);
+ switch(srcSize)
+ {
+ case 7: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[6]) <<
(sizeof(bitD->bitContainer)*8 - 16);
+ /* fall-through */
+
+ case 6: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[5]) <<
(sizeof(bitD->bitContainer)*8 - 24);
+ /* fall-through */
+
+ case 5: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[4]) <<
(sizeof(bitD->bitContainer)*8 - 32);
+ /* fall-through */
+
+ case 4: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[3]) <<
24;
+ /* fall-through */
+
+ case 3: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[2]) <<
16;
+ /* fall-through */
+
+ case 2: bitD->bitContainer += (size_t)(((const BYTE*)(srcBuffer))[1]) <<
8;
+ /* fall-through */
+
+ default: break;
+ }
+ { BYTE const lastByte = ((const BYTE*)srcBuffer)[srcSize-1];
+ bitD->bitsConsumed = lastByte ? 8 - BIT_highbit32(lastByte) : 0;
+ if (lastByte == 0) return ERROR(corruption_detected); /* endMark not present
*/
+ }
+ bitD->bitsConsumed += (U32)(sizeof(bitD->bitContainer) - srcSize)*8;
+ }
+
+ return srcSize;
+}
+
+MEM_STATIC size_t BIT_getUpperBits(size_t bitContainer, U32 const start)
+{
+ return bitContainer >> start;
+}
+
+MEM_STATIC size_t BIT_getMiddleBits(size_t bitContainer, U32 const start, U32 const
nbBits)
+{
+ U32 const regMask = sizeof(bitContainer)*8 - 1;
+ /* if start > regMask, bitstream is corrupted, and result is undefined */
+ assert(nbBits < BIT_MASK_SIZE);
+ return (bitContainer >> (start & regMask)) & BIT_mask[nbBits];
+}
+
+MEM_STATIC size_t BIT_getLowerBits(size_t bitContainer, U32 const nbBits)
+{
+ assert(nbBits < BIT_MASK_SIZE);
+ return bitContainer & BIT_mask[nbBits];
+}
+
+/*! BIT_lookBits() :
+ * Provides next n bits from local register.
+ * local register is not modified.
+ * On 32-bits, maxNbBits==24.
+ * On 64-bits, maxNbBits==56.
+ * @return : value extracted */
+MEM_STATIC size_t BIT_lookBits(const BIT_DStream_t* bitD, U32 nbBits)
+{
+ /* arbitrate between double-shift and shift+mask */
+#if 1
+ /* if bitD->bitsConsumed + nbBits > sizeof(bitD->bitContainer)*8,
+ * bitstream is likely corrupted, and result is undefined */
+ return BIT_getMiddleBits(bitD->bitContainer, (sizeof(bitD->bitContainer)*8) -
bitD->bitsConsumed - nbBits, nbBits);
+#else
... 20921 lines suppressed ...