https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c982533ea9ede11a71992…
commit c982533ea9ede11a719925731c9c1b2fc5b5d347
Author: Vincent Franchomme <franchomme.vincent(a)gmail.com>
AuthorDate: Thu Apr 28 21:34:48 2022 +0200
Commit: Hermès BÉLUSCA - MAÏTO <hermes.belusca-maito(a)reactos.org>
CommitDate: Tue May 3 17:30:11 2022 +0200
[BTRFS][UBTRFS][SHELLBTRFS] Upgrade to 1.7.6 (#4417)
v1.7.6 (2021-01-14):
- Fixed race condition when booting with Quibble
- No longer need to restart Windows after initial installation
- Forced maximum file name to 255 UTF-8 characters, to match Linux driver
- Fixed issue where directories could be created with trailing backslash
- Fixed potential deadlock when Windows calls NtCreateSection during flush
- Miscellaneous bug fixes
---
dll/shellext/shellbtrfs/shellbtrfs.rc | 10 +-
dll/win32/ubtrfs/ubtrfs.rc | 10 +-
drivers/filesystems/btrfs/boot.c | 360 +++-------------------
drivers/filesystems/btrfs/btrfs.c | 49 ++-
drivers/filesystems/btrfs/btrfs.inf | 2 +-
drivers/filesystems/btrfs/btrfs.rc | 10 +-
drivers/filesystems/btrfs/btrfs_drv.h | 12 +-
drivers/filesystems/btrfs/create.c | 529 +++++++++++++++++++--------------
drivers/filesystems/btrfs/fastio.c | 46 +++
drivers/filesystems/btrfs/fileinfo.c | 132 +++++---
drivers/filesystems/btrfs/free-space.c | 3 +
drivers/filesystems/btrfs/fsctl.c | 103 +++++--
drivers/filesystems/btrfs/pnp.c | 12 +
drivers/filesystems/btrfs/reparse.c | 10 +-
drivers/filesystems/btrfs/search.c | 2 +-
drivers/filesystems/btrfs/security.c | 2 +-
drivers/filesystems/btrfs/treefuncs.c | 6 +
drivers/filesystems/btrfs/write.c | 15 +-
sdk/lib/fslib/btrfslib/btrfslib.c | 7 -
19 files changed, 657 insertions(+), 663 deletions(-)
diff --git a/dll/shellext/shellbtrfs/shellbtrfs.rc
b/dll/shellext/shellbtrfs/shellbtrfs.rc
index 4852681751d..845d8bc7844 100644
--- a/dll/shellext/shellbtrfs/shellbtrfs.rc
+++ b/dll/shellext/shellbtrfs/shellbtrfs.rc
@@ -61,8 +61,8 @@ IDI_ICON1 ICON "subvol.ico"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,7,5,0
- PRODUCTVERSION 1,7,5,0
+ FILEVERSION 1,7,6,0
+ PRODUCTVERSION 1,7,6,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -78,12 +78,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "FileDescription", "WinBtrfs shell extension"
- VALUE "FileVersion", "1.7.5"
+ VALUE "FileVersion", "1.7.6"
VALUE "InternalName", "btrfs"
- VALUE "LegalCopyright", "Copyright (c) Mark Harmstone
2016-20"
+ VALUE "LegalCopyright", "Copyright (c) Mark Harmstone
2016-21"
VALUE "OriginalFilename", "shellbtrfs.dll"
VALUE "ProductName", "WinBtrfs"
- VALUE "ProductVersion", "1.7.5"
+ VALUE "ProductVersion", "1.7.6"
END
END
BLOCK "VarFileInfo"
diff --git a/dll/win32/ubtrfs/ubtrfs.rc b/dll/win32/ubtrfs/ubtrfs.rc
index 686e30e7b3c..27eef7a7c0b 100644
--- a/dll/win32/ubtrfs/ubtrfs.rc
+++ b/dll/win32/ubtrfs/ubtrfs.rc
@@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,7,5,0
- PRODUCTVERSION 1,7,5,0
+ FILEVERSION 1,7,6,0
+ PRODUCTVERSION 1,7,6,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "FileDescription", "Btrfs utility DLL"
- VALUE "FileVersion", "1.7.5"
+ VALUE "FileVersion", "1.7.6"
VALUE "InternalName", "ubtrfs"
- VALUE "LegalCopyright", "Copyright (c) Mark Harmstone
2016-20"
+ VALUE "LegalCopyright", "Copyright (c) Mark Harmstone
2016-21"
VALUE "OriginalFilename", "ubtrfs.dll"
VALUE "ProductName", "WinBtrfs"
- VALUE "ProductVersion", "1.7.5"
+ VALUE "ProductVersion", "1.7.6"
END
END
BLOCK "VarFileInfo"
diff --git a/drivers/filesystems/btrfs/boot.c b/drivers/filesystems/btrfs/boot.c
index 43486cfad33..011fd544c80 100644
--- a/drivers/filesystems/btrfs/boot.c
+++ b/drivers/filesystems/btrfs/boot.c
@@ -46,20 +46,7 @@ typedef struct {
ULONG ExtensionFlags;
} DEVOBJ_EXTENSION2;
-typedef enum {
- system_root_unknown,
- system_root_partition,
- system_root_btrfs
-} system_root_type;
-
-typedef struct {
- uint32_t disk_num;
- uint32_t partition_num;
- BTRFS_UUID uuid;
- system_root_type type;
-} system_root;
-
-static void get_system_root(system_root* sr) {
+static bool get_system_root() {
NTSTATUS Status;
HANDLE h;
UNICODE_STRING us, target;
@@ -69,8 +56,6 @@ static void get_system_root(system_root* sr) {
static const WCHAR system_root[] = L"\\SystemRoot";
static const WCHAR boot_device[] = L"\\Device\\BootDevice";
- static const WCHAR arc_prefix[] = L"\\ArcName\\multi(0)disk(0)rdisk(";
- static const WCHAR arc_middle[] = L")partition(";
static const WCHAR arc_btrfs_prefix[] = L"\\ArcName\\btrfs(";
us.Buffer = (WCHAR*)system_root;
@@ -82,7 +67,7 @@ static void get_system_root(system_root* sr) {
Status = ZwOpenSymbolicLinkObject(&h, GENERIC_READ, &objatt);
if (!NT_SUCCESS(Status)) {
ERR("ZwOpenSymbolicLinkObject returned %08lx\n", Status);
- return;
+ return false;
}
target.Length = target.MaximumLength = 0;
@@ -91,19 +76,19 @@ static void get_system_root(system_root* sr) {
if (Status != STATUS_BUFFER_TOO_SMALL) {
ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status);
NtClose(h);
- return;
+ return false;
}
if (retlen == 0) {
NtClose(h);
- return;
+ return false;
}
target.Buffer = ExAllocatePoolWithTag(NonPagedPool, retlen, ALLOC_TAG);
if (!target.Buffer) {
ERR("out of memory\n");
NtClose(h);
- return;
+ return false;
}
target.Length = target.MaximumLength = (USHORT)retlen;
@@ -113,7 +98,7 @@ static void get_system_root(system_root* sr) {
ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status);
NtClose(h);
ExFreePool(target.Buffer);
- return;
+ return false;
}
NtClose(h);
@@ -136,85 +121,33 @@ static void get_system_root(system_root* sr) {
break;
}
- sr->type = system_root_unknown;
-
- if (target.Length >= sizeof(arc_prefix) - sizeof(WCHAR) &&
- RtlCompareMemory(target.Buffer, arc_prefix, sizeof(arc_prefix) - sizeof(WCHAR))
== sizeof(arc_prefix) - sizeof(WCHAR)) {
- WCHAR* s = &target.Buffer[(sizeof(arc_prefix) / sizeof(WCHAR)) - 1];
- ULONG left = ((target.Length - sizeof(arc_prefix)) / sizeof(WCHAR)) + 1;
-
- if (left == 0 || s[0] < '0' || s[0] > '9') {
- ExFreePool(target.Buffer);
- return;
- }
-
- sr->disk_num = 0;
-
- while (left > 0 && s[0] >= '0' && s[0] <=
'9') {
- sr->disk_num *= 10;
- sr->disk_num += s[0] - '0';
- s++;
- left--;
- }
-
- if (left <= (sizeof(arc_middle) / sizeof(WCHAR)) - 1 ||
- RtlCompareMemory(s, arc_middle, sizeof(arc_middle) - sizeof(WCHAR)) !=
sizeof(arc_middle) - sizeof(WCHAR)) {
- ExFreePool(target.Buffer);
- return;
- }
-
- s = &s[(sizeof(arc_middle) / sizeof(WCHAR)) - 1];
- left -= (sizeof(arc_middle) / sizeof(WCHAR)) - 1;
-
- if (left == 0 || s[0] < '0' || s[0] > '9') {
- ExFreePool(target.Buffer);
- return;
- }
-
- sr->partition_num = 0;
-
- while (left > 0 && s[0] >= '0' && s[0] <=
'9') {
- sr->partition_num *= 10;
- sr->partition_num += s[0] - '0';
- s++;
- left--;
- }
-
- sr->type = system_root_partition;
- } else if (target.Length >= sizeof(arc_btrfs_prefix) - sizeof(WCHAR) &&
+ if (target.Length >= sizeof(arc_btrfs_prefix) - sizeof(WCHAR) &&
RtlCompareMemory(target.Buffer, arc_btrfs_prefix, sizeof(arc_btrfs_prefix) -
sizeof(WCHAR)) == sizeof(arc_btrfs_prefix) - sizeof(WCHAR)) {
WCHAR* s = &target.Buffer[(sizeof(arc_btrfs_prefix) / sizeof(WCHAR)) - 1];
-#ifdef __REACTOS__
- unsigned int i;
-#endif // __REACTOS__
-#ifndef __REACTOS__
for (unsigned int i = 0; i < 16; i++) {
-#else
- for (i = 0; i < 16; i++) {
-#endif // __REACTOS__
if (*s >= '0' && *s <= '9')
- sr->uuid.uuid[i] = (*s - '0') << 4;
+ boot_uuid.uuid[i] = (*s - '0') << 4;
else if (*s >= 'a' && *s <= 'f')
- sr->uuid.uuid[i] = (*s - 'a' + 0xa) << 4;
+ boot_uuid.uuid[i] = (*s - 'a' + 0xa) << 4;
else if (*s >= 'A' && *s <= 'F')
- sr->uuid.uuid[i] = (*s - 'A' + 0xa) << 4;
+ boot_uuid.uuid[i] = (*s - 'A' + 0xa) << 4;
else {
ExFreePool(target.Buffer);
- return;
+ return false;
}
s++;
if (*s >= '0' && *s <= '9')
- sr->uuid.uuid[i] |= *s - '0';
+ boot_uuid.uuid[i] |= *s - '0';
else if (*s >= 'a' && *s <= 'f')
- sr->uuid.uuid[i] |= *s - 'a' + 0xa;
+ boot_uuid.uuid[i] |= *s - 'a' + 0xa;
else if (*s >= 'A' && *s <= 'F')
- sr->uuid.uuid[i] |= *s - 'A' + 0xa;
+ boot_uuid.uuid[i] |= *s - 'A' + 0xa;
else {
ExFreePool(target.Buffer);
- return;
+ return false;
}
s++;
@@ -222,7 +155,7 @@ static void get_system_root(system_root* sr) {
if (i == 3 || i == 5 || i == 7 || i == 9) {
if (*s != '-') {
ExFreePool(target.Buffer);
- return;
+ return false;
}
s++;
@@ -231,97 +164,17 @@ static void get_system_root(system_root* sr) {
if (*s != ')') {
ExFreePool(target.Buffer);
- return;
+ return false;
}
- sr->type = system_root_btrfs;
- }
-
- ExFreePool(target.Buffer);
-}
-
-static void append_int_to_us(UNICODE_STRING* us, unsigned int n) {
- unsigned int num, digits = 0;
- WCHAR* ptr;
-
- if (n == 0) {
- us->Buffer[us->Length / sizeof(WCHAR)] = '0';
- us->Length += sizeof(WCHAR);
- return;
- }
-
- num = n;
-
- while (num > 0) {
- digits++;
- num /= 10;
- }
-
- ptr = &us->Buffer[(us->Length / sizeof(WCHAR)) + digits - 1];
+ ExFreePool(target.Buffer);
- while (n > 0) {
- *ptr = L'0' + (n % 10);
- ptr--;
- n /= 10;
+ return true;
}
- us->Length += digits * sizeof(WCHAR);
-}
-
-static void change_symlink(uint32_t disk_num, uint32_t partition_num, BTRFS_UUID* uuid)
{
- NTSTATUS Status;
- UNICODE_STRING us, us2;
- WCHAR symlink[60], target[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) + 36], *w;
-#ifdef __REACTOS__
- unsigned int i;
-#endif
-
- static const WCHAR dev_path1[] = L"\\Device\\Harddisk";
- static const WCHAR dev_path2[] = L"\\Partition";
-
- us.Buffer = symlink;
- us.Length = sizeof(dev_path1) - sizeof(WCHAR);
- us.MaximumLength = sizeof(symlink);
-
- RtlCopyMemory(symlink, dev_path1, sizeof(dev_path1) - sizeof(WCHAR));
-
- append_int_to_us(&us, disk_num);
-
- RtlCopyMemory(&us.Buffer[us.Length / sizeof(WCHAR)], dev_path2, sizeof(dev_path2)
- sizeof(WCHAR));
- us.Length += sizeof(dev_path2) - sizeof(WCHAR);
-
- append_int_to_us(&us, partition_num);
-
- Status = IoDeleteSymbolicLink(&us);
- if (!NT_SUCCESS(Status))
- ERR("IoDeleteSymbolicLink returned %08lx\n", Status);
-
- RtlCopyMemory(target, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) -
sizeof(WCHAR));
-
- w = &target[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
-
-#ifndef __REACTOS__
- for (unsigned int i = 0; i < 16; i++) {
-#else
- for (i = 0; i < 16; i++) {
-#endif
- *w = hex_digit(uuid->uuid[i] >> 4); w++;
- *w = hex_digit(uuid->uuid[i] & 0xf); w++;
-
- if (i == 3 || i == 5 || i == 7 || i == 9) {
- *w = L'-';
- w++;
- }
- }
-
- *w = L'}';
-
- us2.Buffer = target;
- us2.Length = us2.MaximumLength = sizeof(target);
+ ExFreePool(target.Buffer);
- Status = IoCreateSymbolicLink(&us, &us2);
- if (!NT_SUCCESS(Status))
- ERR("IoCreateSymbolicLink returned %08lx\n", Status);
+ return false;
}
static void mountmgr_notification(BTRFS_UUID* uuid) {
@@ -332,9 +185,6 @@ static void mountmgr_notification(BTRFS_UUID* uuid) {
ULONG mmtnlen;
MOUNTMGR_TARGET_NAME* mmtn;
WCHAR* w;
-#ifdef __REACTOS__
- unsigned int i;
-#endif
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES,
&FileObject, &mountmgr);
@@ -357,11 +207,7 @@ static void mountmgr_notification(BTRFS_UUID* uuid) {
w = &mmtn->DeviceName[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
-#ifndef __REACTOS__
for (unsigned int i = 0; i < 16; i++) {
-#else
- for (i = 0; i < 16; i++) {
-#endif
*w = hex_digit(uuid->uuid[i] >> 4); w++;
*w = hex_digit(uuid->uuid[i] & 0xf); w++;
@@ -487,166 +333,52 @@ void boot_add_device(DEVICE_OBJECT* pdo) {
mountmgr_notification(&pdode->uuid);
}
-/* If booting from Btrfs, Windows will pass the device object for the raw partition to
- * mount_vol - which is no good to us, as we only use the \Device\Btrfs{} devices we
- * create so that RAID works correctly.
- * At the time check_system_root gets called, \SystemRoot is a symlink to the ARC
device,
- * e.g. \ArcName\multi(0)disk(0)rdisk(0)partition(1)\Windows. We can't change the
symlink,
- * as it gets clobbered by IopReassignSystemRoot shortly afterwards, and we can't
touch
- * the \ArcName symlinks as they haven't been created yet. Instead, we need to change
the
- * symlink \Device\HarddiskX\PartitionY, which is what the ArcName symlink will shortly
- * point to.
- */
-void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULONG Count)
{
- system_root sr;
+void check_system_root() {
LIST_ENTRY* le;
- bool done = false;
PDEVICE_OBJECT pdo_to_add = NULL;
- volume_child* boot_vc = NULL;
-
- TRACE("(%p, %p, %lu)\n", DriverObject, Context, Count);
- UNUSED(DriverObject);
- UNUSED(Context);
- UNUSED(Count);
+ TRACE("()\n");
// wait for any PNP notifications in progress to finish
ExAcquireResourceExclusiveLite(&boot_lock, TRUE);
ExReleaseResourceLite(&boot_lock);
- get_system_root(&sr);
-
- if (sr.type == system_root_partition) {
- TRACE("system boot partition is disk %u, partition %u\n", sr.disk_num,
sr.partition_num);
-
- ExAcquireResourceSharedLite(&pdo_list_lock, true);
-
- le = pdo_list.Flink;
- while (le != &pdo_list) {
- LIST_ENTRY* le2;
- pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension,
list_entry);
-
- ExAcquireResourceSharedLite(&pdode->child_lock, true);
-
- le2 = pdode->children.Flink;
-
- while (le2 != &pdode->children) {
- volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry);
-
- if (vc->disk_num == sr.disk_num && vc->part_num ==
sr.partition_num) {
- change_symlink(sr.disk_num, sr.partition_num, &pdode->uuid);
- done = true;
-
- vc->boot_volume = true;
- boot_uuid = pdode->uuid;
-
- if (!pdode->vde)
- pdo_to_add = pdode->pdo;
-
- boot_vc = vc;
-
- break;
- }
-
- le2 = le2->Flink;
- }
-
- if (done) {
- le2 = pdode->children.Flink;
-
- while (le2 != &pdode->children) {
- volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry);
-
- /* On Windows 7 we need to clear the DO_SYSTEM_BOOT_PARTITION flag
of
- * all of our underlying partition objects - otherwise IopMountVolume
- * will bugcheck with UNMOUNTABLE_BOOT_VOLUME when it tries and fails
- * to mount one. */
- if (vc->devobj) {
- PDEVICE_OBJECT dev = vc->devobj;
-
- ObReferenceObject(dev);
-
- while (dev) {
- PDEVICE_OBJECT dev2 = IoGetLowerDeviceObject(dev);
-
- dev->Flags &= ~DO_SYSTEM_BOOT_PARTITION;
-
- ObDereferenceObject(dev);
-
- dev = dev2;
- }
- }
-
- le2 = le2->Flink;
- }
-
- ExReleaseResourceLite(&pdode->child_lock);
-
- break;
- }
-
- ExReleaseResourceLite(&pdode->child_lock);
+ if (!get_system_root())
+ return;
- le = le->Flink;
- }
+ ExAcquireResourceSharedLite(&pdo_list_lock, true);
- ExReleaseResourceLite(&pdo_list_lock);
- } else if (sr.type == system_root_btrfs) {
- boot_uuid = sr.uuid;
+ le = pdo_list.Flink;
+ while (le != &pdo_list) {
+ pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension,
list_entry);
- ExAcquireResourceSharedLite(&pdo_list_lock, true);
+ if (RtlCompareMemory(&pdode->uuid, &boot_uuid, sizeof(BTRFS_UUID)) ==
sizeof(BTRFS_UUID)) {
+ if (!pdode->vde)
+ pdo_to_add = pdode->pdo;
+ else if (pdode->vde->device &&
!(pdode->vde->device->Flags & DO_SYSTEM_BOOT_PARTITION)) { // AddDevice has
beaten us to it
+ NTSTATUS Status;
- le = pdo_list.Flink;
- while (le != &pdo_list) {
- pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension,
list_entry);
+ pdode->vde->device->Flags |= DO_SYSTEM_BOOT_PARTITION;
+ pdode->pdo->Flags |= DO_SYSTEM_BOOT_PARTITION;
- if (RtlCompareMemory(&pdode->uuid, &sr.uuid, sizeof(BTRFS_UUID))
== sizeof(BTRFS_UUID)) {
- if (!pdode->vde)
- pdo_to_add = pdode->pdo;
+ Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name,
false);
+ if (!NT_SUCCESS(Status))
+ ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
- break;
+ Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name,
true);
+ if (!NT_SUCCESS(Status))
+ ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
}
- le = le->Flink;
+ break;
}
- ExReleaseResourceLite(&pdo_list_lock);
+ le = le->Flink;
}
- if (boot_vc) {
- NTSTATUS Status;
- UNICODE_STRING name;
-
- /* On Windows 8, mountmgr!MountMgrFindBootVolume returns the first volume in its
database
- * with the DO_SYSTEM_BOOT_PARTITION flag set. We've cleared the bit on the
underlying devices,
- * but as it caches it we need to disable and re-enable the volume so mountmgr
receives a PNP
- * notification to refresh its list. */
-
- static const WCHAR prefix[] = L"\\??";
-
- name.Length = name.MaximumLength = boot_vc->pnp_name.Length + sizeof(prefix) -
sizeof(WCHAR);
-
- name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
- if (!name.Buffer)
- ERR("out of memory\n");
- else {
- RtlCopyMemory(name.Buffer, prefix, sizeof(prefix) - sizeof(WCHAR));
- RtlCopyMemory(&name.Buffer[(sizeof(prefix) / sizeof(WCHAR)) - 1],
boot_vc->pnp_name.Buffer, boot_vc->pnp_name.Length);
-
- Status = IoSetDeviceInterfaceState(&name, false);
- if (!NT_SUCCESS(Status))
- ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
-
- Status = IoSetDeviceInterfaceState(&name, true);
- if (!NT_SUCCESS(Status))
- ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
-
- ExFreePool(name.Buffer);
- }
- }
+ ExReleaseResourceLite(&pdo_list_lock);
- if (sr.type == system_root_btrfs || boot_vc)
- check_boot_options();
+ check_boot_options();
// If our FS depends on volumes that aren't there when we do our
IoRegisterPlugPlayNotification calls
// in DriverEntry, bus_query_device_relations won't get called until it's too
late. We need to do our
diff --git a/drivers/filesystems/btrfs/btrfs.c b/drivers/filesystems/btrfs/btrfs.c
index 2f2932f1205..6c821f12534 100644
--- a/drivers/filesystems/btrfs/btrfs.c
+++ b/drivers/filesystems/btrfs/btrfs.c
@@ -667,6 +667,9 @@ static bool lie_about_fs_type() {
INIT_UNICODE_STRING(fsutil, L"FSUTIL.EXE");
INIT_UNICODE_STRING(storsvc, L"STORSVC.DLL");
+ /* Not doing a Volkswagen, honest! Some IFS tests won't run if not recognized FS.
*/
+ INIT_UNICODE_STRING(ifstest, L"IFSTEST.EXE");
+
if (!PsGetCurrentProcess())
return false;
@@ -733,6 +736,15 @@ static bool lie_about_fs_type() {
blacklist = FsRtlAreNamesEqual(&name, &usstorsvc, true, NULL);
}
+ if (!blacklist && entry->FullDllName.Length >= usifstest.Length) {
+ UNICODE_STRING name;
+
+ name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length
- usifstest.Length) / sizeof(WCHAR)];
+ name.Length = name.MaximumLength = usifstest.Length;
+
+ blacklist = FsRtlAreNamesEqual(&name, &usifstest, true, NULL);
+ }
+
if (blacklist) {
void** frames;
ULONG i, num_frames;
@@ -1833,10 +1845,6 @@ void reap_fileref(device_extension* Vcb, file_ref* fr) {
// FIXME - do delete if needed
- ExDeleteResourceLite(&fr->nonpaged->fileref_lock);
-
- ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged);
-
// FIXME - throw error if children not empty
if (fr->fcb->fileref == fr)
@@ -2161,7 +2169,6 @@ void uninit(_In_ device_extension* Vcb) {
ExDeletePagedLookasideList(&Vcb->fcb_lookaside);
ExDeletePagedLookasideList(&Vcb->name_bit_lookaside);
ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside);
- ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside);
ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
ZwClose(Vcb->flush_thread_handle);
@@ -4709,7 +4716,6 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_
PIRP Irp) {
ExInitializePagedLookasideList(&Vcb->fcb_lookaside, NULL, NULL, 0,
sizeof(fcb), ALLOC_TAG, 0);
ExInitializePagedLookasideList(&Vcb->name_bit_lookaside, NULL, NULL, 0,
sizeof(name_bit), ALLOC_TAG, 0);
ExInitializeNPagedLookasideList(&Vcb->range_lock_lookaside, NULL, NULL, 0,
sizeof(range_lock), ALLOC_TAG, 0);
- ExInitializeNPagedLookasideList(&Vcb->fileref_np_lookaside, NULL, NULL, 0,
sizeof(file_ref_nonpaged), ALLOC_TAG, 0);
ExInitializeNPagedLookasideList(&Vcb->fcb_np_lookaside, NULL, NULL, 0,
sizeof(fcb_nonpaged), ALLOC_TAG, 0);
init_lookaside = true;
@@ -5027,7 +5033,6 @@ exit2:
ExDeletePagedLookasideList(&Vcb->fcb_lookaside);
ExDeletePagedLookasideList(&Vcb->name_bit_lookaside);
ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside);
- ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside);
ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
}
@@ -5764,27 +5769,43 @@ exit:
return Status;
}
-bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool stream) {
+NTSTATUS check_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool
stream) {
ULONG i;
if (us->Length < sizeof(WCHAR))
- return false;
+ return STATUS_OBJECT_NAME_INVALID;
if (us->Length > 255 * sizeof(WCHAR))
- return false;
+ return STATUS_OBJECT_NAME_INVALID;
for (i = 0; i < us->Length / sizeof(WCHAR); i++) {
if (us->Buffer[i] == '/' || us->Buffer[i] == 0 ||
(!posix && (us->Buffer[i] == '/' || us->Buffer[i] ==
':')) ||
(!posix && !stream && (us->Buffer[i] == '<' ||
us->Buffer[i] == '>' || us->Buffer[i] == '"' ||
us->Buffer[i] == '|' || us->Buffer[i] == '?' ||
us->Buffer[i] == '*' || (us->Buffer[i] >= 1 && us->Buffer[i]
<= 31))))
- return false;
+ return STATUS_OBJECT_NAME_INVALID;
}
if (us->Buffer[0] == '.' && (us->Length == sizeof(WCHAR) ||
(us->Length == 2 * sizeof(WCHAR) && us->Buffer[1] == '.')))
- return false;
+ return STATUS_OBJECT_NAME_INVALID;
- return true;
+ /* The Linux driver expects filenames with a maximum length of 255 bytes - make sure
+ * that our UTF-8 length won't be longer than that. */
+ if (us->Length >= 85 * sizeof(WCHAR)) {
+ NTSTATUS Status;
+ ULONG utf8len;
+
+ Status = utf16_to_utf8(NULL, 0, &utf8len, us->Buffer, us->Length);
+ if (!NT_SUCCESS(Status))
+ return Status;
+
+ if (utf8len > 255)
+ return STATUS_OBJECT_NAME_INVALID;
+ else if (stream && utf8len > 250) // minus five bytes for
"user."
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ return STATUS_SUCCESS;
}
void chunk_lock_range(_In_ device_extension* Vcb, _In_ chunk* c, _In_ uint64_t start,
_In_ uint64_t length) {
@@ -6519,7 +6540,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_S
IoRegisterFileSystem(DeviceObject);
- IoRegisterBootDriverReinitialization(DriverObject, check_system_root, NULL);
+ check_system_root();
return STATUS_SUCCESS;
}
diff --git a/drivers/filesystems/btrfs/btrfs.inf b/drivers/filesystems/btrfs/btrfs.inf
index ac8ff69dc4d..42a3e97068c 100644
--- a/drivers/filesystems/btrfs/btrfs.inf
+++ b/drivers/filesystems/btrfs/btrfs.inf
@@ -10,7 +10,7 @@ Signature = "$Windows NT$"
Class = Volume
ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f}
Provider = %Me%
-DriverVer = 10/31/2020,1.7.5.0
+DriverVer = 01/14/2021,1.7.6.0
CatalogFile = btrfs.cat
[DestinationDirs]
diff --git a/drivers/filesystems/btrfs/btrfs.rc b/drivers/filesystems/btrfs/btrfs.rc
index e7a7ad6c280..198fcc4e8a9 100644
--- a/drivers/filesystems/btrfs/btrfs.rc
+++ b/drivers/filesystems/btrfs/btrfs.rc
@@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,7,5,0
- PRODUCTVERSION 1,7,5,0
+ FILEVERSION 1,7,6,0
+ PRODUCTVERSION 1,7,6,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "FileDescription", "WinBtrfs"
- VALUE "FileVersion", "1.7.5"
+ VALUE "FileVersion", "1.7.6"
VALUE "InternalName", "btrfs"
- VALUE "LegalCopyright", "Copyright (c) Mark Harmstone
2016-20"
+ VALUE "LegalCopyright", "Copyright (c) Mark Harmstone
2016-21"
VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs"
- VALUE "ProductVersion", "1.7.5"
+ VALUE "ProductVersion", "1.7.6"
END
END
BLOCK "VarFileInfo"
diff --git a/drivers/filesystems/btrfs/btrfs_drv.h
b/drivers/filesystems/btrfs/btrfs_drv.h
index 0e2554adbc3..106332d77c4 100644
--- a/drivers/filesystems/btrfs/btrfs_drv.h
+++ b/drivers/filesystems/btrfs/btrfs_drv.h
@@ -338,10 +338,6 @@ typedef struct _fcb {
LIST_ENTRY list_entry_dirty;
} fcb;
-typedef struct {
- ERESOURCE fileref_lock;
-} file_ref_nonpaged;
-
typedef struct _file_ref {
fcb* fcb;
ANSI_STRING oldutf8;
@@ -350,7 +346,6 @@ typedef struct _file_ref {
bool posix_delete;
bool deleted;
bool created;
- file_ref_nonpaged* nonpaged;
LIST_ENTRY children;
LONG refcount;
LONG open_count;
@@ -832,7 +827,6 @@ typedef struct _device_extension {
PAGED_LOOKASIDE_LIST fcb_lookaside;
PAGED_LOOKASIDE_LIST name_bit_lookaside;
NPAGED_LOOKASIDE_LIST range_lock_lookaside;
- NPAGED_LOOKASIDE_LIST fileref_np_lookaside;
NPAGED_LOOKASIDE_LIST fcb_np_lookaside;
LIST_ENTRY list_entry;
} device_extension;
@@ -1122,7 +1116,7 @@ NTSTATUS create_root(_In_
_Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
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_ bool Override, _Out_opt_ IO_STATUS_BLOCK* iosb);
-bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool stream);
+NTSTATUS check_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool
stream);
void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
ULONG action, _In_opt_ PUNICODE_STRING stream);
void queue_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG
action, _In_opt_ PUNICODE_STRING stream);
@@ -1419,6 +1413,8 @@ NTSTATUS stream_set_end_of_file_information(device_extension* Vcb,
uint16_t end,
NTSTATUS fileref_get_filename(file_ref* fileref, PUNICODE_STRING fn, USHORT* name_offset,
ULONG* preqlen);
void insert_dir_child_into_hash_lists(fcb* fcb, dir_child* dc);
void remove_dir_child_from_hash_lists(fcb* fcb, dir_child* dc);
+void add_fcb_to_subvol(_In_ _Requires_exclusive_lock_held_(_Curr_->Vcb->fcb_lock)
fcb* fcb);
+void remove_fcb_from_subvol(_In_
_Requires_exclusive_lock_held_(_Curr_->Vcb->fcb_lock) fcb* fcb);
// in reparse.c
NTSTATUS get_reparse_point(PFILE_OBJECT FileObject, void* buffer, DWORD buflen,
ULONG_PTR* retlen);
@@ -1626,7 +1622,7 @@ NTSTATUS read_send_buffer(device_extension* Vcb, PFILE_OBJECT
FileObject, void*
NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN
PREPARSE_DATA_BUFFER ReparseBuffer);
// in boot.c
-void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULONG
Count);
+void check_system_root();
void boot_add_device(DEVICE_OBJECT* pdo);
extern BTRFS_UUID boot_uuid;
diff --git a/drivers/filesystems/btrfs/create.c b/drivers/filesystems/btrfs/create.c
index 25b0b975e53..e678a096167 100644
--- a/drivers/filesystems/btrfs/create.c
+++ b/drivers/filesystems/btrfs/create.c
@@ -80,6 +80,12 @@ static const GUID GUID_ECP_ATOMIC_CREATE = { 0x4720bd83, 0x52ac,
0x4104, { 0xa1,
static const GUID GUID_ECP_QUERY_ON_CREATE = { 0x1aca62e9, 0xabb4, 0x4ff2, { 0xbb, 0x5c,
0x1c, 0x79, 0x02, 0x5e, 0x41, 0x7f } };
static const GUID GUID_ECP_CREATE_REDIRECTION = { 0x188d6bd6, 0xa126, 0x4fa8, { 0xbd,
0xf2, 0x1c, 0xcd, 0xf8, 0x96, 0xf3, 0xe0 } };
+typedef struct {
+ device_extension* Vcb;
+ ACCESS_MASK granted_access;
+ file_ref* fileref;
+} oplock_context;
+
fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) {
fcb* fcb;
@@ -160,13 +166,6 @@ file_ref* create_fileref(device_extension* Vcb) {
RtlZeroMemory(fr, sizeof(file_ref));
- fr->nonpaged =
ExAllocateFromNPagedLookasideList(&Vcb->fileref_np_lookaside);
- if (!fr->nonpaged) {
- ERR("out of memory\n");
- ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr);
- return NULL;
- }
-
fr->refcount = 1;
#ifdef DEBUG_FCB_REFCOUNTS
@@ -175,8 +174,6 @@ file_ref* create_fileref(device_extension* Vcb) {
InitializeListHead(&fr->children);
- ExInitializeResourceLite(&fr->nonpaged->fileref_lock);
-
return fr;
}
@@ -1596,7 +1593,7 @@ NTSTATUS
open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
if (duff_fr)
- reap_fileref(Vcb, duff_fr);
+ ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, duff_fr);
} else {
root* subvol;
uint64_t inode;
@@ -1652,9 +1649,6 @@ NTSTATUS
open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
sf2->fcb = fcb;
- if (dc->type == BTRFS_TYPE_DIRECTORY)
- fcb->fileref = sf2;
-
ExAcquireResourceExclusiveLite(&sf->fcb->nonpaged->dir_children_lock, true);
if (!dc->fileref) {
@@ -1663,6 +1657,9 @@ NTSTATUS
open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
dc->fileref = sf2;
InsertTailList(&sf->children, &sf2->list_entry);
increase_fileref_refcount(sf);
+
+ if (dc->type == BTRFS_TYPE_DIRECTORY)
+ fcb->fileref = sf2;
} else {
duff_fr = sf2;
sf2 = dc->fileref;
@@ -2654,9 +2651,6 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
#ifdef DEBUG_FCB_REFCOUNTS
LONG rc;
#endif
-#ifdef __REACTOS__
- LIST_ENTRY* le;
-#endif
TRACE("fpus = %.*S\n", (int)(fpus->Length / sizeof(WCHAR)),
fpus->Buffer);
TRACE("stream = %.*S\n", (int)(stream->Length / sizeof(WCHAR)),
stream->Buffer);
@@ -2671,8 +2665,9 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
UNICODE_STRING fpus2;
- if (!is_file_name_valid(fpus, false, true))
- return STATUS_OBJECT_NAME_INVALID;
+ Status = check_file_name_valid(fpus, false, true);
+ if (!NT_SUCCESS(Status))
+ return Status;
fpus2.Length = fpus2.MaximumLength = fpus->Length;
fpus2.Buffer = ExAllocatePoolWithTag(pool_type, fpus2.MaximumLength, ALLOC_TAG);
@@ -2775,6 +2770,7 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
#endif
fcb->subvol = parfileref->fcb->subvol;
fcb->inode = parfileref->fcb->inode;
+ fcb->hash = parfileref->fcb->hash;
fcb->type = parfileref->fcb->type;
fcb->ads = true;
@@ -2913,11 +2909,7 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock,
true);
-#ifndef __REACTOS__
LIST_ENTRY* le = parfileref->fcb->dir_children_index.Flink;
-#else
- le = parfileref->fcb->dir_children_index.Flink;
-#endif
while (le != &parfileref->fcb->dir_children_index) {
dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_index);
@@ -3143,10 +3135,9 @@ static NTSTATUS file_create(PIRP Irp,
_Requires_lock_held_(_Curr_->tree_lock) _R
} else {
ACCESS_MASK granted_access;
- if (!is_file_name_valid(&fpus, false, false)) {
- Status = STATUS_OBJECT_NAME_INVALID;
+ Status = check_file_name_valid(&fpus, false, false);
+ if (!NT_SUCCESS(Status))
goto end;
- }
SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
@@ -3581,168 +3572,18 @@ end:
fcb->csum_loaded = true;
}
-static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, POOL_TYPE
pool_type, file_ref* fileref, ACCESS_MASK* granted_access,
- PFILE_OBJECT FileObject, UNICODE_STRING* fn, ULONG options,
PIRP Irp, LIST_ENTRY* rollback) {
+static NTSTATUS open_file3(device_extension* Vcb, PIRP Irp, ACCESS_MASK granted_access,
file_ref* fileref, LIST_ENTRY* rollback) {
NTSTATUS Status;
- file_ref* sf;
- bool readonly;
- ccb* ccb;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ ULONG options = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
+ ULONG RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) &
0xff);
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool :
PagedPool;
+ ccb* ccb;
- if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE
|| RequestedDisposition == FILE_OVERWRITE_IF) {
- LARGE_INTEGER zero;
-
- if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY ||
is_subvol_readonly(fileref->fcb->subvol, Irp)) {
- Status = STATUS_ACCESS_DENIED;
- goto end;
- }
-
- if (Vcb->readonly) {
- Status = STATUS_MEDIA_WRITE_PROTECTED;
- goto end;
- }
-
- zero.QuadPart = 0;
- if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object,
&zero)) {
- Status = STATUS_USER_MAPPED_FILE;
- goto end;
- }
- }
-
- if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess != 0) {
-
SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
-
- if (!SeAccessCheck((fileref->fcb->ads || fileref->fcb ==
Vcb->dummy_fcb) ? fileref->parent->fcb->sd : fileref->fcb->sd,
-
&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
- true,
IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 0, NULL,
- IoGetFileObjectGenericMapping(), IrpSp->Flags &
SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
- granted_access, &Status)) {
-
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
- TRACE("SeAccessCheck failed, returning %08lx\n", Status);
- goto end;
- }
-
-
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
- } else
- *granted_access = 0;
-
- TRACE("deleted = %s\n", fileref->deleted ? "true" :
"false");
-
- sf = fileref;
- while (sf) {
- if (sf->delete_on_close) {
- TRACE("could not open as deletion pending\n");
- Status = STATUS_DELETE_PENDING;
- goto end;
- }
- sf = sf->parent;
- }
-
- readonly = (!fileref->fcb->ads && fileref->fcb->atts &
FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE))
||
- (fileref->fcb->ads && fileref->parent->fcb->atts
& FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags &
SL_IGNORE_READONLY_ATTRIBUTE)) ||
- is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb ==
Vcb->dummy_fcb || Vcb->readonly;
-
- if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref ||
readonly)) {
- Status = STATUS_CANNOT_DELETE;
- goto end;
- }
-
- if (readonly) {
- ACCESS_MASK allowed;
-
- allowed = READ_CONTROL | SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | FILE_READ_DATA |
- FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE |
FILE_LIST_DIRECTORY |
- FILE_TRAVERSE;
-
- if (!Vcb->readonly && (fileref->fcb == Vcb->dummy_fcb ||
fileref->fcb->inode == SUBVOL_ROOT_INODE))
- allowed |= DELETE;
-
- if (fileref->fcb != Vcb->dummy_fcb &&
!is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
- allowed |= DELETE | WRITE_OWNER | WRITE_DAC | FILE_WRITE_EA |
FILE_WRITE_ATTRIBUTES;
-
- if (!fileref->fcb->ads && fileref->fcb->type ==
BTRFS_TYPE_DIRECTORY)
- allowed |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_DELETE_CHILD;
- } else if (fileref->fcb->inode == SUBVOL_ROOT_INODE &&
is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
- // We allow a subvolume root to be opened read-write even if its readonly
flag is set, so it can be cleared
-
- allowed |= FILE_WRITE_ATTRIBUTES;
- }
-
- if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess &
MAXIMUM_ALLOWED) {
- *granted_access &= allowed;
-
IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess
&= allowed;
- } else if (*granted_access & ~allowed) {
- Status = Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED :
STATUS_ACCESS_DENIED;
- goto end;
- }
- }
-
- if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts &
FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT)) {
- REPARSE_DATA_BUFFER* data;
-
- /* How reparse points work from the point of view of the filesystem appears to
- * undocumented. When returning STATUS_REPARSE, MSDN encourages us to return
- * IO_REPARSE in Irp->IoStatus.Information, but that means we have to do
our own
- * translation. If we instead return the reparse tag in Information, and
store
- * a pointer to the reparse data buffer in
Irp->Tail.Overlay.AuxiliaryBuffer,
- * IopSymlinkProcessReparse will do the translation for us. */
-
- Status = get_reparse_block(fileref->fcb, (uint8_t**)&data);
- if (!NT_SUCCESS(Status)) {
- ERR("get_reparse_block returned %08lx\n", Status);
- Status = STATUS_SUCCESS;
- } else {
- Irp->IoStatus.Information = data->ReparseTag;
-
- if (fn->Buffer[(fn->Length / sizeof(WCHAR)) - 1] == '\\')
- data->Reserved = sizeof(WCHAR);
-
- Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
-
- Status = STATUS_REPARSE;
- goto end;
- }
- }
-
- if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY &&
!fileref->fcb->ads) {
- if (options & FILE_NON_DIRECTORY_FILE && !(fileref->fcb->atts
& FILE_ATTRIBUTE_REPARSE_POINT)) {
- Status = STATUS_FILE_IS_A_DIRECTORY;
- goto end;
- }
- } else if (options & FILE_DIRECTORY_FILE) {
- TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u)\n",
fileref->fcb->type);
- Status = STATUS_NOT_A_DIRECTORY;
- goto end;
- }
-
- if (fileref->open_count > 0) {
- Status = IoCheckShareAccess(*granted_access,
IrpSp->Parameters.Create.ShareAccess, FileObject,
&fileref->fcb->share_access, false);
-
- if (!NT_SUCCESS(Status)) {
- if (Status == STATUS_SHARING_VIOLATION)
- TRACE("IoCheckShareAccess failed, returning %08lx\n", Status);
- else
- WARN("IoCheckShareAccess failed, returning %08lx\n", Status);
-
- goto end;
- }
-
- IoUpdateShareAccess(FileObject, &fileref->fcb->share_access);
- } else
- IoSetShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess,
FileObject, &fileref->fcb->share_access);
-
- if (*granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) {
- if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object,
MmFlushForWrite)) {
- Status = (options & FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE :
STATUS_SHARING_VIOLATION;
- goto end2;
- }
- }
-
- // FIXME - this can block waiting for network IO, while we're holding
fileref_lock and tree_lock
- Status = FsRtlCheckOplock(fcb_oplock(fileref->fcb), Irp, NULL, NULL, NULL);
- if (!NT_SUCCESS(Status)) {
- WARN("FsRtlCheckOplock returned %08lx\n", Status);
- goto end2;
+ if (granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) {
+ if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object,
MmFlushForWrite))
+ return (options & FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE :
STATUS_SHARING_VIOLATION;
}
if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition ==
FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) {
@@ -3750,28 +3591,20 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
LARGE_INTEGER time;
BTRFS_TIME now;
- if ((RequestedDisposition == FILE_OVERWRITE || RequestedDisposition ==
FILE_OVERWRITE_IF) && readonly) {
- WARN("cannot overwrite readonly file\n");
- Status = STATUS_ACCESS_DENIED;
- goto end2;
- }
-
- if (!fileref->fcb->ads &&
(IrpSp->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_HIDDEN |
FILE_ATTRIBUTE_SYSTEM)) != ((fileref->fcb->atts & (FILE_ATTRIBUTE_SYSTEM |
FILE_ATTRIBUTE_HIDDEN)))) {
- Status = STATUS_ACCESS_DENIED;
- goto end2;
- }
+ if (!fileref->fcb->ads &&
(IrpSp->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_HIDDEN |
FILE_ATTRIBUTE_SYSTEM)) != ((fileref->fcb->atts & (FILE_ATTRIBUTE_SYSTEM |
FILE_ATTRIBUTE_HIDDEN))))
+ return STATUS_ACCESS_DENIED;
if (fileref->fcb->ads) {
Status = stream_set_end_of_file_information(Vcb, 0, fileref->fcb, fileref,
false);
if (!NT_SUCCESS(Status)) {
ERR("stream_set_end_of_file_information returned %08lx\n",
Status);
- goto end2;
+ return Status;
}
} else {
Status = truncate_file(fileref->fcb, 0, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("truncate_file returned %08lx\n", Status);
- goto end2;
+ return Status;
}
}
@@ -3780,7 +3613,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
if (!NT_SUCCESS(Status)) {
ERR("extend_file returned %08lx\n", Status);
- goto end2;
+ return Status;
}
}
@@ -3794,7 +3627,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer,
IrpSp->Parameters.Create.EaLength, &offset);
if (!NT_SUCCESS(Status)) {
ERR("IoCheckEaBufferValidity returned %08lx (error at offset
%lu)\n", Status, offset);
- goto end2;
+ return Status;
}
fileref->fcb->ealen = 4;
@@ -3823,8 +3656,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
fileref->fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(pool_type,
IrpSp->Parameters.Create.EaLength, ALLOC_TAG);
if (!fileref->fcb->ea_xattr.Buffer) {
ERR("out of memory\n");
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto end2;
+ return STATUS_INSUFFICIENT_RESOURCES;
}
fileref->fcb->ea_xattr.Length =
fileref->fcb->ea_xattr.MaximumLength =
(USHORT)IrpSp->Parameters.Create.EaLength;
@@ -3861,7 +3693,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
Status = delete_fileref(dc->fileref, NULL, false, NULL,
rollback);
if (!NT_SUCCESS(Status)) {
ERR("delete_fileref returned %08lx\n", Status);
- goto end2;
+ return Status;
}
}
} else
@@ -3917,8 +3749,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
if (ffei->Flags & FILE_NEED_EA) {
WARN("returning STATUS_ACCESS_DENIED as no EA
knowledge\n");
- Status = STATUS_ACCESS_DENIED;
- goto end2;
+ return STATUS_ACCESS_DENIED;
}
if (ffei->NextEntryOffset == 0)
@@ -3935,8 +3766,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
if (!ccb) {
ERR("out of memory\n");
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto end2;
+ return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(ccb, sizeof(*ccb));
@@ -3949,7 +3779,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
RtlInitUnicodeString(&ccb->query_string, NULL);
ccb->has_wildcard = false;
ccb->specific_file = false;
- ccb->access = *granted_access;
+ ccb->access = granted_access;
ccb->case_sensitive = IrpSp->Flags & SL_CASE_SENSITIVE;
ccb->reserving = false;
ccb->lxss = called_from_lxss();
@@ -4014,9 +3844,264 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
#endif
InterlockedIncrement(&Vcb->open_files);
- Status = STATUS_SUCCESS;
+ return STATUS_SUCCESS;
+}
+
+static void oplock_complete(PVOID Context, PIRP Irp) {
+ NTSTATUS Status;
+ LIST_ENTRY rollback;
+ bool skip_lock;
+ oplock_context* ctx = Context;
+ device_extension* Vcb = ctx->Vcb;
+
+ TRACE("(%p, %p)\n", Context, Irp);
+
+ InitializeListHead(&rollback);
+
+ skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock);
+
+ if (!skip_lock)
+ ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
+
+ ExAcquireResourceSharedLite(&Vcb->fileref_lock, true);
+
+ // FIXME - trans
+ Status = open_file3(Vcb, Irp, ctx->granted_access, ctx->fileref,
&rollback);
+
+ if (!NT_SUCCESS(Status)) {
+ free_fileref(ctx->fileref);
+ do_rollback(ctx->Vcb, &rollback);
+ } else
+ clear_rollback(&rollback);
+
+ ExReleaseResourceLite(&Vcb->fileref_lock);
+
+ if (Status == STATUS_SUCCESS) {
+ fcb* fcb2;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ bool skip_fcb_lock;
+
+
IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess |=
ctx->granted_access;
+
IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess
&= ~(ctx->granted_access | MAXIMUM_ALLOWED);
+
+ if (!FileObject->Vpb)
+ FileObject->Vpb = Vcb->devobj->Vpb;
+
+ fcb2 = FileObject->FsContext;
+
+ if (fcb2->ads) {
+ struct _ccb* ccb2 = FileObject->FsContext2;
+
+ fcb2 = ccb2->fileref->parent->fcb;
+ }
+
+ skip_fcb_lock = ExIsResourceAcquiredExclusiveLite(fcb2->Header.Resource);
+
+ if (!skip_fcb_lock)
+ ExAcquireResourceExclusiveLite(fcb2->Header.Resource, true);
+
+ fcb_load_csums(Vcb, fcb2, Irp);
+
+ if (!skip_fcb_lock)
+ ExReleaseResourceLite(fcb2->Header.Resource);
+ }
+
+ if (!skip_lock)
+ ExReleaseResourceLite(&Vcb->tree_lock);
+
+ // FIXME - call free_trans if failed and within transaction
+
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest(Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
+
+ ExFreePool(ctx);
+}
+
+static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, file_ref*
fileref, ACCESS_MASK* granted_access,
+ PFILE_OBJECT FileObject, UNICODE_STRING* fn, ULONG options,
PIRP Irp, LIST_ENTRY* rollback) {
+ NTSTATUS Status;
+ file_ref* sf;
+ bool readonly;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE
|| RequestedDisposition == FILE_OVERWRITE_IF) {
+ LARGE_INTEGER zero;
+
+ if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY ||
is_subvol_readonly(fileref->fcb->subvol, Irp)) {
+ Status = STATUS_ACCESS_DENIED;
+ goto end;
+ }
+
+ if (Vcb->readonly) {
+ Status = STATUS_MEDIA_WRITE_PROTECTED;
+ goto end;
+ }
+
+ zero.QuadPart = 0;
+ if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object,
&zero)) {
+ Status = STATUS_USER_MAPPED_FILE;
+ goto end;
+ }
+ }
+
+ if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess != 0) {
+
SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
+
+ if (!SeAccessCheck((fileref->fcb->ads || fileref->fcb ==
Vcb->dummy_fcb) ? fileref->parent->fcb->sd : fileref->fcb->sd,
+
&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
+ true,
IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 0, NULL,
+ IoGetFileObjectGenericMapping(), IrpSp->Flags &
SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
+ granted_access, &Status)) {
+
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
+ TRACE("SeAccessCheck failed, returning %08lx\n", Status);
+ goto end;
+ }
+
+
SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
+ } else
+ *granted_access = 0;
+
+ TRACE("deleted = %s\n", fileref->deleted ? "true" :
"false");
+
+ sf = fileref;
+ while (sf) {
+ if (sf->delete_on_close) {
+ TRACE("could not open as deletion pending\n");
+ Status = STATUS_DELETE_PENDING;
+ goto end;
+ }
+ sf = sf->parent;
+ }
+
+ readonly = (!fileref->fcb->ads && fileref->fcb->atts &
FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE))
||
+ (fileref->fcb->ads && fileref->parent->fcb->atts
& FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags &
SL_IGNORE_READONLY_ATTRIBUTE)) ||
+ is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb ==
Vcb->dummy_fcb || Vcb->readonly;
+
+ if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref ||
readonly)) {
+ Status = STATUS_CANNOT_DELETE;
+ goto end;
+ }
+
+ if (readonly) {
+ ACCESS_MASK allowed;
+
+ allowed = READ_CONTROL | SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | FILE_READ_DATA |
+ FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE |
FILE_LIST_DIRECTORY |
+ FILE_TRAVERSE;
+
+ if (!Vcb->readonly && (fileref->fcb == Vcb->dummy_fcb ||
fileref->fcb->inode == SUBVOL_ROOT_INODE))
+ allowed |= DELETE;
+
+ if (fileref->fcb != Vcb->dummy_fcb &&
!is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
+ allowed |= DELETE | WRITE_OWNER | WRITE_DAC | FILE_WRITE_EA |
FILE_WRITE_ATTRIBUTES;
+
+ if (!fileref->fcb->ads && fileref->fcb->type ==
BTRFS_TYPE_DIRECTORY)
+ allowed |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_DELETE_CHILD;
+ } else if (fileref->fcb->inode == SUBVOL_ROOT_INODE &&
is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
+ // We allow a subvolume root to be opened read-write even if its readonly
flag is set, so it can be cleared
+
+ allowed |= FILE_WRITE_ATTRIBUTES;
+ }
+
+ if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess &
MAXIMUM_ALLOWED) {
+ *granted_access &= allowed;
+
IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess
&= allowed;
+ } else if (*granted_access & ~allowed) {
+ Status = Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED :
STATUS_ACCESS_DENIED;
+ goto end;
+ }
+
+ if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition ==
FILE_OVERWRITE_IF) {
+ WARN("cannot overwrite readonly file\n");
+ Status = STATUS_ACCESS_DENIED;
+ goto end;
+ }
+ }
+
+ if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts &
FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT)) {
+ REPARSE_DATA_BUFFER* data;
+
+ /* How reparse points work from the point of view of the filesystem appears to
+ * undocumented. When returning STATUS_REPARSE, MSDN encourages us to return
+ * IO_REPARSE in Irp->IoStatus.Information, but that means we have to do
our own
+ * translation. If we instead return the reparse tag in Information, and
store
+ * a pointer to the reparse data buffer in
Irp->Tail.Overlay.AuxiliaryBuffer,
+ * IopSymlinkProcessReparse will do the translation for us. */
+
+ Status = get_reparse_block(fileref->fcb, (uint8_t**)&data);
+ if (!NT_SUCCESS(Status)) {
+ ERR("get_reparse_block returned %08lx\n", Status);
+ Status = STATUS_SUCCESS;
+ } else {
+ Irp->IoStatus.Information = data->ReparseTag;
+
+ if (fn->Buffer[(fn->Length / sizeof(WCHAR)) - 1] == '\\')
+ data->Reserved = sizeof(WCHAR);
+
+ Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
+
+ Status = STATUS_REPARSE;
+ goto end;
+ }
+ }
+
+ if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY &&
!fileref->fcb->ads) {
+ if (options & FILE_NON_DIRECTORY_FILE && !(fileref->fcb->atts
& FILE_ATTRIBUTE_REPARSE_POINT)) {
+ Status = STATUS_FILE_IS_A_DIRECTORY;
+ goto end;
+ }
+ } else if (options & FILE_DIRECTORY_FILE) {
+ TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u)\n",
fileref->fcb->type);
+ Status = STATUS_NOT_A_DIRECTORY;
+ goto end;
+ }
+
+ if (fileref->open_count > 0) {
+ oplock_context* ctx;
+
+ Status = IoCheckShareAccess(*granted_access,
IrpSp->Parameters.Create.ShareAccess, FileObject,
&fileref->fcb->share_access, false);
+
+ if (!NT_SUCCESS(Status)) {
+ if (Status == STATUS_SHARING_VIOLATION)
+ TRACE("IoCheckShareAccess failed, returning %08lx\n", Status);
+ else
+ WARN("IoCheckShareAccess failed, returning %08lx\n", Status);
+
+ goto end;
+ }
+
+ ctx = ExAllocatePoolWithTag(NonPagedPool, sizeof(oplock_context), ALLOC_TAG);
+ if (!ctx) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto end;
+ }
+
+ ctx->Vcb = Vcb;
+ ctx->granted_access = *granted_access;
+ ctx->fileref = fileref;
+#ifdef __REACTOS__
+ Status = FsRtlCheckOplock(fcb_oplock(fileref->fcb), Irp, ctx,
(POPLOCK_WAIT_COMPLETE_ROUTINE) oplock_complete, NULL);
+#else
+ Status = FsRtlCheckOplock(fcb_oplock(fileref->fcb), Irp, ctx, oplock_complete,
NULL);
+#endif /* __REACTOS__ */
+ if (Status == STATUS_PENDING)
+ return Status;
+
+ ExFreePool(ctx);
+
+ if (!NT_SUCCESS(Status)) {
+ WARN("FsRtlCheckOplock returned %08lx\n", Status);
+ goto end;
+ }
+
+ IoUpdateShareAccess(FileObject, &fileref->fcb->share_access);
+ } else
+ IoSetShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess,
FileObject, &fileref->fcb->share_access);
+
+ Status = open_file3(Vcb, Irp, *granted_access, fileref, rollback);
-end2:
if (!NT_SUCCESS(Status))
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
@@ -4106,9 +4191,6 @@ NTSTATUS
open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
if (tp.item->key.obj_id == fcb->inode) {
if (tp.item->key.obj_type == TYPE_INODE_REF) {
INODE_REF* ir = (INODE_REF*)tp.item->data;
-#ifdef __REACTOS__
- ULONG stringlen;
-#endif
if (tp.item->size < offsetof(INODE_REF, name[0]) ||
tp.item->size < offsetof(INODE_REF, name[0]) + ir->n) {
ERR("INODE_REF was too short\n");
@@ -4116,9 +4198,7 @@ NTSTATUS
open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
return STATUS_INTERNAL_ERROR;
}
-#ifndef __REACTOS__
ULONG stringlen;
-#endif
Status = utf8_to_utf16(NULL, 0, &stringlen, ir->name,
ir->n);
if (!NT_SUCCESS(Status)) {
@@ -4156,9 +4236,6 @@ NTSTATUS
open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
break;
} else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
INODE_EXTREF* ier = (INODE_EXTREF*)tp.item->data;
-#ifdef __REACTOS__
- ULONG stringlen;
-#endif
if (tp.item->size < offsetof(INODE_EXTREF, name[0]) ||
tp.item->size < offsetof(INODE_EXTREF, name[0]) + ier->n) {
ERR("INODE_EXTREF was too short\n");
@@ -4166,9 +4243,7 @@ NTSTATUS
open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
return STATUS_INTERNAL_ERROR;
}
-#ifndef __REACTOS__
ULONG stringlen;
-#endif
Status = utf8_to_utf16(NULL, 0, &stringlen, ier->name,
ier->n);
if (!NT_SUCCESS(Status)) {
@@ -4601,11 +4676,9 @@ loaded:
goto exit;
}
- if (NT_SUCCESS(Status)) { // file already exists
- Status = open_file2(Vcb, RequestedDisposition, pool_type, fileref,
&granted_access, FileObject, &fn, options, Irp, rollback);
- if (!NT_SUCCESS(Status))
- goto exit;
- } else {
+ if (NT_SUCCESS(Status)) // file already exists
+ Status = open_file2(Vcb, RequestedDisposition, fileref, &granted_access,
FileObject, &fn, options, Irp, rollback);
+ else {
file_ref* existing_file = NULL;
Status = file_create(Irp, Vcb, FileObject, related, loaded_related, &fn,
RequestedDisposition, options, &existing_file, rollback);
@@ -4613,9 +4686,7 @@ loaded:
if (Status == STATUS_OBJECT_NAME_COLLISION) { // already exists
fileref = existing_file;
- Status = open_file2(Vcb, RequestedDisposition, pool_type, fileref,
&granted_access, FileObject, &fn, options, Irp, rollback);
- if (!NT_SUCCESS(Status))
- goto exit;
+ Status = open_file2(Vcb, RequestedDisposition, fileref, &granted_access,
FileObject, &fn, options, Irp, rollback);
} else {
Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0;
granted_access =
IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
@@ -4928,7 +4999,11 @@ NTSTATUS __stdcall drv_create(IN PDEVICE_OBJECT DeviceObject, IN
PIRP Irp) {
exit:
Irp->IoStatus.Status = Status;
- IoCompleteRequest( Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT );
+
+ if (Status == STATUS_PENDING)
+ IoMarkIrpPending(Irp);
+ else
+ IoCompleteRequest(Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT :
IO_NO_INCREMENT);
TRACE("create returning %08lx\n", Status);
diff --git a/drivers/filesystems/btrfs/fastio.c b/drivers/filesystems/btrfs/fastio.c
index e073f3f9b1d..2c768895f8d 100644
--- a/drivers/filesystems/btrfs/fastio.c
+++ b/drivers/filesystems/btrfs/fastio.c
@@ -499,6 +499,50 @@ static BOOLEAN __stdcall fast_io_unlock_all_by_key(PFILE_OBJECT
FileObject, PVOI
return true;
}
+#ifdef __REACTOS__
+_Function_class_(FAST_IO_ACQUIRE_FILE)
+static void __stdcall fast_io_acquire_for_create_section(_In_ PFILE_OBJECT FileObject) {
+#else
+static void fast_io_acquire_for_create_section(_In_ PFILE_OBJECT FileObject) {
+#endif /* __REACTOS__ */
+ fcb* fcb;
+
+ TRACE("(%p)\n", FileObject);
+
+ if (!FileObject)
+ return;
+
+ fcb = FileObject->FsContext;
+
+ if (!fcb)
+ return;
+
+ ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
+ ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
+}
+
+#ifdef __REACTOS__
+_Function_class_(FAST_IO_RELEASE_FILE)
+static void __stdcall fast_io_release_for_create_section(_In_ PFILE_OBJECT FileObject) {
+#else
+static void fast_io_release_for_create_section(_In_ PFILE_OBJECT FileObject) {
+#endif /* __REACTOS__ */
+ fcb* fcb;
+
+ TRACE("(%p)\n", FileObject);
+
+ if (!FileObject)
+ return;
+
+ fcb = FileObject->FsContext;
+
+ if (!fcb)
+ return;
+
+ ExReleaseResourceLite(fcb->Header.Resource);
+ ExReleaseResourceLite(&fcb->Vcb->tree_lock);
+}
+
void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
RtlZeroMemory(&FastIoDispatch, sizeof(FastIoDispatch));
@@ -513,6 +557,8 @@ void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
FastIoDispatch.FastIoUnlockSingle = fast_io_unlock_single;
FastIoDispatch.FastIoUnlockAll = fast_io_unlock_all;
FastIoDispatch.FastIoUnlockAllByKey = fast_io_unlock_all_by_key;
+ FastIoDispatch.AcquireFileForNtCreateSection = fast_io_acquire_for_create_section;
+ FastIoDispatch.ReleaseFileForNtCreateSection = fast_io_release_for_create_section;
FastIoDispatch.FastIoQueryNetworkOpenInfo = fast_io_query_network_open_info;
FastIoDispatch.AcquireForModWrite = fast_io_acquire_for_mod_write;
FastIoDispatch.MdlRead = FsRtlMdlReadDev;
diff --git a/drivers/filesystems/btrfs/fileinfo.c b/drivers/filesystems/btrfs/fileinfo.c
index 4bebfda1904..df8652823e7 100644
--- a/drivers/filesystems/btrfs/fileinfo.c
+++ b/drivers/filesystems/btrfs/fileinfo.c
@@ -801,6 +801,7 @@ static NTSTATUS create_directory_fcb(device_extension* Vcb, root* r,
fcb* parfcb
fcb->subvol = r;
fcb->inode = InterlockedIncrement64(&r->lastinode);
+ fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&fcb->inode,
sizeof(uint64_t));
fcb->type = BTRFS_TYPE_DIRECTORY;
fcb->inode_item.generation = Vcb->superblock.generation;
@@ -872,7 +873,7 @@ static NTSTATUS create_directory_fcb(device_extension* Vcb, root* r,
fcb* parfcb
RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
acquire_fcb_lock_exclusive(Vcb);
- InsertTailList(&r->fcbs, &fcb->list_entry);
+ add_fcb_to_subvol(fcb);
InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
r->fcbs_version++;
release_fcb_lock(Vcb);
@@ -884,6 +885,68 @@ static NTSTATUS create_directory_fcb(device_extension* Vcb, root* r,
fcb* parfcb
return STATUS_SUCCESS;
}
+void add_fcb_to_subvol(_In_ _Requires_exclusive_lock_held_(_Curr_->Vcb->fcb_lock)
fcb* fcb) {
+ LIST_ENTRY* lastle = NULL;
+ uint32_t hash = fcb->hash;
+
+ if (fcb->subvol->fcbs_ptrs[hash >> 24]) {
+ LIST_ENTRY* le = fcb->subvol->fcbs_ptrs[hash >> 24];
+
+ while (le != &fcb->subvol->fcbs) {
+ struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
+
+ if (fcb2->hash > hash) {
+ lastle = le->Blink;
+ break;
+ }
+
+ le = le->Flink;
+ }
+ }
+
+ if (!lastle) {
+ uint8_t c = hash >> 24;
+
+ if (c != 0xff) {
+ uint8_t d = c + 1;
+
+ do {
+ if (fcb->subvol->fcbs_ptrs[d]) {
+ lastle = fcb->subvol->fcbs_ptrs[d]->Blink;
+ break;
+ }
+
+ d++;
+ } while (d != 0);
+ }
+ }
+
+ if (lastle) {
+ InsertHeadList(lastle, &fcb->list_entry);
+
+ if (lastle == &fcb->subvol->fcbs || (CONTAINING_RECORD(lastle, struct
_fcb, list_entry)->hash >> 24) != (hash >> 24))
+ fcb->subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
+ } else {
+ InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry);
+
+ if (fcb->list_entry.Blink == &fcb->subvol->fcbs ||
(CONTAINING_RECORD(fcb->list_entry.Blink, struct _fcb, list_entry)->hash >>
24) != (hash >> 24))
+ fcb->subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
+ }
+}
+
+void remove_fcb_from_subvol(_In_
_Requires_exclusive_lock_held_(_Curr_->Vcb->fcb_lock) fcb* fcb) {
+ uint8_t c = fcb->hash >> 24;
+
+ if (fcb->subvol->fcbs_ptrs[c] == &fcb->list_entry) {
+ if (fcb->list_entry.Flink != &fcb->subvol->fcbs &&
(CONTAINING_RECORD(fcb->list_entry.Flink, struct _fcb, list_entry)->hash >>
24) == c)
+ fcb->subvol->fcbs_ptrs[c] = fcb->list_entry.Flink;
+ else
+ fcb->subvol->fcbs_ptrs[c] = NULL;
+ }
+
+ RemoveEntryList(&fcb->list_entry);
+}
+
static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_ref* destdir,
PANSI_STRING utf8, PUNICODE_STRING fnus, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status;
LIST_ENTRY move_list, *le;
@@ -930,6 +993,7 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb,
file_ref* destd
if (!NT_SUCCESS(Status)) {
ERR("add_children_to_move_list returned %08lx\n", Status);
+ ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
goto end;
}
}
@@ -950,8 +1014,6 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb,
file_ref* destd
if (me->fileref->fcb->inode != SUBVOL_ROOT_INODE &&
me->fileref->fcb != fileref->fcb->Vcb->dummy_fcb) {
if (!me->dummyfcb) {
ULONG defda;
- bool inserted = false;
- LIST_ENTRY* le3;
ExAcquireResourceExclusiveLite(me->fileref->fcb->Header.Resource, true);
@@ -964,6 +1026,7 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb,
file_ref* destd
me->dummyfcb->subvol = me->fileref->fcb->subvol;
me->dummyfcb->inode = me->fileref->fcb->inode;
+ me->dummyfcb->hash = me->fileref->fcb->hash;
if (!me->dummyfcb->ads) {
me->dummyfcb->sd_dirty = me->fileref->fcb->sd_dirty;
@@ -983,6 +1046,7 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb,
file_ref* destd
me->fileref->fcb->subvol = destdir->fcb->subvol;
me->fileref->fcb->inode =
InterlockedIncrement64(&destdir->fcb->subvol->lastinode);
+ me->fileref->fcb->hash = calc_crc32c(0xffffffff,
(uint8_t*)&me->fileref->fcb->inode, sizeof(uint64_t));
me->fileref->fcb->inode_item.st_nlink = 1;
defda = get_file_attributes(me->fileref->fcb->Vcb,
me->fileref->fcb->subvol, me->fileref->fcb->inode,
@@ -1042,31 +1106,20 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb,
file_ref* destd
le2 = le2->Flink;
}
+
+ add_fcb_to_subvol(me->dummyfcb);
+ remove_fcb_from_subvol(me->fileref->fcb);
+ add_fcb_to_subvol(me->fileref->fcb);
} else {
me->fileref->fcb->subvol =
me->parent->fileref->fcb->subvol;
me->fileref->fcb->inode =
me->parent->fileref->fcb->inode;
- }
-
- me->fileref->fcb->created = true;
-
- InsertHeadList(&me->fileref->fcb->list_entry,
&me->dummyfcb->list_entry);
- RemoveEntryList(&me->fileref->fcb->list_entry);
-
- le3 = destdir->fcb->subvol->fcbs.Flink;
- while (le3 != &destdir->fcb->subvol->fcbs) {
- fcb* fcb = CONTAINING_RECORD(le3, struct _fcb, list_entry);
-
- if (fcb->inode > me->fileref->fcb->inode) {
- InsertHeadList(le3->Blink,
&me->fileref->fcb->list_entry);
- inserted = true;
- break;
- }
+ me->fileref->fcb->hash =
me->parent->fileref->fcb->hash;
- le3 = le3->Flink;
+ // put stream after parent in FCB list
+ InsertHeadList(&me->parent->fileref->fcb->list_entry,
&me->fileref->fcb->list_entry);
}
- if (!inserted)
- InsertTailList(&destdir->fcb->subvol->fcbs,
&me->fileref->fcb->list_entry);
+ me->fileref->fcb->created = true;
InsertTailList(&me->fileref->fcb->Vcb->all_fcbs,
&me->dummyfcb->list_entry_all);
@@ -1159,7 +1212,7 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb,
file_ref* destd
if (le == move_list.Flink && (me->fileref->dc->utf8.Length !=
utf8->Length || RtlCompareMemory(me->fileref->dc->utf8.Buffer,
utf8->Buffer, utf8->Length) != utf8->Length))
name_changed = true;
- if ((le == move_list.Flink || me->fileref->fcb->inode ==
SUBVOL_ROOT_INODE) && !me->dummyfileref->oldutf8.Buffer) {
+ if (!me->dummyfileref->oldutf8.Buffer) {
me->dummyfileref->oldutf8.Buffer = ExAllocatePoolWithTag(PagedPool,
me->fileref->dc->utf8.Length, ALLOC_TAG);
if (!me->dummyfileref->oldutf8.Buffer) {
ERR("out of memory\n");
@@ -1773,11 +1826,18 @@ static NTSTATUS rename_stream_to_file(device_extension* Vcb,
file_ref* fileref,
dummyfcb->Vcb = Vcb;
dummyfcb->subvol = fileref->fcb->subvol;
dummyfcb->inode = fileref->fcb->inode;
+ dummyfcb->hash = fileref->fcb->hash;
dummyfcb->adsxattr = fileref->fcb->adsxattr;
dummyfcb->adshash = fileref->fcb->adshash;
dummyfcb->ads = true;
dummyfcb->deleted = true;
+ acquire_fcb_lock_exclusive(Vcb);
+ add_fcb_to_subvol(dummyfcb);
+ InsertTailList(&Vcb->all_fcbs, &dummyfcb->list_entry_all);
+ dummyfcb->subvol->fcbs_version++;
+ release_fcb_lock(Vcb);
+
// FIXME - dummyfileref as well?
mark_fcb_dirty(dummyfcb);
@@ -1839,9 +1899,10 @@ static NTSTATUS rename_stream(device_extension* Vcb, file_ref*
fileref, ccb* ccb
if (fn.Length == 0)
return rename_stream_to_file(Vcb, fileref, ccb, flags, Irp, rollback);
- if (!is_file_name_valid(&fn, false, true)) {
+ Status = check_file_name_valid(&fn, false, true);
+ if (!NT_SUCCESS(Status)) {
WARN("invalid stream name %.*S\n", (int)(fn.Length / sizeof(WCHAR)),
fn.Buffer);
- return STATUS_OBJECT_NAME_INVALID;
+ return Status;
}
if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) &&
fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) {
@@ -1989,11 +2050,18 @@ static NTSTATUS rename_stream(device_extension* Vcb, file_ref*
fileref, ccb* ccb
dummyfcb->Vcb = Vcb;
dummyfcb->subvol = fileref->fcb->subvol;
dummyfcb->inode = fileref->fcb->inode;
+ dummyfcb->hash = fileref->fcb->hash;
dummyfcb->adsxattr = fileref->fcb->adsxattr;
dummyfcb->adshash = fileref->fcb->adshash;
dummyfcb->ads = true;
dummyfcb->deleted = true;
+ acquire_fcb_lock_exclusive(Vcb);
+ add_fcb_to_subvol(dummyfcb);
+ InsertTailList(&Vcb->all_fcbs, &dummyfcb->list_entry_all);
+ dummyfcb->subvol->fcbs_version++;
+ release_fcb_lock(Vcb);
+
mark_fcb_dirty(dummyfcb);
free_fcb(dummyfcb);
@@ -2078,9 +2146,10 @@ static NTSTATUS rename_file_to_stream(device_extension* Vcb,
file_ref* fileref,
return STATUS_INVALID_PARAMETER;
}
- if (!is_file_name_valid(&fn, false, true)) {
+ Status = check_file_name_valid(&fn, false, true);
+ if (!NT_SUCCESS(Status)) {
WARN("invalid stream name %.*S\n", (int)(fn.Length / sizeof(WCHAR)),
fn.Buffer);
- return STATUS_OBJECT_NAME_INVALID;
+ return Status;
}
if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) &&
fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) {
@@ -2468,9 +2537,6 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP
Irp, PFILE_OB
SECURITY_SUBJECT_CONTEXT subjcont;
ACCESS_MASK access;
ULONG flags;
-#ifdef __REACTOS__
- unsigned int i;
-#endif
InitializeListHead(&rollback);
@@ -2504,7 +2570,7 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP
Irp, PFILE_OB
for (i = fnlen - 1; i >= 0; i--) {
if (fri->FileName[i] == '\\' || fri->FileName[i] ==
'/') {
fn = &fri->FileName[i+1];
- fnlen = (fri->FileNameLength / sizeof(WCHAR)) - i - 1;
+ fnlen -= i + 1;
break;
}
}
@@ -2555,11 +2621,7 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP
Irp, PFILE_OB
TRACE("fnus = %.*S\n", (int)(fnus.Length / sizeof(WCHAR)), fnus.Buffer);
-#ifndef __REACTOS__
for (unsigned int i = 0 ; i < fnus.Length / sizeof(WCHAR); i++) {
-#else
- for (i = 0 ; i < fnus.Length / sizeof(WCHAR); i++) {
-#endif
if (fnus.Buffer[i] == ':') {
TRACE("colon in filename\n");
Status = STATUS_OBJECT_NAME_INVALID;
diff --git a/drivers/filesystems/btrfs/free-space.c
b/drivers/filesystems/btrfs/free-space.c
index c2fc0c1ae12..50b8141ee6f 100644
--- a/drivers/filesystems/btrfs/free-space.c
+++ b/drivers/filesystems/btrfs/free-space.c
@@ -1150,6 +1150,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk*
c, bool* chan
c->cache->subvol = Vcb->root_root;
c->cache->inode =
InterlockedIncrement64(&Vcb->root_root->lastinode);
+ c->cache->hash = calc_crc32c(0xffffffff,
(uint8_t*)&c->cache->inode, sizeof(uint64_t));
c->cache->type = BTRFS_TYPE_FILE;
c->cache->created = true;
@@ -1214,6 +1215,8 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk*
c, bool* chan
c->cache->extents_changed = true;
InsertTailList(&Vcb->all_fcbs, &c->cache->list_entry_all);
+ add_fcb_to_subvol(c->cache);
+
Status = flush_fcb(c->cache, true, batchlist, Irp);
if (!NT_SUCCESS(Status)) {
ERR("flush_fcb returned %08lx\n", Status);
diff --git a/drivers/filesystems/btrfs/fsctl.c b/drivers/filesystems/btrfs/fsctl.c
index f1bb68c22a0..8ad58df883f 100644
--- a/drivers/filesystems/btrfs/fsctl.c
+++ b/drivers/filesystems/btrfs/fsctl.c
@@ -601,8 +601,9 @@ static NTSTATUS create_snapshot(device_extension* Vcb, PFILE_OBJECT
FileObject,
if (is_subvol_readonly(fcb->subvol, Irp))
return STATUS_ACCESS_DENIED;
- if (!is_file_name_valid(&nameus, posix, false))
- return STATUS_OBJECT_NAME_INVALID;
+ Status = check_file_name_valid(&nameus, posix, false);
+ if (!NT_SUCCESS(Status))
+ return Status;
utf8.Buffer = NULL;
@@ -823,8 +824,9 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT
FileObject, vo
nameus.Length = nameus.MaximumLength = bcs->namelen;
nameus.Buffer = bcs->name;
- if (!is_file_name_valid(&nameus, bcs->posix, false))
- return STATUS_OBJECT_NAME_INVALID;
+ Status = check_file_name_valid(&nameus, bcs->posix, false);
+ if (!NT_SUCCESS(Status))
+ return Status;
utf8.Buffer = NULL;
@@ -961,8 +963,9 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT
FileObject, vo
rootfcb->Vcb = Vcb;
rootfcb->subvol = r;
- rootfcb->inode = SUBVOL_ROOT_INODE;
rootfcb->type = BTRFS_TYPE_DIRECTORY;
+ rootfcb->inode = SUBVOL_ROOT_INODE;
+ rootfcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&rootfcb->inode,
sizeof(uint64_t)); // FIXME - we can hardcode this
rootfcb->inode_item.generation = Vcb->superblock.generation;
rootfcb->inode_item.transid = Vcb->superblock.generation;
@@ -1006,7 +1009,7 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT
FileObject, vo
rootfcb->inode_item_changed = true;
acquire_fcb_lock_exclusive(Vcb);
- InsertTailList(&r->fcbs, &rootfcb->list_entry);
+ add_fcb_to_subvol(rootfcb);
InsertTailList(&Vcb->all_fcbs, &rootfcb->list_entry_all);
r->fcbs_version++;
release_fcb_lock(Vcb);
@@ -3693,6 +3696,44 @@ end:
return Status;
}
+static NTSTATUS check_inode_used(_In_
_Requires_exclusive_lock_held_(_Curr_->tree_lock) device_extension* Vcb,
+ _In_ root* subvol, _In_ uint64_t inode, _In_ uint32_t
hash, _In_opt_ PIRP Irp) {
+ KEY searchkey;
+ traverse_ptr tp;
+ NTSTATUS Status;
+ uint8_t c = hash >> 24;
+
+ if (subvol->fcbs_ptrs[c]) {
+ LIST_ENTRY* le = subvol->fcbs_ptrs[c];
+
+ while (le != &subvol->fcbs) {
+ struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
+
+ if (fcb2->inode == inode)
+ return STATUS_SUCCESS;
+ else if (fcb2->hash > hash)
+ break;
+
+ le = le->Flink;
+ }
+ }
+
+ searchkey.obj_id = inode;
+ searchkey.obj_type = TYPE_INODE_ITEM;
+ searchkey.offset = 0xffffffffffffffff;
+
+ Status = find_item(Vcb, subvol, &tp, &searchkey, false, Irp);
+ if (!NT_SUCCESS(Status)) {
+ ERR("find_item returned %08lx\n", Status);
+ return Status;
+ }
+
+ if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type ==
searchkey.obj_type)
+ return STATUS_SUCCESS;
+
+ return STATUS_NOT_FOUND;
+}
+
static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data, ULONG
datalen, PIRP Irp) {
NTSTATUS Status;
btrfs_mknod* bmn;
@@ -3705,7 +3746,6 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT
FileObject, void* data
dir_child* dc;
LARGE_INTEGER time;
BTRFS_TIME now;
- LIST_ENTRY* lastle;
ANSI_STRING utf8;
ULONG len, i;
SECURITY_SUBJECT_CONTEXT subjcont;
@@ -3925,35 +3965,33 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT
FileObject, void* data
acquire_fcb_lock_exclusive(Vcb);
if (bmn->inode == 0) {
- inode = InterlockedIncrement64(&parfcb->subvol->lastinode);
- lastle = parfcb->subvol->fcbs.Blink;
+ fcb->inode = InterlockedIncrement64(&parfcb->subvol->lastinode);
+ fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&fcb->inode,
sizeof(uint64_t));
} else {
if (bmn->inode > (uint64_t)parfcb->subvol->lastinode) {
- inode = parfcb->subvol->lastinode = bmn->inode;
- lastle = parfcb->subvol->fcbs.Blink;
+ fcb->inode = parfcb->subvol->lastinode = bmn->inode;
+ fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&fcb->inode,
sizeof(uint64_t));
} else {
- LIST_ENTRY* le = parfcb->subvol->fcbs.Flink;
+ uint32_t hash = calc_crc32c(0xffffffff, (uint8_t*)&bmn->inode,
sizeof(uint64_t));
- lastle = parfcb->subvol->fcbs.Blink;;
- while (le != &parfcb->subvol->fcbs) {
- struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
+ Status = check_inode_used(Vcb, subvol, bmn->inode, hash, Irp);
+ if (NT_SUCCESS(Status)) { // STATUS_SUCCESS means inode found
+ release_fcb_lock(Vcb);
+ ExReleaseResourceLite(&Vcb->fileref_lock);
- if (fcb2->inode == bmn->inode && !fcb2->deleted) {
- release_fcb_lock(Vcb);
- ExReleaseResourceLite(&Vcb->fileref_lock);
-
- WARN("inode collision\n");
- Status = STATUS_INVALID_PARAMETER;
- goto end;
- } else if (fcb2->inode > bmn->inode) {
- lastle = fcb2->list_entry.Blink;
- break;
- }
+ WARN("inode collision\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto end;
+ } else if (Status != STATUS_NOT_FOUND) {
+ ERR("check_inode_used returned %08lx\n", Status);
- le = le->Flink;
+ release_fcb_lock(Vcb);
+ ExReleaseResourceLite(&Vcb->fileref_lock);
+ goto end;
}
- inode = bmn->inode;
+ fcb->inode = bmn->inode;
+ fcb->hash = hash;
}
}
@@ -4025,7 +4063,7 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT
FileObject, void* data
RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
}
- InsertHeadList(lastle, &fcb->list_entry);
+ add_fcb_to_subvol(fcb);
InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
if (bmn->type == BTRFS_TYPE_DIRECTORY)
@@ -4924,10 +4962,10 @@ static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* Pirp) {
ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
+ ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
+
if (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_1 || fsctl == FSCTL_REQUEST_BATCH_OPLOCK ||
fsctl == FSCTL_REQUEST_FILTER_OPLOCK ||
fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2 || oplock_request) {
- ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
-
if (shared_request) {
if (fcb->type == BTRFS_TYPE_FILE) {
if (fFsRtlCheckLockForOplockRequest)
@@ -4939,8 +4977,7 @@ static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* Pirp) {
}
} else
oplock_count = fileref->open_count;
- } else
- ExAcquireResourceSharedLite(fcb->Header.Resource, true);
+ }
#if (NTDDI_VERSION >= NTDDI_WIN7)
if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK ||
diff --git a/drivers/filesystems/btrfs/pnp.c b/drivers/filesystems/btrfs/pnp.c
index 02314ba7a1f..54426102b9b 100644
--- a/drivers/filesystems/btrfs/pnp.c
+++ b/drivers/filesystems/btrfs/pnp.c
@@ -188,6 +188,18 @@ static NTSTATUS bus_pnp(bus_device_extension* bde, PIRP Irp) {
bool handled = false;
switch (IrpSp->MinorFunction) {
+ case IRP_MN_START_DEVICE:
+ case IRP_MN_CANCEL_REMOVE_DEVICE:
+ case IRP_MN_SURPRISE_REMOVAL:
+ case IRP_MN_REMOVE_DEVICE:
+ Status = STATUS_SUCCESS;
+ handled = true;
+ break;
+
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ Status = STATUS_UNSUCCESSFUL;
+ handled = true;
+ break;
case IRP_MN_QUERY_CAPABILITIES:
Status = bus_query_capabilities(Irp);
handled = true;
diff --git a/drivers/filesystems/btrfs/reparse.c b/drivers/filesystems/btrfs/reparse.c
index 03708228d46..4e473149d26 100644
--- a/drivers/filesystems/btrfs/reparse.c
+++ b/drivers/filesystems/btrfs/reparse.c
@@ -317,6 +317,11 @@ NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG
buflen, cc
// FIXME - die if not file or directory
+ if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size >
0) {
+ TRACE("directory not empty\n");
+ return STATUS_DIRECTORY_NOT_EMPTY;
+ }
+
if (buflen < sizeof(ULONG)) {
WARN("buffer was not long enough to hold tag\n");
return STATUS_INVALID_BUFFER_SIZE;
@@ -328,7 +333,10 @@ NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG
buflen, cc
return Status;
}
- RtlCopyMemory(&tag, rdb, sizeof(ULONG));
+ tag = *(ULONG*)rdb;
+
+ if (tag == IO_REPARSE_TAG_MOUNT_POINT && fcb->type !=
BTRFS_TYPE_DIRECTORY)
+ return STATUS_NOT_A_DIRECTORY;
if (fcb->type == BTRFS_TYPE_FILE &&
((tag == IO_REPARSE_TAG_SYMLINK &&
rdb->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) || tag ==
IO_REPARSE_TAG_LX_SYMLINK)) {
diff --git a/drivers/filesystems/btrfs/search.c b/drivers/filesystems/btrfs/search.c
index c44e95f7c79..e604cc99814 100644
--- a/drivers/filesystems/btrfs/search.c
+++ b/drivers/filesystems/btrfs/search.c
@@ -903,7 +903,7 @@ void __stdcall mountmgr_thread(_In_ void* context) {
break;
}
- Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp,
sizeof(MOUNTMGR_MOUNT_POINTS), mmps2, mmps.Size,
+ Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_QUERY_POINTS, &mmp,
sizeof(MOUNTMGR_MOUNT_POINT), mmps2, mmps.Size,
false, NULL);
if (!NT_SUCCESS(Status))
ERR("IOCTL_MOUNTMGR_QUERY_POINTS returned %08lx\n", Status);
diff --git a/drivers/filesystems/btrfs/security.c b/drivers/filesystems/btrfs/security.c
index 2761c63a915..c1183de2465 100644
--- a/drivers/filesystems/btrfs/security.c
+++ b/drivers/filesystems/btrfs/security.c
@@ -95,7 +95,7 @@ void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, uint32_t
uid) {
while (sidstringlength > 0) {
val = 0;
i = 0;
- while (sidstring[i] != '-' && i < sidstringlength) {
+ while (i < sidstringlength && sidstring[i] != '-') {
if (sidstring[i] >= '0' && sidstring[i] <= '9')
{
val *= 10;
val += sidstring[i] - '0';
diff --git a/drivers/filesystems/btrfs/treefuncs.c
b/drivers/filesystems/btrfs/treefuncs.c
index 4e5502fce2f..3b9483a7b08 100644
--- a/drivers/filesystems/btrfs/treefuncs.c
+++ b/drivers/filesystems/btrfs/treefuncs.c
@@ -2177,6 +2177,9 @@ static NTSTATUS
commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
Status = handle_batch_collision(Vcb, bi, tp.tree, tp.item, td,
&br->items, &ignore);
if (!NT_SUCCESS(Status)) {
ERR("handle_batch_collision returned %08lx\n",
Status);
+#ifdef _DEBUG
+ int3;
+#endif
if (td)
ExFreeToPagedLookasideList(&Vcb->tree_data_lookaside,
td);
@@ -2258,6 +2261,9 @@ static NTSTATUS
commit_batch_list_root(_Requires_exclusive_lock_held_(_Curr_->tr
Status = handle_batch_collision(Vcb, bi2, tp.tree, td2,
td, &br->items, &ignore);
if (!NT_SUCCESS(Status)) {
ERR("handle_batch_collision returned
%08lx\n", Status);
+#ifdef _DEBUG
+ int3;
+#endif
return Status;
}
}
diff --git a/drivers/filesystems/btrfs/write.c b/drivers/filesystems/btrfs/write.c
index 0d63ac01cec..f4661598400 100644
--- a/drivers/filesystems/btrfs/write.c
+++ b/drivers/filesystems/btrfs/write.c
@@ -3476,7 +3476,7 @@ NTSTATUS extend_file(fcb* fcb, file_ref* fileref, uint64_t end, bool
prealloc, P
Status = insert_prealloc_extent(fcb, oldalloc, newalloc -
oldalloc, rollback);
- if (!NT_SUCCESS(Status)) {
+ if (!NT_SUCCESS(Status) && Status != STATUS_DISK_FULL) {
ERR("insert_prealloc_extent returned %08lx\n",
Status);
return Status;
}
@@ -3503,7 +3503,7 @@ NTSTATUS extend_file(fcb* fcb, file_ref* fileref, uint64_t end, bool
prealloc, P
if (prealloc) {
Status = insert_prealloc_extent(fcb, 0, newalloc, rollback);
- if (!NT_SUCCESS(Status)) {
+ if (!NT_SUCCESS(Status) && Status != STATUS_DISK_FULL) {
ERR("insert_prealloc_extent returned %08lx\n",
Status);
return Status;
}
@@ -4285,16 +4285,19 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp,
LARGE_INTEGER offset, void
Status = Irp->IoStatus.Status;
goto end;
} else {
+ /* We have to wait in CcCopyWrite - if we return STATUS_PENDING and add
this to the work queue,
+ * it can result in CcFlushCache being called before the job has run. See
ifstest ReadWriteTest. */
+
if (fCcCopyWriteEx) {
- TRACE("CcCopyWriteEx(%p, %I64x, %lx, %u, %p, %p)\n",
FileObject, off64, *length, wait, buf, Irp->Tail.Overlay.Thread);
- if (!fCcCopyWriteEx(FileObject, &offset, *length, wait, buf,
Irp->Tail.Overlay.Thread)) {
+ TRACE("CcCopyWriteEx(%p, %I64x, %lx, %u, %p, %p)\n",
FileObject, off64, *length, true, buf, Irp->Tail.Overlay.Thread);
+ if (!fCcCopyWriteEx(FileObject, &offset, *length, true, buf,
Irp->Tail.Overlay.Thread)) {
Status = STATUS_PENDING;
goto end;
}
TRACE("CcCopyWriteEx finished\n");
} else {
- TRACE("CcCopyWrite(%p, %I64x, %lx, %u, %p)\n", FileObject,
off64, *length, wait, buf);
- if (!CcCopyWrite(FileObject, &offset, *length, wait, buf)) {
+ TRACE("CcCopyWrite(%p, %I64x, %lx, %u, %p)\n", FileObject,
off64, *length, true, buf);
+ if (!CcCopyWrite(FileObject, &offset, *length, true, buf)) {
Status = STATUS_PENDING;
goto end;
}
diff --git a/sdk/lib/fslib/btrfslib/btrfslib.c b/sdk/lib/fslib/btrfslib/btrfslib.c
index d176204b2a2..7c07cdc1d63 100644
--- a/sdk/lib/fslib/btrfslib/btrfslib.c
+++ b/sdk/lib/fslib/btrfslib/btrfslib.c
@@ -1263,13 +1263,6 @@ static bool is_mounted_multi_device(HANDLE h, uint32_t sector_size)
{
bfs = malloc(bfssize);
Status = NtDeviceIoControlFile(h2, NULL, NULL, NULL, &iosb,
IOCTL_BTRFS_QUERY_FILESYSTEMS, NULL, 0, bfs, bfssize);
- if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_OVERFLOW) {
-#ifdef __REACTOS__
- if (bfs) free(bfs);
-#endif
- NtClose(h2);
- return false;
- }
} while (Status == STATUS_BUFFER_OVERFLOW);
if (!NT_SUCCESS(Status))