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); + + return true; } 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]; - - 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); + 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 (!get_system_root()) + return; - 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); - 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; - while (le != &pdo_list) { - LIST_ENTRY* le2; - pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension, list_entry); + 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; - 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) { - 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; + Status = IoSetDeviceInterfaceState(&pdode->vde->bus_name, true); + if (!NT_SUCCESS(Status)) + ERR("IoSetDeviceInterfaceState returned %08lx\n", Status); } - 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); - - le = le->Flink; + break; } - ExReleaseResourceLite(&pdo_list_lock); - } 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); + le = le->Flink; } - if (boot_vc) { - NTSTATUS Status; - UNICODE_STRING name; + ExReleaseResourceLite(&pdo_list_lock); - /* 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); - } - } - - 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,12 +3572,357 @@ 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, +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) { NTSTATUS Status; file_ref* sf; bool readonly; - ccb* ccb; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 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; 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)) { @@ -3716,6 +4058,8 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO } 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)) { @@ -3727,296 +4071,37 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, PO 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); - 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; - } - } + Status = open_file3(Vcb, Irp, *granted_access, fileref, rollback); - // 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)) 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,32 +1106,21 @@ 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->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; - 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); 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)) 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 (Status != STATUS_NOT_FOUND) { + ERR("check_inode_used returned %08lx\n", Status); - WARN("inode collision\n"); - Status = STATUS_INVALID_PARAMETER; - goto end; - } else if (fcb2->inode > bmn->inode) { - lastle = fcb2->list_entry.Blink; - break; - } - - 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))