[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
This commit is contained in:
Vincent Franchomme 2022-04-28 21:34:48 +02:00 committed by Hermès BÉLUSCA - MAÏTO
parent b826992ab2
commit c982533ea9
19 changed files with 761 additions and 767 deletions

View file

@ -61,8 +61,8 @@ IDI_ICON1 ICON "subvol.ico"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,7,5,0 FILEVERSION 1,7,6,0
PRODUCTVERSION 1,7,5,0 PRODUCTVERSION 1,7,6,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -78,12 +78,12 @@ BEGIN
BLOCK "080904b0" BLOCK "080904b0"
BEGIN BEGIN
VALUE "FileDescription", "WinBtrfs shell extension" VALUE "FileDescription", "WinBtrfs shell extension"
VALUE "FileVersion", "1.7.5" VALUE "FileVersion", "1.7.6"
VALUE "InternalName", "btrfs" VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-21"
VALUE "OriginalFilename", "shellbtrfs.dll" VALUE "OriginalFilename", "shellbtrfs.dll"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.7.5" VALUE "ProductVersion", "1.7.6"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,7,5,0 FILEVERSION 1,7,6,0
PRODUCTVERSION 1,7,5,0 PRODUCTVERSION 1,7,6,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -68,12 +68,12 @@ BEGIN
BLOCK "080904b0" BLOCK "080904b0"
BEGIN BEGIN
VALUE "FileDescription", "Btrfs utility DLL" VALUE "FileDescription", "Btrfs utility DLL"
VALUE "FileVersion", "1.7.5" VALUE "FileVersion", "1.7.6"
VALUE "InternalName", "ubtrfs" VALUE "InternalName", "ubtrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-21"
VALUE "OriginalFilename", "ubtrfs.dll" VALUE "OriginalFilename", "ubtrfs.dll"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.7.5" VALUE "ProductVersion", "1.7.6"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -46,20 +46,7 @@ typedef struct {
ULONG ExtensionFlags; ULONG ExtensionFlags;
} DEVOBJ_EXTENSION2; } DEVOBJ_EXTENSION2;
typedef enum { static bool get_system_root() {
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) {
NTSTATUS Status; NTSTATUS Status;
HANDLE h; HANDLE h;
UNICODE_STRING us, target; 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 system_root[] = L"\\SystemRoot";
static const WCHAR boot_device[] = L"\\Device\\BootDevice"; 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("; static const WCHAR arc_btrfs_prefix[] = L"\\ArcName\\btrfs(";
us.Buffer = (WCHAR*)system_root; us.Buffer = (WCHAR*)system_root;
@ -82,7 +67,7 @@ static void get_system_root(system_root* sr) {
Status = ZwOpenSymbolicLinkObject(&h, GENERIC_READ, &objatt); Status = ZwOpenSymbolicLinkObject(&h, GENERIC_READ, &objatt);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("ZwOpenSymbolicLinkObject returned %08lx\n", Status); ERR("ZwOpenSymbolicLinkObject returned %08lx\n", Status);
return; return false;
} }
target.Length = target.MaximumLength = 0; target.Length = target.MaximumLength = 0;
@ -91,19 +76,19 @@ static void get_system_root(system_root* sr) {
if (Status != STATUS_BUFFER_TOO_SMALL) { if (Status != STATUS_BUFFER_TOO_SMALL) {
ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status); ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status);
NtClose(h); NtClose(h);
return; return false;
} }
if (retlen == 0) { if (retlen == 0) {
NtClose(h); NtClose(h);
return; return false;
} }
target.Buffer = ExAllocatePoolWithTag(NonPagedPool, retlen, ALLOC_TAG); target.Buffer = ExAllocatePoolWithTag(NonPagedPool, retlen, ALLOC_TAG);
if (!target.Buffer) { if (!target.Buffer) {
ERR("out of memory\n"); ERR("out of memory\n");
NtClose(h); NtClose(h);
return; return false;
} }
target.Length = target.MaximumLength = (USHORT)retlen; target.Length = target.MaximumLength = (USHORT)retlen;
@ -113,7 +98,7 @@ static void get_system_root(system_root* sr) {
ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status); ERR("ZwQuerySymbolicLinkObject returned %08lx\n", Status);
NtClose(h); NtClose(h);
ExFreePool(target.Buffer); ExFreePool(target.Buffer);
return; return false;
} }
NtClose(h); NtClose(h);
@ -136,85 +121,33 @@ static void get_system_root(system_root* sr) {
break; break;
} }
sr->type = system_root_unknown; if (target.Length >= sizeof(arc_btrfs_prefix) - sizeof(WCHAR) &&
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) &&
RtlCompareMemory(target.Buffer, arc_btrfs_prefix, sizeof(arc_btrfs_prefix) - sizeof(WCHAR)) == 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]; 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++) { for (unsigned int i = 0; i < 16; i++) {
#else
for (i = 0; i < 16; i++) {
#endif // __REACTOS__
if (*s >= '0' && *s <= '9') 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') 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') else if (*s >= 'A' && *s <= 'F')
sr->uuid.uuid[i] = (*s - 'A' + 0xa) << 4; boot_uuid.uuid[i] = (*s - 'A' + 0xa) << 4;
else { else {
ExFreePool(target.Buffer); ExFreePool(target.Buffer);
return; return false;
} }
s++; s++;
if (*s >= '0' && *s <= '9') if (*s >= '0' && *s <= '9')
sr->uuid.uuid[i] |= *s - '0'; boot_uuid.uuid[i] |= *s - '0';
else if (*s >= 'a' && *s <= 'f') 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') else if (*s >= 'A' && *s <= 'F')
sr->uuid.uuid[i] |= *s - 'A' + 0xa; boot_uuid.uuid[i] |= *s - 'A' + 0xa;
else { else {
ExFreePool(target.Buffer); ExFreePool(target.Buffer);
return; return false;
} }
s++; s++;
@ -222,7 +155,7 @@ static void get_system_root(system_root* sr) {
if (i == 3 || i == 5 || i == 7 || i == 9) { if (i == 3 || i == 5 || i == 7 || i == 9) {
if (*s != '-') { if (*s != '-') {
ExFreePool(target.Buffer); ExFreePool(target.Buffer);
return; return false;
} }
s++; s++;
@ -231,97 +164,17 @@ static void get_system_root(system_root* sr) {
if (*s != ')') { if (*s != ')') {
ExFreePool(target.Buffer); ExFreePool(target.Buffer);
return; return false;
} }
sr->type = system_root_btrfs; ExFreePool(target.Buffer);
return true;
} }
ExFreePool(target.Buffer); ExFreePool(target.Buffer);
}
static void append_int_to_us(UNICODE_STRING* us, unsigned int n) { return false;
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];
while (n > 0) {
*ptr = L'0' + (n % 10);
ptr--;
n /= 10;
}
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);
Status = IoCreateSymbolicLink(&us, &us2);
if (!NT_SUCCESS(Status))
ERR("IoCreateSymbolicLink returned %08lx\n", Status);
} }
static void mountmgr_notification(BTRFS_UUID* uuid) { static void mountmgr_notification(BTRFS_UUID* uuid) {
@ -332,9 +185,6 @@ static void mountmgr_notification(BTRFS_UUID* uuid) {
ULONG mmtnlen; ULONG mmtnlen;
MOUNTMGR_TARGET_NAME* mmtn; MOUNTMGR_TARGET_NAME* mmtn;
WCHAR* w; WCHAR* w;
#ifdef __REACTOS__
unsigned int i;
#endif
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME); RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &FileObject, &mountmgr); 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]; w = &mmtn->DeviceName[(sizeof(BTRFS_VOLUME_PREFIX) / sizeof(WCHAR)) - 1];
#ifndef __REACTOS__
for (unsigned int i = 0; i < 16; i++) { 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] >> 4); w++;
*w = hex_digit(uuid->uuid[i] & 0xf); w++; *w = hex_digit(uuid->uuid[i] & 0xf); w++;
@ -487,166 +333,52 @@ void boot_add_device(DEVICE_OBJECT* pdo) {
mountmgr_notification(&pdode->uuid); mountmgr_notification(&pdode->uuid);
} }
/* If booting from Btrfs, Windows will pass the device object for the raw partition to void check_system_root() {
* 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;
LIST_ENTRY* le; LIST_ENTRY* le;
bool done = false;
PDEVICE_OBJECT pdo_to_add = NULL; PDEVICE_OBJECT pdo_to_add = NULL;
volume_child* boot_vc = NULL;
TRACE("(%p, %p, %lu)\n", DriverObject, Context, Count); TRACE("()\n");
UNUSED(DriverObject);
UNUSED(Context);
UNUSED(Count);
// wait for any PNP notifications in progress to finish // wait for any PNP notifications in progress to finish
ExAcquireResourceExclusiveLite(&boot_lock, TRUE); ExAcquireResourceExclusiveLite(&boot_lock, TRUE);
ExReleaseResourceLite(&boot_lock); ExReleaseResourceLite(&boot_lock);
get_system_root(&sr); if (!get_system_root())
return;
if (sr.type == system_root_partition) { ExAcquireResourceSharedLite(&pdo_list_lock, true);
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) {
pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry);
le = pdo_list.Flink; if (RtlCompareMemory(&pdode->uuid, &boot_uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
while (le != &pdo_list) { if (!pdode->vde)
LIST_ENTRY* le2; pdo_to_add = pdode->pdo;
pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); else if (pdode->vde->device && !(pdode->vde->device->Flags & DO_SYSTEM_BOOT_PARTITION)) { // AddDevice has beaten us to it
NTSTATUS Status;
ExAcquireResourceSharedLite(&pdode->child_lock, true); pdode->vde->device->Flags |= DO_SYSTEM_BOOT_PARTITION;
pdode->pdo->Flags |= DO_SYSTEM_BOOT_PARTITION;
le2 = pdode->children.Flink; Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, false);
if (!NT_SUCCESS(Status))
ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
while (le2 != &pdode->children) { Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, true);
volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry); if (!NT_SUCCESS(Status))
ERR("IoSetDeviceInterfaceState returned %08lx\n", Status);
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) { break;
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);
le = le->Flink;
} }
ExReleaseResourceLite(&pdo_list_lock); le = le->Flink;
} else if (sr.type == system_root_btrfs) {
boot_uuid = sr.uuid;
ExAcquireResourceSharedLite(&pdo_list_lock, true);
le = pdo_list.Flink;
while (le != &pdo_list) {
pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry);
if (RtlCompareMemory(&pdode->uuid, &sr.uuid, sizeof(BTRFS_UUID)) == sizeof(BTRFS_UUID)) {
if (!pdode->vde)
pdo_to_add = pdode->pdo;
break;
}
le = le->Flink;
}
ExReleaseResourceLite(&pdo_list_lock);
} }
if (boot_vc) { ExReleaseResourceLite(&pdo_list_lock);
NTSTATUS Status;
UNICODE_STRING name;
/* On Windows 8, mountmgr!MountMgrFindBootVolume returns the first volume in its database check_boot_options();
* 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);
}
}
if (sr.type == system_root_btrfs || boot_vc)
check_boot_options();
// If our FS depends on volumes that aren't there when we do our IoRegisterPlugPlayNotification calls // 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 // in DriverEntry, bus_query_device_relations won't get called until it's too late. We need to do our

View file

@ -667,6 +667,9 @@ static bool lie_about_fs_type() {
INIT_UNICODE_STRING(fsutil, L"FSUTIL.EXE"); INIT_UNICODE_STRING(fsutil, L"FSUTIL.EXE");
INIT_UNICODE_STRING(storsvc, L"STORSVC.DLL"); 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()) if (!PsGetCurrentProcess())
return false; return false;
@ -733,6 +736,15 @@ static bool lie_about_fs_type() {
blacklist = FsRtlAreNamesEqual(&name, &usstorsvc, true, NULL); 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) { if (blacklist) {
void** frames; void** frames;
ULONG i, num_frames; ULONG i, num_frames;
@ -1833,10 +1845,6 @@ void reap_fileref(device_extension* Vcb, file_ref* fr) {
// FIXME - do delete if needed // FIXME - do delete if needed
ExDeleteResourceLite(&fr->nonpaged->fileref_lock);
ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged);
// FIXME - throw error if children not empty // FIXME - throw error if children not empty
if (fr->fcb->fileref == fr) if (fr->fcb->fileref == fr)
@ -2161,7 +2169,6 @@ void uninit(_In_ device_extension* Vcb) {
ExDeletePagedLookasideList(&Vcb->fcb_lookaside); ExDeletePagedLookasideList(&Vcb->fcb_lookaside);
ExDeletePagedLookasideList(&Vcb->name_bit_lookaside); ExDeletePagedLookasideList(&Vcb->name_bit_lookaside);
ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside); ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside);
ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside);
ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside); ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
ZwClose(Vcb->flush_thread_handle); 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->fcb_lookaside, NULL, NULL, 0, sizeof(fcb), ALLOC_TAG, 0);
ExInitializePagedLookasideList(&Vcb->name_bit_lookaside, NULL, NULL, 0, sizeof(name_bit), 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->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); ExInitializeNPagedLookasideList(&Vcb->fcb_np_lookaside, NULL, NULL, 0, sizeof(fcb_nonpaged), ALLOC_TAG, 0);
init_lookaside = true; init_lookaside = true;
@ -5027,7 +5033,6 @@ exit2:
ExDeletePagedLookasideList(&Vcb->fcb_lookaside); ExDeletePagedLookasideList(&Vcb->fcb_lookaside);
ExDeletePagedLookasideList(&Vcb->name_bit_lookaside); ExDeletePagedLookasideList(&Vcb->name_bit_lookaside);
ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside); ExDeleteNPagedLookasideList(&Vcb->range_lock_lookaside);
ExDeleteNPagedLookasideList(&Vcb->fileref_np_lookaside);
ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside); ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
} }
@ -5764,27 +5769,43 @@ exit:
return Status; 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; ULONG i;
if (us->Length < sizeof(WCHAR)) if (us->Length < sizeof(WCHAR))
return false; return STATUS_OBJECT_NAME_INVALID;
if (us->Length > 255 * sizeof(WCHAR)) if (us->Length > 255 * sizeof(WCHAR))
return false; return STATUS_OBJECT_NAME_INVALID;
for (i = 0; i < us->Length / sizeof(WCHAR); i++) { for (i = 0; i < us->Length / sizeof(WCHAR); i++) {
if (us->Buffer[i] == '/' || us->Buffer[i] == 0 || if (us->Buffer[i] == '/' || us->Buffer[i] == 0 ||
(!posix && (us->Buffer[i] == '/' || us->Buffer[i] == ':')) || (!posix && (us->Buffer[i] == '/' || us->Buffer[i] == ':')) ||
(!posix && !stream && (us->Buffer[i] == '<' || 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)))) 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] == '.'))) 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) { 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); IoRegisterFileSystem(DeviceObject);
IoRegisterBootDriverReinitialization(DriverObject, check_system_root, NULL); check_system_root();
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View file

@ -10,7 +10,7 @@ Signature = "$Windows NT$"
Class = Volume Class = Volume
ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f} ClassGuid = {71a27cdd-812a-11d0-bec7-08002be2092f}
Provider = %Me% Provider = %Me%
DriverVer = 10/31/2020,1.7.5.0 DriverVer = 01/14/2021,1.7.6.0
CatalogFile = btrfs.cat CatalogFile = btrfs.cat
[DestinationDirs] [DestinationDirs]

View file

@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,7,5,0 FILEVERSION 1,7,6,0
PRODUCTVERSION 1,7,5,0 PRODUCTVERSION 1,7,6,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -68,12 +68,12 @@ BEGIN
BLOCK "080904b0" BLOCK "080904b0"
BEGIN BEGIN
VALUE "FileDescription", "WinBtrfs" VALUE "FileDescription", "WinBtrfs"
VALUE "FileVersion", "1.7.5" VALUE "FileVersion", "1.7.6"
VALUE "InternalName", "btrfs" VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-20" VALUE "LegalCopyright", "Copyright (c) Mark Harmstone 2016-21"
VALUE "OriginalFilename", "btrfs.sys" VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs" VALUE "ProductName", "WinBtrfs"
VALUE "ProductVersion", "1.7.5" VALUE "ProductVersion", "1.7.6"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View file

@ -338,10 +338,6 @@ typedef struct _fcb {
LIST_ENTRY list_entry_dirty; LIST_ENTRY list_entry_dirty;
} fcb; } fcb;
typedef struct {
ERESOURCE fileref_lock;
} file_ref_nonpaged;
typedef struct _file_ref { typedef struct _file_ref {
fcb* fcb; fcb* fcb;
ANSI_STRING oldutf8; ANSI_STRING oldutf8;
@ -350,7 +346,6 @@ typedef struct _file_ref {
bool posix_delete; bool posix_delete;
bool deleted; bool deleted;
bool created; bool created;
file_ref_nonpaged* nonpaged;
LIST_ENTRY children; LIST_ENTRY children;
LONG refcount; LONG refcount;
LONG open_count; LONG open_count;
@ -832,7 +827,6 @@ typedef struct _device_extension {
PAGED_LOOKASIDE_LIST fcb_lookaside; PAGED_LOOKASIDE_LIST fcb_lookaside;
PAGED_LOOKASIDE_LIST name_bit_lookaside; PAGED_LOOKASIDE_LIST name_bit_lookaside;
NPAGED_LOOKASIDE_LIST range_lock_lookaside; NPAGED_LOOKASIDE_LIST range_lock_lookaside;
NPAGED_LOOKASIDE_LIST fileref_np_lookaside;
NPAGED_LOOKASIDE_LIST fcb_np_lookaside; NPAGED_LOOKASIDE_LIST fcb_np_lookaside;
LIST_ENTRY list_entry; LIST_ENTRY list_entry;
} device_extension; } device_extension;
@ -1122,7 +1116,7 @@ NTSTATUS create_root(_In_ _Requires_exclusive_lock_held_(_Curr_->tree_lock) devi
void uninit(_In_ device_extension* Vcb); 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, 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); _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 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); 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); 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 insert_dir_child_into_hash_lists(fcb* fcb, dir_child* dc);
void remove_dir_child_from_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 // in reparse.c
NTSTATUS get_reparse_point(PFILE_OBJECT FileObject, void* buffer, DWORD buflen, ULONG_PTR* retlen); 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); NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN PREPARSE_DATA_BUFFER ReparseBuffer);
// in boot.c // 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); void boot_add_device(DEVICE_OBJECT* pdo);
extern BTRFS_UUID boot_uuid; extern BTRFS_UUID boot_uuid;

View file

@ -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_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 } }; 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* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) {
fcb* fcb; fcb* fcb;
@ -160,13 +166,6 @@ file_ref* create_fileref(device_extension* Vcb) {
RtlZeroMemory(fr, sizeof(file_ref)); 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; fr->refcount = 1;
#ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_FCB_REFCOUNTS
@ -175,8 +174,6 @@ file_ref* create_fileref(device_extension* Vcb) {
InitializeListHead(&fr->children); InitializeListHead(&fr->children);
ExInitializeResourceLite(&fr->nonpaged->fileref_lock);
return fr; 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); ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
if (duff_fr) if (duff_fr)
reap_fileref(Vcb, duff_fr); ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, duff_fr);
} else { } else {
root* subvol; root* subvol;
uint64_t inode; uint64_t inode;
@ -1652,9 +1649,6 @@ NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
sf2->fcb = fcb; sf2->fcb = fcb;
if (dc->type == BTRFS_TYPE_DIRECTORY)
fcb->fileref = sf2;
ExAcquireResourceExclusiveLite(&sf->fcb->nonpaged->dir_children_lock, true); ExAcquireResourceExclusiveLite(&sf->fcb->nonpaged->dir_children_lock, true);
if (!dc->fileref) { if (!dc->fileref) {
@ -1663,6 +1657,9 @@ NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
dc->fileref = sf2; dc->fileref = sf2;
InsertTailList(&sf->children, &sf2->list_entry); InsertTailList(&sf->children, &sf2->list_entry);
increase_fileref_refcount(sf); increase_fileref_refcount(sf);
if (dc->type == BTRFS_TYPE_DIRECTORY)
fcb->fileref = sf2;
} else { } else {
duff_fr = sf2; duff_fr = sf2;
sf2 = dc->fileref; sf2 = dc->fileref;
@ -2654,9 +2651,6 @@ static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
#ifdef DEBUG_FCB_REFCOUNTS #ifdef DEBUG_FCB_REFCOUNTS
LONG rc; LONG rc;
#endif #endif
#ifdef __REACTOS__
LIST_ENTRY* le;
#endif
TRACE("fpus = %.*S\n", (int)(fpus->Length / sizeof(WCHAR)), fpus->Buffer); TRACE("fpus = %.*S\n", (int)(fpus->Length / sizeof(WCHAR)), fpus->Buffer);
TRACE("stream = %.*S\n", (int)(stream->Length / sizeof(WCHAR)), stream->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) { if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
UNICODE_STRING fpus2; UNICODE_STRING fpus2;
if (!is_file_name_valid(fpus, false, true)) Status = check_file_name_valid(fpus, false, true);
return STATUS_OBJECT_NAME_INVALID; if (!NT_SUCCESS(Status))
return Status;
fpus2.Length = fpus2.MaximumLength = fpus->Length; fpus2.Length = fpus2.MaximumLength = fpus->Length;
fpus2.Buffer = ExAllocatePoolWithTag(pool_type, fpus2.MaximumLength, ALLOC_TAG); 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 #endif
fcb->subvol = parfileref->fcb->subvol; fcb->subvol = parfileref->fcb->subvol;
fcb->inode = parfileref->fcb->inode; fcb->inode = parfileref->fcb->inode;
fcb->hash = parfileref->fcb->hash;
fcb->type = parfileref->fcb->type; fcb->type = parfileref->fcb->type;
fcb->ads = true; 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); ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock, true);
#ifndef __REACTOS__
LIST_ENTRY* le = parfileref->fcb->dir_children_index.Flink; 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) { while (le != &parfileref->fcb->dir_children_index) {
dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_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 { } else {
ACCESS_MASK granted_access; ACCESS_MASK granted_access;
if (!is_file_name_valid(&fpus, false, false)) { Status = check_file_name_valid(&fpus, false, false);
Status = STATUS_OBJECT_NAME_INVALID; if (!NT_SUCCESS(Status))
goto end; goto end;
}
SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext); SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
@ -3581,12 +3572,357 @@ end:
fcb->csum_loaded = true; fcb->csum_loaded = true;
} }
static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, POOL_TYPE pool_type, file_ref* fileref, ACCESS_MASK* granted_access, static NTSTATUS open_file3(device_extension* Vcb, PIRP Irp, ACCESS_MASK granted_access, file_ref* fileref, LIST_ENTRY* rollback) {
NTSTATUS Status;
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 (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) {
ULONG defda, oldatts, filter;
LARGE_INTEGER time;
BTRFS_TIME now;
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);
return Status;
}
} else {
Status = truncate_file(fileref->fcb, 0, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("truncate_file returned %08lx\n", Status);
return Status;
}
}
if (Irp->Overlay.AllocationSize.QuadPart > 0) {
Status = extend_file(fileref->fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, true, NULL, rollback);
if (!NT_SUCCESS(Status)) {
ERR("extend_file returned %08lx\n", Status);
return Status;
}
}
if (!fileref->fcb->ads) {
LIST_ENTRY* le;
if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
ULONG offset;
FILE_FULL_EA_INFORMATION* eainfo;
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);
return Status;
}
fileref->fcb->ealen = 4;
// capitalize EA name
eainfo = Irp->AssociatedIrp.SystemBuffer;
do {
STRING s;
s.Length = s.MaximumLength = eainfo->EaNameLength;
s.Buffer = eainfo->EaName;
RtlUpperString(&s, &s);
fileref->fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
if (eainfo->NextEntryOffset == 0)
break;
eainfo = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)eainfo) + eainfo->NextEntryOffset);
} while (true);
if (fileref->fcb->ea_xattr.Buffer)
ExFreePool(fileref->fcb->ea_xattr.Buffer);
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");
return STATUS_INSUFFICIENT_RESOURCES;
}
fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = (USHORT)IrpSp->Parameters.Create.EaLength;
RtlCopyMemory(fileref->fcb->ea_xattr.Buffer, Irp->AssociatedIrp.SystemBuffer, fileref->fcb->ea_xattr.Length);
} else {
if (fileref->fcb->ea_xattr.Length > 0) {
ExFreePool(fileref->fcb->ea_xattr.Buffer);
fileref->fcb->ea_xattr.Buffer = NULL;
fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = 0;
fileref->fcb->ea_changed = true;
fileref->fcb->ealen = 0;
}
}
// remove streams and send notifications
le = fileref->fcb->dir_children_index.Flink;
while (le != &fileref->fcb->dir_children_index) {
dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
LIST_ENTRY* le2 = le->Flink;
if (dc->index == 0) {
if (!dc->fileref) {
file_ref* fr2;
Status = open_fileref_child(Vcb, fileref, &dc->name, true, true, true, PagedPool, &fr2, NULL);
if (!NT_SUCCESS(Status))
WARN("open_fileref_child returned %08lx\n", Status);
}
if (dc->fileref) {
queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name);
Status = delete_fileref(dc->fileref, NULL, false, NULL, rollback);
if (!NT_SUCCESS(Status)) {
ERR("delete_fileref returned %08lx\n", Status);
return Status;
}
}
} else
break;
le = le2;
}
}
KeQuerySystemTime(&time);
win_time_to_unix(time, &now);
filter = FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
if (fileref->fcb->ads) {
fileref->parent->fcb->inode_item.st_mtime = now;
fileref->parent->fcb->inode_item_changed = true;
mark_fcb_dirty(fileref->parent->fcb);
queue_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name);
} else {
mark_fcb_dirty(fileref->fcb);
oldatts = fileref->fcb->atts;
defda = get_file_attributes(Vcb, fileref->fcb->subvol, fileref->fcb->inode, fileref->fcb->type,
fileref->dc && fileref->dc->name.Length >= sizeof(WCHAR) && fileref->dc->name.Buffer[0] == '.', true, Irp);
if (RequestedDisposition == FILE_SUPERSEDE)
fileref->fcb->atts = IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
else
fileref->fcb->atts |= IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
if (fileref->fcb->atts != oldatts) {
fileref->fcb->atts_changed = true;
fileref->fcb->atts_deleted = IrpSp->Parameters.Create.FileAttributes == defda;
filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
}
fileref->fcb->inode_item.transid = Vcb->superblock.generation;
fileref->fcb->inode_item.sequence++;
fileref->fcb->inode_item.st_ctime = now;
fileref->fcb->inode_item.st_mtime = now;
fileref->fcb->inode_item_changed = true;
queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
}
} else {
if (options & FILE_NO_EA_KNOWLEDGE && fileref->fcb->ea_xattr.Length > 0) {
FILE_FULL_EA_INFORMATION* ffei = (FILE_FULL_EA_INFORMATION*)fileref->fcb->ea_xattr.Buffer;
do {
if (ffei->Flags & FILE_NEED_EA) {
WARN("returning STATUS_ACCESS_DENIED as no EA knowledge\n");
return STATUS_ACCESS_DENIED;
}
if (ffei->NextEntryOffset == 0)
break;
ffei = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)ffei) + ffei->NextEntryOffset);
} while (true);
}
}
FileObject->FsContext = fileref->fcb;
ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG);
if (!ccb) {
ERR("out of memory\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(ccb, sizeof(*ccb));
ccb->NodeType = BTRFS_NODE_TYPE_CCB;
ccb->NodeSize = sizeof(*ccb);
ccb->disposition = RequestedDisposition;
ccb->options = options;
ccb->query_dir_offset = 0;
RtlInitUnicodeString(&ccb->query_string, NULL);
ccb->has_wildcard = false;
ccb->specific_file = false;
ccb->access = granted_access;
ccb->case_sensitive = IrpSp->Flags & SL_CASE_SENSITIVE;
ccb->reserving = false;
ccb->lxss = called_from_lxss();
ccb->fileref = fileref;
FileObject->FsContext2 = ccb;
FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
switch (RequestedDisposition) {
case FILE_SUPERSEDE:
Irp->IoStatus.Information = FILE_SUPERSEDED;
break;
case FILE_OPEN:
case FILE_OPEN_IF:
Irp->IoStatus.Information = FILE_OPENED;
break;
case FILE_OVERWRITE:
case FILE_OVERWRITE_IF:
Irp->IoStatus.Information = FILE_OVERWRITTEN;
break;
}
// Make sure paging files don't have any extents marked as being prealloc,
// as this would mean we'd have to lock exclusively when writing.
if (IrpSp->Flags & SL_OPEN_PAGING_FILE) {
LIST_ENTRY* le;
bool changed = false;
ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, true);
le = fileref->fcb->extents.Flink;
while (le != &fileref->fcb->extents) {
extent* ext = CONTAINING_RECORD(le, extent, list_entry);
if (ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
ext->extent_data.type = EXTENT_TYPE_REGULAR;
changed = true;
}
le = le->Flink;
}
ExReleaseResourceLite(fileref->fcb->Header.Resource);
if (changed) {
fileref->fcb->extents_changed = true;
mark_fcb_dirty(fileref->fcb);
}
fileref->fcb->Header.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE;
}
#ifdef DEBUG_FCB_REFCOUNTS
LONG oc = InterlockedIncrement(&fileref->open_count);
ERR("fileref %p: open_count now %i\n", fileref, oc);
#else
InterlockedIncrement(&fileref->open_count);
#endif
InterlockedIncrement(&Vcb->open_files);
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) { PFILE_OBJECT FileObject, UNICODE_STRING* fn, ULONG options, PIRP Irp, LIST_ENTRY* rollback) {
NTSTATUS Status; NTSTATUS Status;
file_ref* sf; file_ref* sf;
bool readonly; bool readonly;
ccb* ccb;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) { if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) {
@ -3675,6 +4011,12 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO
Status = Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED : STATUS_ACCESS_DENIED; Status = Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED : STATUS_ACCESS_DENIED;
goto end; 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)) { if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT)) {
@ -3716,6 +4058,8 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO
} }
if (fileref->open_count > 0) { if (fileref->open_count > 0) {
oplock_context* ctx;
Status = IoCheckShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, false); Status = IoCheckShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, false);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
@ -3727,296 +4071,37 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO
goto end; 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); IoUpdateShareAccess(FileObject, &fileref->fcb->share_access);
} else } else
IoSetShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access); IoSetShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
if (*granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) { Status = open_file3(Vcb, Irp, *granted_access, fileref, rollback);
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 (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) {
ULONG defda, oldatts, filter;
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) {
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;
}
} else {
Status = truncate_file(fileref->fcb, 0, Irp, rollback);
if (!NT_SUCCESS(Status)) {
ERR("truncate_file returned %08lx\n", Status);
goto end2;
}
}
if (Irp->Overlay.AllocationSize.QuadPart > 0) {
Status = extend_file(fileref->fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, true, NULL, rollback);
if (!NT_SUCCESS(Status)) {
ERR("extend_file returned %08lx\n", Status);
goto end2;
}
}
if (!fileref->fcb->ads) {
LIST_ENTRY* le;
if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
ULONG offset;
FILE_FULL_EA_INFORMATION* eainfo;
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;
}
fileref->fcb->ealen = 4;
// capitalize EA name
eainfo = Irp->AssociatedIrp.SystemBuffer;
do {
STRING s;
s.Length = s.MaximumLength = eainfo->EaNameLength;
s.Buffer = eainfo->EaName;
RtlUpperString(&s, &s);
fileref->fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
if (eainfo->NextEntryOffset == 0)
break;
eainfo = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)eainfo) + eainfo->NextEntryOffset);
} while (true);
if (fileref->fcb->ea_xattr.Buffer)
ExFreePool(fileref->fcb->ea_xattr.Buffer);
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;
}
fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = (USHORT)IrpSp->Parameters.Create.EaLength;
RtlCopyMemory(fileref->fcb->ea_xattr.Buffer, Irp->AssociatedIrp.SystemBuffer, fileref->fcb->ea_xattr.Length);
} else {
if (fileref->fcb->ea_xattr.Length > 0) {
ExFreePool(fileref->fcb->ea_xattr.Buffer);
fileref->fcb->ea_xattr.Buffer = NULL;
fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = 0;
fileref->fcb->ea_changed = true;
fileref->fcb->ealen = 0;
}
}
// remove streams and send notifications
le = fileref->fcb->dir_children_index.Flink;
while (le != &fileref->fcb->dir_children_index) {
dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
LIST_ENTRY* le2 = le->Flink;
if (dc->index == 0) {
if (!dc->fileref) {
file_ref* fr2;
Status = open_fileref_child(Vcb, fileref, &dc->name, true, true, true, PagedPool, &fr2, NULL);
if (!NT_SUCCESS(Status))
WARN("open_fileref_child returned %08lx\n", Status);
}
if (dc->fileref) {
queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name);
Status = delete_fileref(dc->fileref, NULL, false, NULL, rollback);
if (!NT_SUCCESS(Status)) {
ERR("delete_fileref returned %08lx\n", Status);
goto end2;
}
}
} else
break;
le = le2;
}
}
KeQuerySystemTime(&time);
win_time_to_unix(time, &now);
filter = FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
if (fileref->fcb->ads) {
fileref->parent->fcb->inode_item.st_mtime = now;
fileref->parent->fcb->inode_item_changed = true;
mark_fcb_dirty(fileref->parent->fcb);
queue_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name);
} else {
mark_fcb_dirty(fileref->fcb);
oldatts = fileref->fcb->atts;
defda = get_file_attributes(Vcb, fileref->fcb->subvol, fileref->fcb->inode, fileref->fcb->type,
fileref->dc && fileref->dc->name.Length >= sizeof(WCHAR) && fileref->dc->name.Buffer[0] == '.', true, Irp);
if (RequestedDisposition == FILE_SUPERSEDE)
fileref->fcb->atts = IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
else
fileref->fcb->atts |= IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
if (fileref->fcb->atts != oldatts) {
fileref->fcb->atts_changed = true;
fileref->fcb->atts_deleted = IrpSp->Parameters.Create.FileAttributes == defda;
filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
}
fileref->fcb->inode_item.transid = Vcb->superblock.generation;
fileref->fcb->inode_item.sequence++;
fileref->fcb->inode_item.st_ctime = now;
fileref->fcb->inode_item.st_mtime = now;
fileref->fcb->inode_item_changed = true;
queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
}
} else {
if (options & FILE_NO_EA_KNOWLEDGE && fileref->fcb->ea_xattr.Length > 0) {
FILE_FULL_EA_INFORMATION* ffei = (FILE_FULL_EA_INFORMATION*)fileref->fcb->ea_xattr.Buffer;
do {
if (ffei->Flags & FILE_NEED_EA) {
WARN("returning STATUS_ACCESS_DENIED as no EA knowledge\n");
Status = STATUS_ACCESS_DENIED;
goto end2;
}
if (ffei->NextEntryOffset == 0)
break;
ffei = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)ffei) + ffei->NextEntryOffset);
} while (true);
}
}
FileObject->FsContext = fileref->fcb;
ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG);
if (!ccb) {
ERR("out of memory\n");
Status = STATUS_INSUFFICIENT_RESOURCES;
goto end2;
}
RtlZeroMemory(ccb, sizeof(*ccb));
ccb->NodeType = BTRFS_NODE_TYPE_CCB;
ccb->NodeSize = sizeof(*ccb);
ccb->disposition = RequestedDisposition;
ccb->options = options;
ccb->query_dir_offset = 0;
RtlInitUnicodeString(&ccb->query_string, NULL);
ccb->has_wildcard = false;
ccb->specific_file = false;
ccb->access = *granted_access;
ccb->case_sensitive = IrpSp->Flags & SL_CASE_SENSITIVE;
ccb->reserving = false;
ccb->lxss = called_from_lxss();
ccb->fileref = fileref;
FileObject->FsContext2 = ccb;
FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
switch (RequestedDisposition) {
case FILE_SUPERSEDE:
Irp->IoStatus.Information = FILE_SUPERSEDED;
break;
case FILE_OPEN:
case FILE_OPEN_IF:
Irp->IoStatus.Information = FILE_OPENED;
break;
case FILE_OVERWRITE:
case FILE_OVERWRITE_IF:
Irp->IoStatus.Information = FILE_OVERWRITTEN;
break;
}
// Make sure paging files don't have any extents marked as being prealloc,
// as this would mean we'd have to lock exclusively when writing.
if (IrpSp->Flags & SL_OPEN_PAGING_FILE) {
LIST_ENTRY* le;
bool changed = false;
ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, true);
le = fileref->fcb->extents.Flink;
while (le != &fileref->fcb->extents) {
extent* ext = CONTAINING_RECORD(le, extent, list_entry);
if (ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
ext->extent_data.type = EXTENT_TYPE_REGULAR;
changed = true;
}
le = le->Flink;
}
ExReleaseResourceLite(fileref->fcb->Header.Resource);
if (changed) {
fileref->fcb->extents_changed = true;
mark_fcb_dirty(fileref->fcb);
}
fileref->fcb->Header.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE;
}
#ifdef DEBUG_FCB_REFCOUNTS
LONG oc = InterlockedIncrement(&fileref->open_count);
ERR("fileref %p: open_count now %i\n", fileref, oc);
#else
InterlockedIncrement(&fileref->open_count);
#endif
InterlockedIncrement(&Vcb->open_files);
Status = STATUS_SUCCESS;
end2:
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
IoRemoveShareAccess(FileObject, &fileref->fcb->share_access); 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_id == fcb->inode) {
if (tp.item->key.obj_type == TYPE_INODE_REF) { if (tp.item->key.obj_type == TYPE_INODE_REF) {
INODE_REF* ir = (INODE_REF*)tp.item->data; 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) { 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"); 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; return STATUS_INTERNAL_ERROR;
} }
#ifndef __REACTOS__
ULONG stringlen; ULONG stringlen;
#endif
Status = utf8_to_utf16(NULL, 0, &stringlen, ir->name, ir->n); Status = utf8_to_utf16(NULL, 0, &stringlen, ir->name, ir->n);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
@ -4156,9 +4236,6 @@ NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
break; break;
} else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) { } else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
INODE_EXTREF* ier = (INODE_EXTREF*)tp.item->data; 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) { 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"); 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; return STATUS_INTERNAL_ERROR;
} }
#ifndef __REACTOS__
ULONG stringlen; ULONG stringlen;
#endif
Status = utf8_to_utf16(NULL, 0, &stringlen, ier->name, ier->n); Status = utf8_to_utf16(NULL, 0, &stringlen, ier->name, ier->n);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
@ -4601,11 +4676,9 @@ loaded:
goto exit; goto exit;
} }
if (NT_SUCCESS(Status)) { // file already exists if (NT_SUCCESS(Status)) // file already exists
Status = open_file2(Vcb, RequestedDisposition, pool_type, fileref, &granted_access, FileObject, &fn, options, Irp, rollback); Status = open_file2(Vcb, RequestedDisposition, fileref, &granted_access, FileObject, &fn, options, Irp, rollback);
if (!NT_SUCCESS(Status)) else {
goto exit;
} else {
file_ref* existing_file = NULL; file_ref* existing_file = NULL;
Status = file_create(Irp, Vcb, FileObject, related, loaded_related, &fn, RequestedDisposition, options, &existing_file, rollback); 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 if (Status == STATUS_OBJECT_NAME_COLLISION) { // already exists
fileref = existing_file; fileref = existing_file;
Status = open_file2(Vcb, RequestedDisposition, pool_type, fileref, &granted_access, FileObject, &fn, options, Irp, rollback); Status = open_file2(Vcb, RequestedDisposition, fileref, &granted_access, FileObject, &fn, options, Irp, rollback);
if (!NT_SUCCESS(Status))
goto exit;
} else { } else {
Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0; Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0;
granted_access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess; granted_access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
@ -4928,7 +4999,11 @@ NTSTATUS __stdcall drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
exit: exit:
Irp->IoStatus.Status = Status; 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); TRACE("create returning %08lx\n", Status);

View file

@ -499,6 +499,50 @@ static BOOLEAN __stdcall fast_io_unlock_all_by_key(PFILE_OBJECT FileObject, PVOI
return true; 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) { void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
RtlZeroMemory(&FastIoDispatch, sizeof(FastIoDispatch)); RtlZeroMemory(&FastIoDispatch, sizeof(FastIoDispatch));
@ -513,6 +557,8 @@ void init_fast_io_dispatch(FAST_IO_DISPATCH** fiod) {
FastIoDispatch.FastIoUnlockSingle = fast_io_unlock_single; FastIoDispatch.FastIoUnlockSingle = fast_io_unlock_single;
FastIoDispatch.FastIoUnlockAll = fast_io_unlock_all; FastIoDispatch.FastIoUnlockAll = fast_io_unlock_all;
FastIoDispatch.FastIoUnlockAllByKey = fast_io_unlock_all_by_key; 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.FastIoQueryNetworkOpenInfo = fast_io_query_network_open_info;
FastIoDispatch.AcquireForModWrite = fast_io_acquire_for_mod_write; FastIoDispatch.AcquireForModWrite = fast_io_acquire_for_mod_write;
FastIoDispatch.MdlRead = FsRtlMdlReadDev; FastIoDispatch.MdlRead = FsRtlMdlReadDev;

View file

@ -801,6 +801,7 @@ static NTSTATUS create_directory_fcb(device_extension* Vcb, root* r, fcb* parfcb
fcb->subvol = r; fcb->subvol = r;
fcb->inode = InterlockedIncrement64(&r->lastinode); fcb->inode = InterlockedIncrement64(&r->lastinode);
fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&fcb->inode, sizeof(uint64_t));
fcb->type = BTRFS_TYPE_DIRECTORY; fcb->type = BTRFS_TYPE_DIRECTORY;
fcb->inode_item.generation = Vcb->superblock.generation; 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); RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
acquire_fcb_lock_exclusive(Vcb); acquire_fcb_lock_exclusive(Vcb);
InsertTailList(&r->fcbs, &fcb->list_entry); add_fcb_to_subvol(fcb);
InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all); InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
r->fcbs_version++; r->fcbs_version++;
release_fcb_lock(Vcb); release_fcb_lock(Vcb);
@ -884,6 +885,68 @@ static NTSTATUS create_directory_fcb(device_extension* Vcb, root* r, fcb* parfcb
return STATUS_SUCCESS; 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) { 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; NTSTATUS Status;
LIST_ENTRY move_list, *le; 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)) { if (!NT_SUCCESS(Status)) {
ERR("add_children_to_move_list returned %08lx\n", Status); ERR("add_children_to_move_list returned %08lx\n", Status);
ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
goto end; 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->fileref->fcb->inode != SUBVOL_ROOT_INODE && me->fileref->fcb != fileref->fcb->Vcb->dummy_fcb) {
if (!me->dummyfcb) { if (!me->dummyfcb) {
ULONG defda; ULONG defda;
bool inserted = false;
LIST_ENTRY* le3;
ExAcquireResourceExclusiveLite(me->fileref->fcb->Header.Resource, true); 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->subvol = me->fileref->fcb->subvol;
me->dummyfcb->inode = me->fileref->fcb->inode; me->dummyfcb->inode = me->fileref->fcb->inode;
me->dummyfcb->hash = me->fileref->fcb->hash;
if (!me->dummyfcb->ads) { if (!me->dummyfcb->ads) {
me->dummyfcb->sd_dirty = me->fileref->fcb->sd_dirty; 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->subvol = destdir->fcb->subvol;
me->fileref->fcb->inode = InterlockedIncrement64(&destdir->fcb->subvol->lastinode); 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; me->fileref->fcb->inode_item.st_nlink = 1;
defda = get_file_attributes(me->fileref->fcb->Vcb, me->fileref->fcb->subvol, me->fileref->fcb->inode, defda = get_file_attributes(me->fileref->fcb->Vcb, me->fileref->fcb->subvol, me->fileref->fcb->inode,
@ -1042,32 +1106,21 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb, file_ref* destd
le2 = le2->Flink; le2 = le2->Flink;
} }
add_fcb_to_subvol(me->dummyfcb);
remove_fcb_from_subvol(me->fileref->fcb);
add_fcb_to_subvol(me->fileref->fcb);
} else { } else {
me->fileref->fcb->subvol = me->parent->fileref->fcb->subvol; me->fileref->fcb->subvol = me->parent->fileref->fcb->subvol;
me->fileref->fcb->inode = me->parent->fileref->fcb->inode; me->fileref->fcb->inode = me->parent->fileref->fcb->inode;
me->fileref->fcb->hash = me->parent->fileref->fcb->hash;
// put stream after parent in FCB list
InsertHeadList(&me->parent->fileref->fcb->list_entry, &me->fileref->fcb->list_entry);
} }
me->fileref->fcb->created = true; 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;
}
le3 = le3->Flink;
}
if (!inserted)
InsertTailList(&destdir->fcb->subvol->fcbs, &me->fileref->fcb->list_entry);
InsertTailList(&me->fileref->fcb->Vcb->all_fcbs, &me->dummyfcb->list_entry_all); InsertTailList(&me->fileref->fcb->Vcb->all_fcbs, &me->dummyfcb->list_entry_all);
while (!IsListEmpty(&me->fileref->fcb->hardlinks)) { while (!IsListEmpty(&me->fileref->fcb->hardlinks)) {
@ -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)) 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; 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); me->dummyfileref->oldutf8.Buffer = ExAllocatePoolWithTag(PagedPool, me->fileref->dc->utf8.Length, ALLOC_TAG);
if (!me->dummyfileref->oldutf8.Buffer) { if (!me->dummyfileref->oldutf8.Buffer) {
ERR("out of memory\n"); 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->Vcb = Vcb;
dummyfcb->subvol = fileref->fcb->subvol; dummyfcb->subvol = fileref->fcb->subvol;
dummyfcb->inode = fileref->fcb->inode; dummyfcb->inode = fileref->fcb->inode;
dummyfcb->hash = fileref->fcb->hash;
dummyfcb->adsxattr = fileref->fcb->adsxattr; dummyfcb->adsxattr = fileref->fcb->adsxattr;
dummyfcb->adshash = fileref->fcb->adshash; dummyfcb->adshash = fileref->fcb->adshash;
dummyfcb->ads = true; dummyfcb->ads = true;
dummyfcb->deleted = 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? // FIXME - dummyfileref as well?
mark_fcb_dirty(dummyfcb); mark_fcb_dirty(dummyfcb);
@ -1839,9 +1899,10 @@ static NTSTATUS rename_stream(device_extension* Vcb, file_ref* fileref, ccb* ccb
if (fn.Length == 0) if (fn.Length == 0)
return rename_stream_to_file(Vcb, fileref, ccb, flags, Irp, rollback); 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); 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) { 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->Vcb = Vcb;
dummyfcb->subvol = fileref->fcb->subvol; dummyfcb->subvol = fileref->fcb->subvol;
dummyfcb->inode = fileref->fcb->inode; dummyfcb->inode = fileref->fcb->inode;
dummyfcb->hash = fileref->fcb->hash;
dummyfcb->adsxattr = fileref->fcb->adsxattr; dummyfcb->adsxattr = fileref->fcb->adsxattr;
dummyfcb->adshash = fileref->fcb->adshash; dummyfcb->adshash = fileref->fcb->adshash;
dummyfcb->ads = true; dummyfcb->ads = true;
dummyfcb->deleted = 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); mark_fcb_dirty(dummyfcb);
free_fcb(dummyfcb); free_fcb(dummyfcb);
@ -2078,9 +2146,10 @@ static NTSTATUS rename_file_to_stream(device_extension* Vcb, file_ref* fileref,
return STATUS_INVALID_PARAMETER; 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); 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) { 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; SECURITY_SUBJECT_CONTEXT subjcont;
ACCESS_MASK access; ACCESS_MASK access;
ULONG flags; ULONG flags;
#ifdef __REACTOS__
unsigned int i;
#endif
InitializeListHead(&rollback); 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--) { for (i = fnlen - 1; i >= 0; i--) {
if (fri->FileName[i] == '\\' || fri->FileName[i] == '/') { if (fri->FileName[i] == '\\' || fri->FileName[i] == '/') {
fn = &fri->FileName[i+1]; fn = &fri->FileName[i+1];
fnlen = (fri->FileNameLength / sizeof(WCHAR)) - i - 1; fnlen -= i + 1;
break; 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); TRACE("fnus = %.*S\n", (int)(fnus.Length / sizeof(WCHAR)), fnus.Buffer);
#ifndef __REACTOS__
for (unsigned int i = 0 ; i < fnus.Length / sizeof(WCHAR); i++) { 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] == ':') { if (fnus.Buffer[i] == ':') {
TRACE("colon in filename\n"); TRACE("colon in filename\n");
Status = STATUS_OBJECT_NAME_INVALID; Status = STATUS_OBJECT_NAME_INVALID;

View file

@ -1150,6 +1150,7 @@ static NTSTATUS allocate_cache_chunk(device_extension* Vcb, chunk* c, bool* chan
c->cache->subvol = Vcb->root_root; c->cache->subvol = Vcb->root_root;
c->cache->inode = InterlockedIncrement64(&Vcb->root_root->lastinode); 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->type = BTRFS_TYPE_FILE;
c->cache->created = true; 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; c->cache->extents_changed = true;
InsertTailList(&Vcb->all_fcbs, &c->cache->list_entry_all); InsertTailList(&Vcb->all_fcbs, &c->cache->list_entry_all);
add_fcb_to_subvol(c->cache);
Status = flush_fcb(c->cache, true, batchlist, Irp); Status = flush_fcb(c->cache, true, batchlist, Irp);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("flush_fcb returned %08lx\n", Status); ERR("flush_fcb returned %08lx\n", Status);

View file

@ -601,8 +601,9 @@ static NTSTATUS create_snapshot(device_extension* Vcb, PFILE_OBJECT FileObject,
if (is_subvol_readonly(fcb->subvol, Irp)) if (is_subvol_readonly(fcb->subvol, Irp))
return STATUS_ACCESS_DENIED; return STATUS_ACCESS_DENIED;
if (!is_file_name_valid(&nameus, posix, false)) Status = check_file_name_valid(&nameus, posix, false);
return STATUS_OBJECT_NAME_INVALID; if (!NT_SUCCESS(Status))
return Status;
utf8.Buffer = NULL; 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.Length = nameus.MaximumLength = bcs->namelen;
nameus.Buffer = bcs->name; nameus.Buffer = bcs->name;
if (!is_file_name_valid(&nameus, bcs->posix, false)) Status = check_file_name_valid(&nameus, bcs->posix, false);
return STATUS_OBJECT_NAME_INVALID; if (!NT_SUCCESS(Status))
return Status;
utf8.Buffer = NULL; utf8.Buffer = NULL;
@ -961,8 +963,9 @@ static NTSTATUS create_subvol(device_extension* Vcb, PFILE_OBJECT FileObject, vo
rootfcb->Vcb = Vcb; rootfcb->Vcb = Vcb;
rootfcb->subvol = r; rootfcb->subvol = r;
rootfcb->inode = SUBVOL_ROOT_INODE;
rootfcb->type = BTRFS_TYPE_DIRECTORY; 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.generation = Vcb->superblock.generation;
rootfcb->inode_item.transid = 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; rootfcb->inode_item_changed = true;
acquire_fcb_lock_exclusive(Vcb); acquire_fcb_lock_exclusive(Vcb);
InsertTailList(&r->fcbs, &rootfcb->list_entry); add_fcb_to_subvol(rootfcb);
InsertTailList(&Vcb->all_fcbs, &rootfcb->list_entry_all); InsertTailList(&Vcb->all_fcbs, &rootfcb->list_entry_all);
r->fcbs_version++; r->fcbs_version++;
release_fcb_lock(Vcb); release_fcb_lock(Vcb);
@ -3693,6 +3696,44 @@ end:
return Status; 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) { static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data, ULONG datalen, PIRP Irp) {
NTSTATUS Status; NTSTATUS Status;
btrfs_mknod* bmn; btrfs_mknod* bmn;
@ -3705,7 +3746,6 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
dir_child* dc; dir_child* dc;
LARGE_INTEGER time; LARGE_INTEGER time;
BTRFS_TIME now; BTRFS_TIME now;
LIST_ENTRY* lastle;
ANSI_STRING utf8; ANSI_STRING utf8;
ULONG len, i; ULONG len, i;
SECURITY_SUBJECT_CONTEXT subjcont; SECURITY_SUBJECT_CONTEXT subjcont;
@ -3925,35 +3965,33 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT FileObject, void* data
acquire_fcb_lock_exclusive(Vcb); acquire_fcb_lock_exclusive(Vcb);
if (bmn->inode == 0) { if (bmn->inode == 0) {
inode = InterlockedIncrement64(&parfcb->subvol->lastinode); fcb->inode = InterlockedIncrement64(&parfcb->subvol->lastinode);
lastle = parfcb->subvol->fcbs.Blink; fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&fcb->inode, sizeof(uint64_t));
} else { } else {
if (bmn->inode > (uint64_t)parfcb->subvol->lastinode) { if (bmn->inode > (uint64_t)parfcb->subvol->lastinode) {
inode = parfcb->subvol->lastinode = bmn->inode; fcb->inode = parfcb->subvol->lastinode = bmn->inode;
lastle = parfcb->subvol->fcbs.Blink; fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&fcb->inode, sizeof(uint64_t));
} else { } 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;; Status = check_inode_used(Vcb, subvol, bmn->inode, hash, Irp);
while (le != &parfcb->subvol->fcbs) { if (NT_SUCCESS(Status)) { // STATUS_SUCCESS means inode found
struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry); release_fcb_lock(Vcb);
ExReleaseResourceLite(&Vcb->fileref_lock);
if (fcb2->inode == bmn->inode && !fcb2->deleted) { WARN("inode collision\n");
release_fcb_lock(Vcb); Status = STATUS_INVALID_PARAMETER;
ExReleaseResourceLite(&Vcb->fileref_lock); goto end;
} else if (Status != STATUS_NOT_FOUND) {
ERR("check_inode_used returned %08lx\n", Status);
WARN("inode collision\n"); release_fcb_lock(Vcb);
Status = STATUS_INVALID_PARAMETER; ExReleaseResourceLite(&Vcb->fileref_lock);
goto end; goto end;
} else if (fcb2->inode > bmn->inode) {
lastle = fcb2->list_entry.Blink;
break;
}
le = le->Flink;
} }
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); 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); InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
if (bmn->type == BTRFS_TYPE_DIRECTORY) if (bmn->type == BTRFS_TYPE_DIRECTORY)
@ -4924,10 +4962,10 @@ static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* Pirp) {
ExAcquireResourceSharedLite(&Vcb->tree_lock, true); 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 || 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) { fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2 || oplock_request) {
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
if (shared_request) { if (shared_request) {
if (fcb->type == BTRFS_TYPE_FILE) { if (fcb->type == BTRFS_TYPE_FILE) {
if (fFsRtlCheckLockForOplockRequest) if (fFsRtlCheckLockForOplockRequest)
@ -4939,8 +4977,7 @@ static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* Pirp) {
} }
} else } else
oplock_count = fileref->open_count; oplock_count = fileref->open_count;
} else }
ExAcquireResourceSharedLite(fcb->Header.Resource, true);
#if (NTDDI_VERSION >= NTDDI_WIN7) #if (NTDDI_VERSION >= NTDDI_WIN7)
if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK || if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK ||

View file

@ -188,6 +188,18 @@ static NTSTATUS bus_pnp(bus_device_extension* bde, PIRP Irp) {
bool handled = false; bool handled = false;
switch (IrpSp->MinorFunction) { 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: case IRP_MN_QUERY_CAPABILITIES:
Status = bus_query_capabilities(Irp); Status = bus_query_capabilities(Irp);
handled = true; handled = true;

View file

@ -317,6 +317,11 @@ NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, cc
// FIXME - die if not file or directory // 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)) { if (buflen < sizeof(ULONG)) {
WARN("buffer was not long enough to hold tag\n"); WARN("buffer was not long enough to hold tag\n");
return STATUS_INVALID_BUFFER_SIZE; return STATUS_INVALID_BUFFER_SIZE;
@ -328,7 +333,10 @@ NTSTATUS set_reparse_point2(fcb* fcb, REPARSE_DATA_BUFFER* rdb, ULONG buflen, cc
return Status; 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 && if (fcb->type == BTRFS_TYPE_FILE &&
((tag == IO_REPARSE_TAG_SYMLINK && rdb->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) || tag == IO_REPARSE_TAG_LX_SYMLINK)) { ((tag == IO_REPARSE_TAG_SYMLINK && rdb->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) || tag == IO_REPARSE_TAG_LX_SYMLINK)) {

View file

@ -903,7 +903,7 @@ void __stdcall mountmgr_thread(_In_ void* context) {
break; 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); false, NULL);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
ERR("IOCTL_MOUNTMGR_QUERY_POINTS returned %08lx\n", Status); ERR("IOCTL_MOUNTMGR_QUERY_POINTS returned %08lx\n", Status);

View file

@ -95,7 +95,7 @@ void add_user_mapping(WCHAR* sidstring, ULONG sidstringlength, uint32_t uid) {
while (sidstringlength > 0) { while (sidstringlength > 0) {
val = 0; val = 0;
i = 0; i = 0;
while (sidstring[i] != '-' && i < sidstringlength) { while (i < sidstringlength && sidstring[i] != '-') {
if (sidstring[i] >= '0' && sidstring[i] <= '9') { if (sidstring[i] >= '0' && sidstring[i] <= '9') {
val *= 10; val *= 10;
val += sidstring[i] - '0'; val += sidstring[i] - '0';

View file

@ -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); Status = handle_batch_collision(Vcb, bi, tp.tree, tp.item, td, &br->items, &ignore);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("handle_batch_collision returned %08lx\n", Status); ERR("handle_batch_collision returned %08lx\n", Status);
#ifdef _DEBUG
int3;
#endif
if (td) if (td)
ExFreeToPagedLookasideList(&Vcb->tree_data_lookaside, 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); Status = handle_batch_collision(Vcb, bi2, tp.tree, td2, td, &br->items, &ignore);
if (!NT_SUCCESS(Status)) { if (!NT_SUCCESS(Status)) {
ERR("handle_batch_collision returned %08lx\n", Status); ERR("handle_batch_collision returned %08lx\n", Status);
#ifdef _DEBUG
int3;
#endif
return Status; return Status;
} }
} }

View file

@ -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); 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); ERR("insert_prealloc_extent returned %08lx\n", Status);
return Status; return Status;
} }
@ -3503,7 +3503,7 @@ NTSTATUS extend_file(fcb* fcb, file_ref* fileref, uint64_t end, bool prealloc, P
if (prealloc) { if (prealloc) {
Status = insert_prealloc_extent(fcb, 0, newalloc, rollback); 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); ERR("insert_prealloc_extent returned %08lx\n", Status);
return Status; return Status;
} }
@ -4285,16 +4285,19 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void
Status = Irp->IoStatus.Status; Status = Irp->IoStatus.Status;
goto end; goto end;
} else { } 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) { if (fCcCopyWriteEx) {
TRACE("CcCopyWriteEx(%p, %I64x, %lx, %u, %p, %p)\n", FileObject, off64, *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, wait, buf, Irp->Tail.Overlay.Thread)) { if (!fCcCopyWriteEx(FileObject, &offset, *length, true, buf, Irp->Tail.Overlay.Thread)) {
Status = STATUS_PENDING; Status = STATUS_PENDING;
goto end; goto end;
} }
TRACE("CcCopyWriteEx finished\n"); TRACE("CcCopyWriteEx finished\n");
} else { } else {
TRACE("CcCopyWrite(%p, %I64x, %lx, %u, %p)\n", FileObject, off64, *length, wait, buf); TRACE("CcCopyWrite(%p, %I64x, %lx, %u, %p)\n", FileObject, off64, *length, true, buf);
if (!CcCopyWrite(FileObject, &offset, *length, wait, buf)) { if (!CcCopyWrite(FileObject, &offset, *length, true, buf)) {
Status = STATUS_PENDING; Status = STATUS_PENDING;
goto end; goto end;
} }

View file

@ -1263,13 +1263,6 @@ static bool is_mounted_multi_device(HANDLE h, uint32_t sector_size) {
bfs = malloc(bfssize); bfs = malloc(bfssize);
Status = NtDeviceIoControlFile(h2, NULL, NULL, NULL, &iosb, IOCTL_BTRFS_QUERY_FILESYSTEMS, NULL, 0, bfs, 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); } while (Status == STATUS_BUFFER_OVERFLOW);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))