https://git.reactos.org/?p=reactos.git;a=commitdiff;h=62e630de4c8c43542a04a…
commit 62e630de4c8c43542a04a848a0f2abf89e15f4ed
Author: Pierre Schweitzer <pierre(a)reactos.org>
AuthorDate: Tue Nov 12 19:32:46 2019 +0100
Commit: Pierre Schweitzer <pierre(a)reactos.org>
CommitDate: Tue Nov 12 19:35:43 2019 +0100
[BTRFS] Upgrade to 1.5
CORE-16494
---
drivers/filesystems/btrfs/balance.c | 26 +-
drivers/filesystems/btrfs/boot.c | 140 ++++-
drivers/filesystems/btrfs/btrfs.c | 523 +++++++++-------
drivers/filesystems/btrfs/btrfs.h | 1 +
drivers/filesystems/btrfs/btrfs.rc | 8 +-
drivers/filesystems/btrfs/btrfs_drv.h | 110 +++-
drivers/filesystems/btrfs/btrfsioctl.h | 1 +
drivers/filesystems/btrfs/cache.c | 24 +-
drivers/filesystems/btrfs/create.c | 157 ++++-
drivers/filesystems/btrfs/devctrl.c | 15 +
drivers/filesystems/btrfs/dirctrl.c | 4 +-
drivers/filesystems/btrfs/fastio.c | 28 +-
drivers/filesystems/btrfs/fileinfo.c | 1033 ++++++++++++++++++++++++++++++-
drivers/filesystems/btrfs/flushthread.c | 23 +-
drivers/filesystems/btrfs/fsctl.c | 207 +++++--
drivers/filesystems/btrfs/fsrtl.c | 2 +-
drivers/filesystems/btrfs/pnp.c | 56 +-
drivers/filesystems/btrfs/read.c | 5 +-
drivers/filesystems/btrfs/registry.c | 9 +-
drivers/filesystems/btrfs/reparse.c | 8 +-
drivers/filesystems/btrfs/scrub.c | 5 +-
drivers/filesystems/btrfs/search.c | 22 +
drivers/filesystems/btrfs/security.c | 12 +-
drivers/filesystems/btrfs/send.c | 5 +-
drivers/filesystems/btrfs/volume.c | 254 +++++---
drivers/filesystems/btrfs/write.c | 40 +-
media/doc/README.FSD | 2 +-
27 files changed, 2185 insertions(+), 535 deletions(-)
diff --git a/drivers/filesystems/btrfs/balance.c b/drivers/filesystems/btrfs/balance.c
index b7794125deb..1a2c6a2dc6a 100644
--- a/drivers/filesystems/btrfs/balance.c
+++ b/drivers/filesystems/btrfs/balance.c
@@ -1037,6 +1037,7 @@ static NTSTATUS
write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
tw->address = mr->new_address;
tw->length = Vcb->superblock.node_size;
tw->data = (uint8_t*)mr->data;
+ tw->allocated = false;
if (IsListEmpty(&tree_writes))
InsertTailList(&tree_writes, &tw->list_entry);
@@ -1089,6 +1090,10 @@ static NTSTATUS
write_metadata_items(_Requires_exclusive_lock_held_(_Curr_->tree
end:
while (!IsListEmpty(&tree_writes)) {
tree_write* tw = CONTAINING_RECORD(RemoveHeadList(&tree_writes), tree_write,
list_entry);
+
+ if (tw->allocated)
+ ExFreePool(tw->data);
+
ExFreePool(tw);
}
@@ -1203,6 +1208,9 @@ end:
ExFreePool(ref);
}
+ if (mr->data)
+ ExFreePool(mr->data);
+
ExFreePool(mr);
}
@@ -2187,6 +2195,9 @@ end:
ExFreePool(ref);
}
+ if (mr->data)
+ ExFreePool(mr->data);
+
ExFreePool(mr);
}
@@ -3499,6 +3510,7 @@ end:
NTSTATUS start_balance(device_extension* Vcb, void* data, ULONG length, KPROCESSOR_MODE
processor_mode) {
NTSTATUS Status;
btrfs_start_balance* bsb = (btrfs_start_balance*)data;
+ OBJECT_ATTRIBUTES oa;
uint8_t i;
if (length < sizeof(btrfs_start_balance) || !data)
@@ -3599,7 +3611,9 @@ NTSTATUS start_balance(device_extension* Vcb, void* data, ULONG
length, KPROCESS
Vcb->balance.status = STATUS_SUCCESS;
KeInitializeEvent(&Vcb->balance.event, NotificationEvent,
!Vcb->balance.paused);
- Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL,
balance_thread, Vcb);
+ InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL,
balance_thread, Vcb);
if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status);
return Status;
@@ -3613,6 +3627,7 @@ NTSTATUS
look_for_balance_item(_Requires_lock_held_(_Curr_->tree_lock) device_ex
traverse_ptr tp;
NTSTATUS Status;
BALANCE_ITEM* bi;
+ OBJECT_ATTRIBUTES oa;
int i;
searchkey.obj_id = BALANCE_ITEM_ID;
@@ -3679,7 +3694,9 @@ NTSTATUS
look_for_balance_item(_Requires_lock_held_(_Curr_->tree_lock) device_ex
Vcb->balance.status = STATUS_SUCCESS;
KeInitializeEvent(&Vcb->balance.event, NotificationEvent,
!Vcb->balance.paused);
- Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL,
balance_thread, Vcb);
+ InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL,
balance_thread, Vcb);
if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status);
return Status;
@@ -3783,6 +3800,7 @@ NTSTATUS remove_device(device_extension* Vcb, void* data, ULONG
length, KPROCESS
NTSTATUS Status;
int i;
uint64_t num_rw_devices;
+ OBJECT_ATTRIBUTES oa;
TRACE("(%p, %p, %x)\n", Vcb, data, length);
@@ -3876,7 +3894,9 @@ NTSTATUS remove_device(device_extension* Vcb, void* data, ULONG
length, KPROCESS
Vcb->balance.status = STATUS_SUCCESS;
KeInitializeEvent(&Vcb->balance.event, NotificationEvent,
!Vcb->balance.paused);
- Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL, NULL,
balance_thread, Vcb);
+ InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL, NULL,
balance_thread, Vcb);
if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status);
dev->reloc = false;
diff --git a/drivers/filesystems/btrfs/boot.c b/drivers/filesystems/btrfs/boot.c
index f73fc38b4e8..34fee170ec7 100755
--- a/drivers/filesystems/btrfs/boot.c
+++ b/drivers/filesystems/btrfs/boot.c
@@ -27,11 +27,26 @@
extern ERESOURCE pdo_list_lock;
extern LIST_ENTRY pdo_list;
+extern ERESOURCE boot_lock;
+extern PDRIVER_OBJECT drvobj;
#ifndef _MSC_VER
NTSTATUS RtlUnicodeStringPrintf(PUNICODE_STRING DestinationString, const WCHAR*
pszFormat, ...); // not in mingw
#endif
+// Not in any headers? Windbg knows about it though.
+#define DOE_START_PENDING 0x10
+
+// Just as much as we need - the version in mingw is truncated still further
+typedef struct {
+ CSHORT Type;
+ USHORT Size;
+ PDEVICE_OBJECT DeviceObject;
+ ULONG PowerFlags;
+ void* Dope;
+ ULONG ExtensionFlags;
+} DEVOBJ_EXTENSION2;
+
static bool get_system_root_partition(uint32_t* disk_num, uint32_t* partition_num) {
NTSTATUS Status;
HANDLE h;
@@ -191,6 +206,65 @@ static void change_symlink(uint32_t disk_num, uint32_t partition_num,
BTRFS_UUID
ERR("IoCreateSymbolicLink returned %08x\n", Status);
}
+static void mountmgr_notification(BTRFS_UUID* uuid) {
+ UNICODE_STRING mmdevpath;
+ NTSTATUS Status;
+ PFILE_OBJECT FileObject;
+ PDEVICE_OBJECT mountmgr;
+ 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);
+ if (!NT_SUCCESS(Status)) {
+ ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
+ return;
+ }
+
+ mmtnlen = offsetof(MOUNTMGR_TARGET_NAME, DeviceName[0]) + sizeof(BTRFS_VOLUME_PREFIX)
+ (36 * sizeof(WCHAR));
+
+ mmtn = ExAllocatePoolWithTag(NonPagedPool, mmtnlen, ALLOC_TAG);
+ if (!mmtn) {
+ ERR("out of memory\n");
+ return;
+ }
+
+ mmtn->DeviceNameLength = sizeof(BTRFS_VOLUME_PREFIX) + (36 * sizeof(WCHAR));
+
+ RtlCopyMemory(mmtn->DeviceName, BTRFS_VOLUME_PREFIX, sizeof(BTRFS_VOLUME_PREFIX) -
sizeof(WCHAR));
+
+ 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++;
+
+ if (i == 3 || i == 5 || i == 7 || i == 9) {
+ *w = L'-';
+ w++;
+ }
+ }
+
+ *w = L'}';
+
+ Status = dev_ioctl(mountmgr, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, mmtn,
mmtnlen, NULL, 0, false, NULL);
+ if (!NT_SUCCESS(Status)) {
+ ERR("IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION returned %08x\n",
Status);
+ ExFreePool(mmtn);
+ return;
+ }
+
+ ExFreePool(mmtn);
+}
+
/* 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.
@@ -205,9 +279,14 @@ void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID
Context, ULO
uint32_t disk_num, partition_num;
LIST_ENTRY* le;
bool done = false;
+ PDEVICE_OBJECT pdo_to_add = NULL;
TRACE("(%p, %p, %u)\n", DriverObject, Context, Count);
+ // wait for any PNP notifications in progress to finish
+ ExAcquireResourceExclusiveLite(&boot_lock, TRUE);
+ ExReleaseResourceLite(&boot_lock);
+
if (!get_system_root_partition(&disk_num, &partition_num))
return;
@@ -230,19 +309,76 @@ void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID
Context, ULO
if (vc->disk_num == disk_num && vc->part_num == partition_num)
{
change_symlink(disk_num, partition_num, &pdode->uuid);
done = true;
+
+ if (!pdode->vde)
+ pdo_to_add = pdode->pdo;
+
break;
}
le2 = le2->Flink;
}
- ExReleaseResourceLite(&pdode->child_lock);
+ 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);
- if (done)
break;
+ }
+
+ ExReleaseResourceLite(&pdode->child_lock);
le = le->Flink;
}
ExReleaseResourceLite(&pdo_list_lock);
+
+ // 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
+ // own call to AddDevice here as a result. We need to clear the DOE_START_PENDING
bits, or NtOpenFile
+ // will return STATUS_NO_SUCH_DEVICE.
+ if (pdo_to_add) {
+ pdo_device_extension* pdode = pdo_to_add->DeviceExtension;
+
+ AddDevice(drvobj, pdo_to_add);
+
+ // To stop Windows sneakily setting DOE_START_PENDING
+ pdode->dont_report = true;
+
+ if (pdo_to_add->DeviceObjectExtension) {
+ ((DEVOBJ_EXTENSION2*)pdo_to_add->DeviceObjectExtension)->ExtensionFlags
&= ~DOE_START_PENDING;
+
+ if (pdode && pdode->vde && pdode->vde->device)
+
((DEVOBJ_EXTENSION2*)pdode->vde->device->DeviceObjectExtension)->ExtensionFlags
&= ~DOE_START_PENDING;
+ }
+
+ mountmgr_notification(&pdode->uuid);
+ }
}
diff --git a/drivers/filesystems/btrfs/btrfs.c b/drivers/filesystems/btrfs/btrfs.c
index 2977667de9a..2080c5d70f7 100644
--- a/drivers/filesystems/btrfs/btrfs.c
+++ b/drivers/filesystems/btrfs/btrfs.c
@@ -86,6 +86,7 @@ uint32_t mount_no_trim = 0;
uint32_t mount_clear_cache = 0;
uint32_t mount_allow_degraded = 0;
uint32_t mount_readonly = 0;
+uint32_t mount_no_root_dir = 0;
uint32_t no_pnp = 0;
bool log_started = false;
UNICODE_STRING log_device, log_file, registry_path;
@@ -98,6 +99,8 @@ tIoUnregisterPlugPlayNotificationEx
fIoUnregisterPlugPlayNotificationEx;
tFsRtlGetEcpListFromIrp fFsRtlGetEcpListFromIrp;
tFsRtlGetNextExtraCreateParameter fFsRtlGetNextExtraCreateParameter;
tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer;
+tFsRtlCheckLockForOplockRequest fFsRtlCheckLockForOplockRequest;
+tFsRtlAreThereCurrentOrInProgressFileLocks fFsRtlAreThereCurrentOrInProgressFileLocks;
bool diskacc = false;
void *notification_entry = NULL, *notification_entry2 = NULL, *notification_entry3 =
NULL;
ERESOURCE pdo_list_lock, mapping_lock;
@@ -107,6 +110,7 @@ HANDLE degraded_wait_handle = NULL, mountmgr_thread_handle = NULL;
bool degraded_wait = true;
KEVENT mountmgr_thread_event;
bool shutting_down = false;
+ERESOURCE boot_lock;
#ifdef _DEBUG
PFILE_OBJECT comfo = NULL;
@@ -284,31 +288,6 @@ static void __stdcall DriverUnload(_In_ PDRIVER_OBJECT DriverObject)
{
TRACE("(%p)\n", DriverObject);
- free_cache();
-
- IoUnregisterFileSystem(DriverObject->DeviceObject);
-
- if (notification_entry2) {
- if (fIoUnregisterPlugPlayNotificationEx)
- fIoUnregisterPlugPlayNotificationEx(notification_entry2);
- else
- IoUnregisterPlugPlayNotification(notification_entry2);
- }
-
- if (notification_entry3) {
- if (fIoUnregisterPlugPlayNotificationEx)
- fIoUnregisterPlugPlayNotificationEx(notification_entry3);
- else
- IoUnregisterPlugPlayNotification(notification_entry3);
- }
-
- if (notification_entry) {
- if (fIoUnregisterPlugPlayNotificationEx)
- fIoUnregisterPlugPlayNotificationEx(notification_entry);
- else
- IoUnregisterPlugPlayNotification(notification_entry);
- }
-
dosdevice_nameW.Buffer = (WCHAR*)dosdevice_name;
dosdevice_nameW.Length = dosdevice_nameW.MaximumLength = sizeof(dosdevice_name) -
sizeof(WCHAR);
@@ -504,7 +483,6 @@ static NTSTATUS __stdcall drv_close(_In_ PDEVICE_OBJECT DeviceObject,
_In_ PIRP
IrpSp = IoGetCurrentIrpStackLocation(Irp);
- // FIXME - unmount if called for volume
// FIXME - call FsRtlNotifyUninitializeSync(&Vcb->NotifySync) if unmounting
Status = close_file(IrpSp->FileObject, Irp);
@@ -560,6 +538,8 @@ static NTSTATUS __stdcall drv_flush_buffers(_In_ PDEVICE_OBJECT
DeviceObject, _I
goto end;
}
+ FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
+
Irp->IoStatus.Information = 0;
fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
@@ -615,6 +595,8 @@ static void calculate_total_space(_In_ device_extension* Vcb, _Out_
uint64_t* to
}
#ifndef __REACTOS__
+#define INIT_UNICODE_STRING(var, val) UNICODE_STRING us##var; us##var.Buffer =
(WCHAR*)val; us##var.Length = us##var.MaximumLength = sizeof(val) - sizeof(WCHAR);
+
// This function exists because we have to lie about our FS type in certain situations.
// MPR!MprGetConnection queries the FS type, and compares it to a whitelist. If it
doesn't match,
// it will return ERROR_NO_NET_OR_BAD_PATH, which prevents UAC from working.
@@ -631,17 +613,10 @@ static bool lie_about_fs_type() {
ULONG_PTR wow64info;
#endif
- static const WCHAR mpr[] = L"MPR.DLL";
- static const WCHAR cmd[] = L"CMD.EXE";
- static const WCHAR fsutil[] = L"FSUTIL.EXE";
- UNICODE_STRING mprus, cmdus, fsutilus;
-
- mprus.Buffer = (WCHAR*)mpr;
- mprus.Length = mprus.MaximumLength = sizeof(mpr) - sizeof(WCHAR);
- cmdus.Buffer = (WCHAR*)cmd;
- cmdus.Length = cmdus.MaximumLength = sizeof(cmd) - sizeof(WCHAR);
- fsutilus.Buffer = (WCHAR*)fsutil;
- fsutilus.Length = fsutilus.MaximumLength = sizeof(fsutil) - sizeof(WCHAR);
+ INIT_UNICODE_STRING(mpr, L"MPR.DLL");
+ INIT_UNICODE_STRING(cmd, L"CMD.EXE");
+ INIT_UNICODE_STRING(fsutil, L"FSUTIL.EXE");
+ INIT_UNICODE_STRING(storsvc, L"STORSVC.DLL");
if (!PsGetCurrentProcess())
return false;
@@ -673,31 +648,40 @@ static bool lie_about_fs_type() {
LDR_DATA_TABLE_ENTRY* entry = CONTAINING_RECORD(le, LDR_DATA_TABLE_ENTRY,
InMemoryOrderLinks);
bool blacklist = false;
- if (entry->FullDllName.Length >= mprus.Length) {
+ if (entry->FullDllName.Length >= usmpr.Length) {
+ UNICODE_STRING name;
+
+ name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length
- usmpr.Length) / sizeof(WCHAR)];
+ name.Length = name.MaximumLength = usmpr.Length;
+
+ blacklist = FsRtlAreNamesEqual(&name, &usmpr, true, NULL);
+ }
+
+ if (!blacklist && entry->FullDllName.Length >= uscmd.Length) {
UNICODE_STRING name;
- name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length
- mprus.Length) / sizeof(WCHAR)];
- name.Length = name.MaximumLength = mprus.Length;
+ name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length
- uscmd.Length) / sizeof(WCHAR)];
+ name.Length = name.MaximumLength = uscmd.Length;
- blacklist = FsRtlAreNamesEqual(&name, &mprus, true, NULL);
+ blacklist = FsRtlAreNamesEqual(&name, &uscmd, true, NULL);
}
- if (!blacklist && entry->FullDllName.Length >= cmdus.Length) {
+ if (!blacklist && entry->FullDllName.Length >= usfsutil.Length) {
UNICODE_STRING name;
- name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length
- cmdus.Length) / sizeof(WCHAR)];
- name.Length = name.MaximumLength = cmdus.Length;
+ name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length
- usfsutil.Length) / sizeof(WCHAR)];
+ name.Length = name.MaximumLength = usfsutil.Length;
- blacklist = FsRtlAreNamesEqual(&name, &cmdus, true, NULL);
+ blacklist = FsRtlAreNamesEqual(&name, &usfsutil, true, NULL);
}
- if (!blacklist && entry->FullDllName.Length >= fsutilus.Length) {
+ if (!blacklist && entry->FullDllName.Length >= usstorsvc.Length) {
UNICODE_STRING name;
- name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length
- fsutilus.Length) / sizeof(WCHAR)];
- name.Length = name.MaximumLength = fsutilus.Length;
+ name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length
- usstorsvc.Length) / sizeof(WCHAR)];
+ name.Length = name.MaximumLength = usstorsvc.Length;
- blacklist = FsRtlAreNamesEqual(&name, &fsutilus, true, NULL);
+ blacklist = FsRtlAreNamesEqual(&name, &usstorsvc, true, NULL);
}
if (blacklist) {
@@ -1451,95 +1435,6 @@ end:
return Status;
}
-static WCHAR* file_desc_fcb(_In_ fcb* fcb) {
- char s[60];
- NTSTATUS Status;
- UNICODE_STRING us;
- ANSI_STRING as;
-
- if (fcb->debug_desc)
- return fcb->debug_desc;
-
- if (fcb == fcb->Vcb->volume_fcb)
- return L"volume FCB";
-
- fcb->debug_desc = ExAllocatePoolWithTag(PagedPool, 60 * sizeof(WCHAR),
ALLOC_TAG);
- if (!fcb->debug_desc)
- return L"(memory error)";
-
- // I know this is pretty hackish...
- // GCC doesn't like %llx in sprintf, and MSVC won't let us use swprintf
- // without the CRT, which breaks drivers.
-
- sprintf(s, "subvol %x, inode %x", (uint32_t)fcb->subvol->id,
(uint32_t)fcb->inode);
-
- as.Buffer = s;
- as.Length = as.MaximumLength = (USHORT)strlen(s);
-
- us.Buffer = fcb->debug_desc;
- us.MaximumLength = 60 * sizeof(WCHAR);
- us.Length = 0;
-
- Status = RtlAnsiStringToUnicodeString(&us, &as, false);
- if (!NT_SUCCESS(Status))
- return L"(RtlAnsiStringToUnicodeString error)";
-
- us.Buffer[us.Length / sizeof(WCHAR)] = 0;
-
- return fcb->debug_desc;
-}
-
-WCHAR* file_desc_fileref(_In_ file_ref* fileref) {
- NTSTATUS Status;
- UNICODE_STRING fn;
- ULONG reqlen;
-
- if (fileref->debug_desc)
- return fileref->debug_desc;
-
- fn.Length = fn.MaximumLength = 0;
- Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
- if (Status != STATUS_BUFFER_OVERFLOW)
- return L"ERROR";
-
- if (reqlen > 0xffff - sizeof(WCHAR))
- return L"(too long)";
-
- fileref->debug_desc = ExAllocatePoolWithTag(PagedPool, reqlen + sizeof(WCHAR),
ALLOC_TAG);
- if (!fileref->debug_desc)
- return L"(memory error)";
-
- fn.Buffer = fileref->debug_desc;
- fn.Length = 0;
- fn.MaximumLength = (USHORT)(reqlen + sizeof(WCHAR));
-
- Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
- if (!NT_SUCCESS(Status)) {
- ExFreePool(fileref->debug_desc);
- fileref->debug_desc = NULL;
- return L"ERROR";
- }
-
- fileref->debug_desc[fn.Length / sizeof(WCHAR)] = 0;
-
- return fileref->debug_desc;
-}
-
-_Ret_z_
-WCHAR* file_desc(_In_ PFILE_OBJECT FileObject) {
- fcb* fcb = FileObject->FsContext;
- ccb* ccb = FileObject->FsContext2;
- file_ref* fileref = ccb ? ccb->fileref : NULL;
-
- if (fcb->Header.Flags2 & FSRTL_FLAG2_IS_PAGING_FILE)
- return L"(paging file)";
-
- if (fileref)
- return file_desc_fileref(fileref);
- else
- return file_desc_fcb(fcb);
-}
-
void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
ULONG action, _In_opt_ PUNICODE_STRING stream) {
UNICODE_STRING fn;
NTSTATUS Status;
@@ -1580,7 +1475,7 @@ void send_notification_fileref(_In_ file_ref* fileref, _In_ ULONG
filter_match,
ExFreePool(fn.Buffer);
}
-void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG
action, _In_opt_ PUNICODE_STRING stream) {
+static void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_
ULONG action, _In_opt_ PUNICODE_STRING stream) {
fcb* fcb = fileref->fcb;
LIST_ENTRY* le;
NTSTATUS Status;
@@ -1661,6 +1556,61 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG
filter_match, _In_
ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
}
+typedef struct {
+ file_ref* fileref;
+ ULONG filter_match;
+ ULONG action;
+ PUNICODE_STRING stream;
+ PIO_WORKITEM work_item;
+} notification_fcb;
+
+_Function_class_(IO_WORKITEM_ROUTINE)
+static void __stdcall notification_work_item(PDEVICE_OBJECT DeviceObject, PVOID con) {
+ notification_fcb* nf = con;
+
+ UNUSED(DeviceObject);
+
+ ExAcquireResourceSharedLite(&nf->fileref->fcb->Vcb->tree_lock, TRUE);
// protect us from fileref being reaped
+
+ send_notification_fcb(nf->fileref, nf->filter_match, nf->action,
nf->stream);
+
+ free_fileref(nf->fileref);
+
+ ExReleaseResourceLite(&nf->fileref->fcb->Vcb->tree_lock);
+
+ IoFreeWorkItem(nf->work_item);
+
+ ExFreePool(nf);
+}
+
+void queue_notification_fcb(_In_ file_ref* fileref, _In_ ULONG filter_match, _In_ ULONG
action, _In_opt_ PUNICODE_STRING stream) {
+ notification_fcb* nf;
+ PIO_WORKITEM work_item;
+
+ nf = ExAllocatePoolWithTag(PagedPool, sizeof(notification_fcb), ALLOC_TAG);
+ if (!nf) {
+ ERR("out of memory\n");
+ return;
+ }
+
+ work_item = IoAllocateWorkItem(master_devobj);
+ if (!work_item) {
+ ERR("out of memory\n");
+ ExFreePool(nf);
+ return;
+ }
+
+ InterlockedIncrement(&fileref->refcount);
+
+ nf->fileref = fileref;
+ nf->filter_match = filter_match;
+ nf->action = action;
+ nf->stream = stream;
+ nf->work_item = work_item;
+
+ IoQueueWorkItem(work_item, notification_work_item, DelayedWorkQueue, nf);
+}
+
void mark_fcb_dirty(_In_ fcb* fcb) {
if (!fcb->dirty) {
#ifdef DEBUG_FCB_REFCOUNTS
@@ -1746,9 +1696,6 @@ void reap_fcb(fcb* fcb) {
if (fcb->adsdata.Buffer)
ExFreePool(fcb->adsdata.Buffer);
- if (fcb->debug_desc)
- ExFreePool(fcb->debug_desc);
-
while (!IsListEmpty(&fcb->extents)) {
LIST_ENTRY* le = RemoveHeadList(&fcb->extents);
extent* ext = CONTAINING_RECORD(le, extent, list_entry);
@@ -1795,6 +1742,7 @@ void reap_fcb(fcb* fcb) {
ExFreePool(fcb->hash_ptrs_uc);
FsRtlUninitializeFileLock(&fcb->lock);
+ FsRtlUninitializeOplock(fcb_oplock(fcb));
if (fcb->pool_type == NonPagedPool)
ExFreePool(fcb);
@@ -1842,9 +1790,6 @@ void reap_fileref(device_extension* Vcb, file_ref* fr) {
// FIXME - do delete if needed
- if (fr->debug_desc)
- ExFreePool(fr->debug_desc);
-
ExDeleteResourceLite(&fr->nonpaged->fileref_lock);
ExFreeToNPagedLookasideList(&Vcb->fileref_np_lookaside, fr->nonpaged);
@@ -1869,6 +1814,9 @@ void reap_fileref(device_extension* Vcb, file_ref* fr) {
free_fcb(fr->fcb);
+ if (fr->oldutf8.Buffer)
+ ExFreePool(fr->oldutf8.Buffer);
+
ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr);
}
@@ -1911,7 +1859,7 @@ static NTSTATUS close_file(_In_ PFILE_OBJECT FileObject, _In_ PIRP
Irp) {
ccb = FileObject->FsContext2;
- TRACE("close called for %S (fcb == %p)\n", file_desc(FileObject), fcb);
+ TRACE("close called for fcb %p)\n", fcb);
// FIXME - make sure notification gets sent if file is being deleted
@@ -1980,9 +1928,13 @@ void uninit(_In_ device_extension* Vcb) {
ExReleaseResourceLite(&Vcb->tree_lock);
}
+ if (Vcb->vde && Vcb->vde->mounted_device == Vcb->devobj)
+ Vcb->vde->mounted_device = NULL;
+
IoAcquireVpbSpinLock(&irql);
Vcb->Vpb->Flags &= ~VPB_MOUNTED;
Vcb->Vpb->Flags |= VPB_DIRECT_WRITES_ALLOWED;
+ Vcb->Vpb->DeviceObject = NULL;
IoReleaseVpbSpinLock(irql);
RemoveEntryList(&Vcb->list_entry);
@@ -2071,6 +2023,21 @@ void uninit(_In_ device_extension* Vcb) {
le = le->Flink;
}
+ while (!IsListEmpty(&Vcb->all_fcbs)) {
+ fcb* fcb = CONTAINING_RECORD(Vcb->all_fcbs.Flink, struct _fcb,
list_entry_all);
+
+ reap_fcb(fcb);
+ }
+
+ while (!IsListEmpty(&Vcb->sys_chunks)) {
+ sys_chunk* sc = CONTAINING_RECORD(RemoveHeadList(&Vcb->sys_chunks),
sys_chunk, list_entry);
+
+ if (sc->data)
+ ExFreePool(sc->data);
+
+ ExFreePool(sc);
+ }
+
while (!IsListEmpty(&Vcb->roots)) {
root* r = CONTAINING_RECORD(RemoveHeadList(&Vcb->roots), root,
list_entry);
@@ -2111,8 +2078,6 @@ void uninit(_In_ device_extension* Vcb) {
ExFreePool(c);
}
- // FIXME - free any open fcbs?
-
while (!IsListEmpty(&Vcb->devices)) {
device* dev = CONTAINING_RECORD(RemoveHeadList(&Vcb->devices), device,
list_entry);
@@ -2156,6 +2121,11 @@ void uninit(_In_ device_extension* Vcb) {
ExDeleteNPagedLookasideList(&Vcb->fcb_np_lookaside);
ZwClose(Vcb->flush_thread_handle);
+
+ if (Vcb->devobj->AttachedDevice)
+ IoDetachDevice(Vcb->devobj);
+
+ IoDeleteDevice(Vcb->devobj);
}
static NTSTATUS delete_fileref_fcb(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT
FileObject, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback) {
@@ -2422,6 +2392,8 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT
DeviceObject, _In_ PIR
goto exit;
}
+ FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
+
// We have to use the pointer to Vcb stored in the fcb, as we can receive cleanup
// messages belonging to other devices.
@@ -2435,7 +2407,7 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT
DeviceObject, _In_ PIR
fileref = ccb ? ccb->fileref : NULL;
TRACE("cleanup called for FileObject %p\n", FileObject);
- TRACE("fileref %p (%S), refcount = %u, open_count = %u\n", fileref,
file_desc(FileObject), fileref ? fileref->refcount : 0, fileref ?
fileref->open_count : 0);
+ TRACE("fileref %p, refcount = %u, open_count = %u\n", fileref, fileref
? fileref->refcount : 0, fileref ? fileref->open_count : 0);
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
@@ -2475,7 +2447,8 @@ static NTSTATUS __stdcall drv_cleanup(_In_ PDEVICE_OBJECT
DeviceObject, _In_ PIR
if (fileref && (oc == 0 || (fileref->delete_on_close &&
fileref->posix_delete))) {
if (!fcb->Vcb->removing) {
- if (oc == 0 && fileref->fcb->inode_item.st_nlink == 0
&& fileref != fcb->Vcb->root_fileref && fcb !=
fcb->Vcb->volume_fcb) { // last handle closed on POSIX-deleted file
+ if (oc == 0 && fileref->fcb->inode_item.st_nlink == 0
&& fileref != fcb->Vcb->root_fileref &&
+ fcb != fcb->Vcb->volume_fcb && !fcb->ads) { // last
handle closed on POSIX-deleted file
LIST_ENTRY rollback;
InitializeListHead(&rollback);
@@ -2647,9 +2620,8 @@ ULONG get_file_attributes(_In_
_Requires_lock_held_(_Curr_->tree_lock) device_ex
break;
}
- if (dotfile) {
+ if (dotfile || (r->id == BTRFS_ROOT_FSTREE && inode ==
SUBVOL_ROOT_INODE))
att |= FILE_ATTRIBUTE_HIDDEN;
- }
att |= FILE_ATTRIBUTE_ARCHIVE;
@@ -3883,7 +3855,7 @@ static NTSTATUS load_sys_chunks(_In_ device_extension* Vcb) {
}
_Ret_maybenull_
-static root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock)
device_extension* Vcb, _In_opt_ PIRP Irp) {
+root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock)
device_extension* Vcb, _In_opt_ PIRP Irp) {
LIST_ENTRY* le;
static const char fn[] = "default";
@@ -3974,7 +3946,7 @@ end:
void init_file_cache(_In_ PFILE_OBJECT FileObject, _In_ CC_FILE_SIZES* ccfs) {
TRACE("(%p, %p)\n", FileObject, ccfs);
- CcInitializeCacheMap(FileObject, ccfs, false, cache_callbacks, FileObject);
+ CcInitializeCacheMap(FileObject, ccfs, false, &cache_callbacks, FileObject);
if (diskacc)
fCcSetAdditionalCacheAttributesEx(FileObject, CC_ENABLE_DISK_IO_ACCOUNTING);
@@ -3998,6 +3970,7 @@ uint32_t get_num_of_processors() {
static NTSTATUS create_calc_threads(_In_ PDEVICE_OBJECT DeviceObject) {
device_extension* Vcb = DeviceObject->DeviceExtension;
+ OBJECT_ATTRIBUTES oa;
ULONG i;
Vcb->calcthreads.num_threads = get_num_of_processors();
@@ -4014,13 +3987,15 @@ static NTSTATUS create_calc_threads(_In_ PDEVICE_OBJECT
DeviceObject) {
RtlZeroMemory(Vcb->calcthreads.threads, sizeof(drv_calc_thread) *
Vcb->calcthreads.num_threads);
+ InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
for (i = 0; i < Vcb->calcthreads.num_threads; i++) {
NTSTATUS Status;
Vcb->calcthreads.threads[i].DeviceObject = DeviceObject;
KeInitializeEvent(&Vcb->calcthreads.threads[i].finished,
NotificationEvent, false);
- Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0,
NULL, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]);
+ Status = PsCreateSystemThread(&Vcb->calcthreads.threads[i].handle, 0,
&oa, NULL, NULL, calc_thread, &Vcb->calcthreads.threads[i]);
if (!NT_SUCCESS(Status)) {
ULONG j;
@@ -4201,12 +4176,7 @@ static NTSTATUS check_mount_device(_In_ PDEVICE_OBJECT
DeviceObject, _Out_ bool*
pnp_name.Length = 0;
}
- if (pnp_name.Length == 0)
- *pno_pnp = true;
- else {
- *pno_pnp = false;
- volume_arrival(drvobj, &pnp_name);
- }
+ *pno_pnp = pnp_name.Length == 0;
if (pnp_name.Buffer)
ExFreePool(pnp_name.Buffer);
@@ -4223,7 +4193,6 @@ static bool still_has_superblock(_In_ PDEVICE_OBJECT device, _In_
PFILE_OBJECT f
NTSTATUS Status;
ULONG to_read;
superblock* sb;
- PDEVICE_OBJECT device2;
if (!device)
return false;
@@ -4257,14 +4226,20 @@ static bool still_has_superblock(_In_ PDEVICE_OBJECT device, _In_
PFILE_OBJECT f
}
}
- device2 = device;
+ ObReferenceObject(device);
- do {
- device2->Flags &= ~DO_VERIFY_VOLUME;
- device2 = IoGetLowerDeviceObject(device2);
- } while (device2);
+ while (device) {
+ PDEVICE_OBJECT device2 = IoGetLowerDeviceObject(device);
+
+ device->Flags &= ~DO_VERIFY_VOLUME;
+
+ ObDereferenceObject(device);
+
+ device = device2;
+ }
ExFreePool(sb);
+
return true;
}
@@ -4286,6 +4261,9 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_
PIRP Irp) {
pdo_device_extension* pdode = NULL;
volume_child* vc;
uint64_t readobjsize;
+ OBJECT_ATTRIBUTES oa;
+ device_extension* real_devext;
+ KIRQL irql;
TRACE("(%p, %p)\n", DeviceObject, Irp);
@@ -4297,6 +4275,12 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_
PIRP Irp) {
IrpSp = IoGetCurrentIrpStackLocation(Irp);
DeviceToMount = IrpSp->Parameters.MountVolume.DeviceObject;
+ real_devext =
IrpSp->Parameters.MountVolume.Vpb->RealDevice->DeviceExtension;
+
+ // Make sure we're not trying to mount the PDO
+ if (IrpSp->Parameters.MountVolume.Vpb->RealDevice->DriverObject == drvobj
&& real_devext->type == VCB_TYPE_PDO)
+ return STATUS_UNRECOGNIZED_VOLUME;
+
if (!is_btrfs_volume(DeviceToMount)) {
bool not_pnp = false;
@@ -4313,8 +4297,17 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_
PIRP Irp) {
pdo = DeviceToMount;
- while (IoGetLowerDeviceObject(pdo)) {
- pdo = IoGetLowerDeviceObject(pdo);
+ ObReferenceObject(pdo);
+
+ while (true) {
+ PDEVICE_OBJECT pdo2 = IoGetLowerDeviceObject(pdo);
+
+ ObDereferenceObject(pdo);
+
+ if (!pdo2)
+ break;
+ else
+ pdo = pdo2;
}
ExAcquireResourceSharedLite(&pdo_list_lock, true);
@@ -4797,7 +4790,7 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_
PIRP Irp) {
Vcb->root_file->FsContext2 = root_ccb;
_SEH2_TRY {
- CcInitializeCacheMap(Vcb->root_file,
(PCC_FILE_SIZES)(&root_fcb->Header.AllocationSize), false, cache_callbacks,
Vcb->root_file);
+ CcInitializeCacheMap(Vcb->root_file,
(PCC_FILE_SIZES)(&root_fcb->Header.AllocationSize), false, &cache_callbacks,
Vcb->root_file);
} _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
Status = _SEH2_GetExceptionCode();
goto exit;
@@ -4816,17 +4809,23 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_
PIRP Irp) {
le = le->Flink;
}
+ IoAcquireVpbSpinLock(&irql);
+
NewDeviceObject->Vpb = IrpSp->Parameters.MountVolume.Vpb;
IrpSp->Parameters.MountVolume.Vpb->DeviceObject = NewDeviceObject;
IrpSp->Parameters.MountVolume.Vpb->Flags |= VPB_MOUNTED;
NewDeviceObject->Vpb->VolumeLabelLength = 4; // FIXME
NewDeviceObject->Vpb->VolumeLabel[0] = '?';
NewDeviceObject->Vpb->VolumeLabel[1] = 0;
- NewDeviceObject->Vpb->ReferenceCount++; // FIXME - should we deref this at any
point?
+ NewDeviceObject->Vpb->ReferenceCount++;
+
+ IoReleaseVpbSpinLock(irql);
KeInitializeEvent(&Vcb->flush_thread_finished, NotificationEvent, false);
- Status = PsCreateSystemThread(&Vcb->flush_thread_handle, 0, NULL, NULL, NULL,
flush_thread, NewDeviceObject);
+ InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ Status = PsCreateSystemThread(&Vcb->flush_thread_handle, 0, &oa, NULL,
NULL, flush_thread, NewDeviceObject);
if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status);
goto exit;
@@ -4851,6 +4850,8 @@ static NTSTATUS mount_vol(_In_ PDEVICE_OBJECT DeviceObject, _In_
PIRP Irp) {
if (vde)
vde->mounted_device = NewDeviceObject;
+ Vcb->devobj = NewDeviceObject;
+
ExInitializeResourceLite(&Vcb->send_load_lock);
exit:
@@ -5166,7 +5167,7 @@ _Function_class_(DRIVER_DISPATCH)
static NTSTATUS __stdcall drv_lock_control(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP
Irp) {
NTSTATUS Status;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
- fcb* fcb = IrpSp->FileObject->FsContext;
+ fcb* fcb = IrpSp->FileObject ? IrpSp->FileObject->FsContext : NULL;
device_extension* Vcb = DeviceObject->DeviceExtension;
bool top_level;
@@ -5185,6 +5186,14 @@ static NTSTATUS __stdcall drv_lock_control(_In_ PDEVICE_OBJECT
DeviceObject, _In
TRACE("lock control\n");
+ if (!fcb) {
+ ERR("fcb was NULL\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
+
Status = FsRtlProcessFileLock(&fcb->lock, Irp, NULL);
fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
@@ -5200,55 +5209,53 @@ exit:
return Status;
}
-_Dispatch_type_(IRP_MJ_SHUTDOWN)
-_Function_class_(DRIVER_DISPATCH)
-static NTSTATUS __stdcall drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp)
{
- NTSTATUS Status;
- bool top_level;
- device_extension* Vcb = DeviceObject->DeviceExtension;
+void do_shutdown(PIRP Irp) {
LIST_ENTRY* le;
-
- FsRtlEnterFileSystem();
-
- TRACE("shutdown\n");
-
- top_level = is_top_level(Irp);
-
- if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
- Status = vol_shutdown(DeviceObject, Irp);
- goto end;
- }
-
- Status = STATUS_SUCCESS;
+ bus_device_extension* bde;
shutting_down = true;
KeSetEvent(&mountmgr_thread_event, 0, false);
le = VcbList.Flink;
while (le != &VcbList) {
- bool open_files;
LIST_ENTRY* le2 = le->Flink;
- Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
+ device_extension* Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
+ volume_device_extension* vde = Vcb->vde;
TRACE("shutting down Vcb %p\n", Vcb);
- ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
- Vcb->removing = true;
- open_files = Vcb->open_files > 0;
+ if (vde)
+ InterlockedIncrement(&vde->open_count);
- if (Vcb->need_write && !Vcb->readonly) {
- Status = do_write(Vcb, Irp);
+ dismount_volume(Vcb, true, Irp);
+
+ if (vde) {
+ NTSTATUS Status;
+ UNICODE_STRING mmdevpath;
+ PDEVICE_OBJECT mountmgr;
+ PFILE_OBJECT mountmgrfo;
+ KIRQL irql;
+
+ RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
+ Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES,
&mountmgrfo, &mountmgr);
if (!NT_SUCCESS(Status))
- ERR("do_write returned %08x\n", Status);
- }
+ ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
+ else {
+ remove_drive_letter(mountmgr, &vde->name);
+
+ ObDereferenceObject(mountmgrfo);
+ }
- free_trees(Vcb);
+ vde->removing = true;
- ExReleaseResourceLite(&Vcb->tree_lock);
+ IoAcquireVpbSpinLock(&irql);
+ vde->device->Vpb->DeviceObject = vde->device;
+ IoReleaseVpbSpinLock(irql);
- if (!open_files)
- uninit(Vcb);
+ if (InterlockedDecrement(&vde->open_count) == 0)
+ free_vol(vde);
+ }
le = le2;
}
@@ -5261,6 +5268,66 @@ static NTSTATUS __stdcall drv_shutdown(_In_ PDEVICE_OBJECT
DeviceObject, _In_ PI
}
#endif
+ IoUnregisterFileSystem(master_devobj);
+
+ if (notification_entry2) {
+ if (fIoUnregisterPlugPlayNotificationEx)
+ fIoUnregisterPlugPlayNotificationEx(notification_entry2);
+ else
+ IoUnregisterPlugPlayNotification(notification_entry2);
+
+ notification_entry2 = NULL;
+ }
+
+ if (notification_entry3) {
+ if (fIoUnregisterPlugPlayNotificationEx)
+ fIoUnregisterPlugPlayNotificationEx(notification_entry3);
+ else
+ IoUnregisterPlugPlayNotification(notification_entry3);
+
+ notification_entry3 = NULL;
+ }
+
+ if (notification_entry) {
+ if (fIoUnregisterPlugPlayNotificationEx)
+ fIoUnregisterPlugPlayNotificationEx(notification_entry);
+ else
+ IoUnregisterPlugPlayNotification(notification_entry);
+
+ notification_entry = NULL;
+ }
+
+ bde = busobj->DeviceExtension;
+
+ if (bde->attached_device)
+ IoDetachDevice(bde->attached_device);
+
+ IoDeleteDevice(busobj);
+ IoDeleteDevice(master_devobj);
+}
+
+_Dispatch_type_(IRP_MJ_SHUTDOWN)
+_Function_class_(DRIVER_DISPATCH)
+static NTSTATUS __stdcall drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PIRP Irp)
{
+ NTSTATUS Status;
+ bool top_level;
+ device_extension* Vcb = DeviceObject->DeviceExtension;
+
+ FsRtlEnterFileSystem();
+
+ TRACE("shutdown\n");
+
+ top_level = is_top_level(Irp);
+
+ if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
+ Status = vol_shutdown(DeviceObject, Irp);
+ goto end;
+ }
+
+ Status = STATUS_SUCCESS;
+
+ do_shutdown(Irp);
+
end:
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = 0;
@@ -5380,7 +5447,7 @@ exit:
return Status;
}
-bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix) {
+bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool stream) {
ULONG i;
if (us->Length < sizeof(WCHAR))
@@ -5391,7 +5458,8 @@ bool is_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix) {
for (i = 0; i < us->Length / sizeof(WCHAR); i++) {
if (us->Buffer[i] == '/' || us->Buffer[i] == 0 ||
- (!posix && (us->Buffer[i] == '<' || us->Buffer[i] ==
'>' || us->Buffer[i] == ':' || us->Buffer[i] == '"'
||
+ (!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;
}
@@ -5518,7 +5586,11 @@ static void init_serial(bool first_time) {
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
if (first_time) {
- Status = PsCreateSystemThread(&serial_thread_handle, 0, NULL, NULL, NULL,
serial_thread, NULL);
+ OBJECT_ATTRIBUTES oa;
+
+ InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ Status = PsCreateSystemThread(&serial_thread_handle, 0, &oa, NULL,
NULL, serial_thread, NULL);
if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status);
return;
@@ -5692,7 +5764,12 @@ NTSTATUS __stdcall AddDevice(PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT Physica
goto end;
}
- ExAcquireResourceSharedLite(&pdode->child_lock, true);
+ ExAcquireResourceExclusiveLite(&pdode->child_lock, true);
+
+ if (pdode->vde) { // if already done, return success
+ Status = STATUS_SUCCESS;
+ goto end2;
+ }
volname.Length = volname.MaximumLength = (sizeof(BTRFS_VOLUME_PREFIX) -
sizeof(WCHAR)) + ((36 + 1) * sizeof(WCHAR));
volname.Buffer = ExAllocatePoolWithTag(PagedPool, volname.MaximumLength, ALLOC_TAG);
// FIXME - when do we free this?
@@ -5736,6 +5813,7 @@ NTSTATUS __stdcall AddDevice(PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT Physica
vde->pdo = PhysicalDeviceObject;
vde->pdode = pdode;
vde->removing = false;
+ vde->dead = false;
vde->open_count = 0;
Status = IoRegisterDeviceInterface(PhysicalDeviceObject,
&GUID_DEVINTERFACE_VOLUME, NULL, &vde->bus_name);
@@ -5775,7 +5853,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_S
control_device_extension* cde;
bus_device_extension* bde;
HANDLE regh;
- OBJECT_ATTRIBUTES oa;
+ OBJECT_ATTRIBUTES oa, system_thread_attributes;
ULONG dispos;
InitializeListHead(&uid_map_list);
@@ -5844,12 +5922,16 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_S
RtlInitUnicodeString(&name, L"CcSetAdditionalCacheAttributesEx");
fCcSetAdditionalCacheAttributesEx =
(tCcSetAdditionalCacheAttributesEx)MmGetSystemRoutineAddress(&name);
+
+ RtlInitUnicodeString(&name, L"FsRtlCheckLockForOplockRequest");
+ fFsRtlCheckLockForOplockRequest =
(tFsRtlCheckLockForOplockRequest)MmGetSystemRoutineAddress(&name);
} else {
fPsUpdateDiskCounters = NULL;
fCcCopyReadEx = NULL;
fCcCopyWriteEx = NULL;
fCcSetAdditionalCacheAttributesEx = NULL;
fFsRtlUpdateDiskCounters = NULL;
+ fFsRtlCheckLockForOplockRequest = NULL;
}
if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_WIN7)) {
@@ -5857,8 +5939,13 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_S
RtlInitUnicodeString(&name,
L"IoUnregisterPlugPlayNotificationEx");
fIoUnregisterPlugPlayNotificationEx =
(tIoUnregisterPlugPlayNotificationEx)MmGetSystemRoutineAddress(&name);
- } else
+
+ RtlInitUnicodeString(&name,
L"FsRtlAreThereCurrentOrInProgressFileLocks");
+ fFsRtlAreThereCurrentOrInProgressFileLocks =
(tFsRtlAreThereCurrentOrInProgressFileLocks)MmGetSystemRoutineAddress(&name);
+ } else {
fIoUnregisterPlugPlayNotificationEx = NULL;
+ fFsRtlAreThereCurrentOrInProgressFileLocks = NULL;
+ }
if (WdmlibRtlIsNtDdiVersionAvailable(NTDDI_VISTA)) {
UNICODE_STRING name;
@@ -5935,11 +6022,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_S
return Status;
}
- Status = init_cache();
- if (!NT_SUCCESS(Status)) {
- ERR("init_cache returned %08x\n", Status);
- return Status;
- }
+ init_cache();
InitializeListHead(&VcbList);
ExInitializeResourceLite(&global_loading_lock);
@@ -5990,10 +6073,14 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_S
IoInvalidateDeviceRelations(bde->buspdo, BusRelations);
- Status = PsCreateSystemThread(°raded_wait_handle, 0, NULL, NULL, NULL,
degraded_wait_thread, NULL);
+ InitializeObjectAttributes(&system_thread_attributes, NULL, OBJ_KERNEL_HANDLE,
NULL, NULL);
+
+ Status = PsCreateSystemThread(°raded_wait_handle, 0,
&system_thread_attributes, NULL, NULL, degraded_wait_thread, NULL);
if (!NT_SUCCESS(Status))
WARN("PsCreateSystemThread returned %08x\n", Status);
+ ExInitializeResourceLite(&boot_lock);
+
Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(PVOID)&GUID_DEVINTERFACE_VOLUME,
DriverObject, volume_notification, DriverObject, ¬ification_entry2);
if (!NT_SUCCESS(Status))
@@ -6013,7 +6100,7 @@ NTSTATUS __stdcall DriverEntry(_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_S
KeInitializeEvent(&mountmgr_thread_event, NotificationEvent, false);
- Status = PsCreateSystemThread(&mountmgr_thread_handle, 0, NULL, NULL, NULL,
mountmgr_thread, NULL);
+ Status = PsCreateSystemThread(&mountmgr_thread_handle, 0,
&system_thread_attributes, NULL, NULL, mountmgr_thread, NULL);
if (!NT_SUCCESS(Status))
WARN("PsCreateSystemThread returned %08x\n", Status);
diff --git a/drivers/filesystems/btrfs/btrfs.h b/drivers/filesystems/btrfs/btrfs.h
index f55ef82683e..780bb5d0bab 100644
--- a/drivers/filesystems/btrfs/btrfs.h
+++ b/drivers/filesystems/btrfs/btrfs.h
@@ -52,6 +52,7 @@ static const uint64_t superblock_addrs[] = { 0x10000, 0x4000000,
0x4000000000, 0
#define BTRFS_ROOT_CHUNK 3
#define BTRFS_ROOT_DEVTREE 4
#define BTRFS_ROOT_FSTREE 5
+#define BTRFS_ROOT_TREEDIR 6
#define BTRFS_ROOT_CHECKSUM 7
#define BTRFS_ROOT_UUID 9
#define BTRFS_ROOT_FREE_SPACE 0xa
diff --git a/drivers/filesystems/btrfs/btrfs.rc b/drivers/filesystems/btrfs/btrfs.rc
index c899d599b5d..a594c6014d1 100644
--- a/drivers/filesystems/btrfs/btrfs.rc
+++ b/drivers/filesystems/btrfs/btrfs.rc
@@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,4,0,0
- PRODUCTVERSION 1,4,0,0
+ FILEVERSION 1,5,0,0
+ PRODUCTVERSION 1,5,0,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
BLOCK "080904b0"
BEGIN
VALUE "FileDescription", "WinBtrfs"
- VALUE "FileVersion", "1.4"
+ VALUE "FileVersion", "1.5"
VALUE "InternalName", "btrfs"
VALUE "LegalCopyright", "Copyright (c) Mark Harmstone
2016-19"
VALUE "OriginalFilename", "btrfs.sys"
VALUE "ProductName", "WinBtrfs"
- VALUE "ProductVersion", "1.4"
+ VALUE "ProductVersion", "1.5"
END
END
BLOCK "VarFileInfo"
diff --git a/drivers/filesystems/btrfs/btrfs_drv.h
b/drivers/filesystems/btrfs/btrfs_drv.h
index 67cb24902c7..e24e4980244 100644
--- a/drivers/filesystems/btrfs/btrfs_drv.h
+++ b/drivers/filesystems/btrfs/btrfs_drv.h
@@ -136,6 +136,12 @@ C_ASSERT(sizeof(bool) == 1);
#define finally if (1)
#endif
+#ifndef __REACTOS__
+#ifdef __GNUC__
+#define InterlockedIncrement64(a) __sync_add_and_fetch(a, 1)
+#endif
+#endif
+
#ifndef FILE_SUPPORTS_BLOCK_REFCOUNTING
#define FILE_SUPPORTS_BLOCK_REFCOUNTING 0x08000000
#endif
@@ -248,6 +254,7 @@ typedef struct {
UNICODE_STRING name_uc;
ULONG size;
struct _file_ref* fileref;
+ bool root_dir;
LIST_ENTRY list_entry_index;
LIST_ENTRY list_entry_hash;
LIST_ENTRY list_entry_hash_uc;
@@ -285,7 +292,6 @@ typedef struct _fcb {
PKTHREAD lazy_writer_thread;
ULONG atts;
SHARE_ACCESS share_access;
- WCHAR* debug_desc;
bool csum_loaded;
LIST_ENTRY extents;
ANSI_STRING reparse_xattr;
@@ -299,6 +305,7 @@ typedef struct _fcb {
bool marked_as_orphan;
bool case_sensitive;
bool case_sensitive_set;
+ OPLOCK oplock;
LIST_ENTRY dir_children_index;
LIST_ENTRY dir_children_hash;
@@ -344,7 +351,6 @@ typedef struct _file_ref {
LONG refcount;
LONG open_count;
struct _file_ref* parent;
- WCHAR* debug_desc;
dir_child* dc;
bool dirty;
@@ -652,6 +658,7 @@ typedef struct {
bool no_trim;
bool clear_cache;
bool allow_degraded;
+ bool no_root_dir;
} mount_options;
#define VCB_TYPE_FS 1
@@ -729,6 +736,7 @@ typedef struct _device_extension {
uint32_t type;
mount_options options;
PVPB Vpb;
+ PDEVICE_OBJECT devobj;
struct _volume_device_extension* vde;
LIST_ENTRY devices;
#ifdef DEBUG_CHUNK_LOCKS
@@ -846,6 +854,7 @@ typedef struct _volume_device_extension {
UNICODE_STRING bus_name;
PDEVICE_OBJECT attached_device;
bool removing;
+ bool dead;
LONG open_count;
} volume_device_extension;
@@ -855,6 +864,7 @@ typedef struct pdo_device_extension {
volume_device_extension* vde;
PDEVICE_OBJECT pdo;
bool removable;
+ bool dont_report;
uint64_t num_children;
uint64_t children_loaded;
@@ -912,6 +922,7 @@ typedef struct {
uint32_t length;
uint8_t* data;
chunk* c;
+ bool allocated;
LIST_ENTRY list_entry;
} tree_write;
@@ -1082,9 +1093,9 @@ 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);
+bool is_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_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);
#ifdef DEBUG_CHUNK_LOCKS
#define acquire_chunk_lock(c, Vcb) { ExAcquireResourceExclusiveLite(&c->lock,
true); InterlockedIncrement(&Vcb->chunk_locks_held); }
@@ -1094,9 +1105,6 @@ void send_notification_fcb(_In_ file_ref* fileref, _In_ ULONG
filter_match, _In_
#define release_chunk_lock(c, Vcb) ExReleaseResourceLite(&(c)->lock)
#endif
-_Ret_z_
-WCHAR* file_desc(_In_ PFILE_OBJECT FileObject);
-WCHAR* file_desc_fileref(_In_ file_ref* fileref);
void mark_fcb_dirty(_In_ fcb* fcb);
void mark_fileref_dirty(_In_ file_ref* fileref);
NTSTATUS delete_fileref(_In_ file_ref* fileref, _In_opt_ PFILE_OBJECT FileObject, _In_
bool make_orphan, _In_opt_ PIRP Irp, _In_ LIST_ENTRY* rollback);
@@ -1122,6 +1130,11 @@ NTSTATUS utf8_to_utf16(WCHAR* dest, ULONG dest_max, ULONG*
dest_len, char* src,
NTSTATUS utf16_to_utf8(char* dest, ULONG dest_max, ULONG* dest_len, WCHAR* src, ULONG
src_len);
uint32_t get_num_of_processors();
+_Ret_maybenull_
+root* find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock)
device_extension* Vcb, _In_opt_ PIRP Irp);
+
+void do_shutdown(PIRP Irp);
+
#ifdef _MSC_VER
#define funcname __FUNCTION__
#else
@@ -1143,6 +1156,7 @@ extern uint32_t mount_no_trim;
extern uint32_t mount_clear_cache;
extern uint32_t mount_allow_degraded;
extern uint32_t mount_readonly;
+extern uint32_t mount_no_root_dir;
extern uint32_t no_pnp;
#ifdef _DEBUG
@@ -1274,9 +1288,8 @@ void remove_volume_child(_Inout_
_Requires_exclusive_lock_held_(_Curr_->child_lo
_In_ volume_child* vc, _In_ bool skip_dev);
// in cache.c
-NTSTATUS init_cache();
-void free_cache();
-extern CACHE_MANAGER_CALLBACKS* cache_callbacks;
+void init_cache();
+extern CACHE_MANAGER_CALLBACKS cache_callbacks;
// in write.c
NTSTATUS write_file(device_extension* Vcb, PIRP Irp, bool wait, bool deferred_write);
@@ -1398,6 +1411,7 @@ void do_unlock_volume(device_extension* Vcb);
void trim_whole_device(device* dev);
void flush_subvol_fcbs(root* subvol);
bool fcb_is_inline(fcb* fcb);
+NTSTATUS dismount_volume(device_extension* Vcb, bool shutdown, PIRP Irp);
// in flushthread.c
@@ -1552,6 +1566,8 @@ NTSTATUS mountmgr_add_drive_letter(PDEVICE_OBJECT mountmgr,
PUNICODE_STRING devp
_Function_class_(DRIVER_NOTIFICATION_CALLBACK_ROUTINE)
NTSTATUS __stdcall pnp_removal(PVOID NotificationStructure, PVOID Context);
+void free_vol(volume_device_extension* vde);
+
// in scrub.c
NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode);
NTSTATUS query_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode, void* data,
ULONG length);
@@ -1564,7 +1580,7 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG
datalen, PFILE_OBJ
NTSTATUS read_send_buffer(device_extension* Vcb, PFILE_OBJECT FileObject, void* data,
ULONG datalen, ULONG_PTR* retlen, KPROCESSOR_MODE processor_mode);
// in fsrtl.c
-NTSTATUS 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
void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID Context, ULONG
Count);
@@ -1572,7 +1588,43 @@ void __stdcall check_system_root(PDRIVER_OBJECT DriverObject, PVOID
Context, ULO
// based on function in sys/sysmacros.h
#define makedev(major, minor) (((minor) & 0xFF) | (((major) & 0xFFF) << 8)
| (((uint64_t)((minor) & ~0xFF)) << 12) | (((uint64_t)((major) & ~0xFFF))
<< 32))
-#define fast_io_possible(fcb) (!FsRtlAreThereCurrentFileLocks(&fcb->lock)
&& !fcb->Vcb->readonly ? FastIoIsPossible : FastIoIsQuestionable)
+// not in mingw yet
+#ifndef _MSC_VER
+typedef struct {
+ FSRTL_COMMON_FCB_HEADER DUMMYSTRUCTNAME;
+ PFAST_MUTEX FastMutex;
+ LIST_ENTRY FilterContexts;
+ EX_PUSH_LOCK PushLock;
+ PVOID* FileContextSupportPointer;
+ union {
+ OPLOCK Oplock;
+ PVOID ReservedForRemote;
+ };
+ PVOID ReservedContext;
+} FSRTL_ADVANCED_FCB_HEADER_NEW;
+
+#define FSRTL_FCB_HEADER_V2 2
+
+#else
+#define FSRTL_ADVANCED_FCB_HEADER_NEW FSRTL_ADVANCED_FCB_HEADER
+#endif
+
+static __inline POPLOCK fcb_oplock(fcb* fcb) {
+ if (fcb->Header.Version >= FSRTL_FCB_HEADER_V2)
+ return &((FSRTL_ADVANCED_FCB_HEADER_NEW*)&fcb->Header)->Oplock;
+ else
+ return &fcb->oplock;
+}
+
+static __inline FAST_IO_POSSIBLE fast_io_possible(fcb* fcb) {
+ if (!FsRtlOplockIsFastIoPossible(fcb_oplock(fcb)))
+ return FastIoIsNotPossible;
+
+ if (!FsRtlAreThereCurrentFileLocks(&fcb->lock) &&
!fcb->Vcb->readonly)
+ return FastIoIsPossible;
+
+ return FastIoIsQuestionable;
+}
static __inline void print_open_trees(device_extension* Vcb) {
LIST_ENTRY* le = Vcb->trees.Flink;
@@ -1738,16 +1790,16 @@ static __inline uint64_t fcb_alloc_size(fcb* fcb) {
return sector_align(fcb->inode_item.st_size,
fcb->Vcb->superblock.sector_size);
}
-typedef BOOLEAN (*tPsIsDiskCountersEnabled)();
+typedef BOOLEAN (__stdcall *tPsIsDiskCountersEnabled)();
-typedef VOID (*tPsUpdateDiskCounters)(PEPROCESS Process, ULONG64 BytesRead, ULONG64
BytesWritten,
- ULONG ReadOperationCount, ULONG
WriteOperationCount, ULONG FlushOperationCount);
+typedef VOID (__stdcall *tPsUpdateDiskCounters)(PEPROCESS Process, ULONG64 BytesRead,
ULONG64 BytesWritten,
+ ULONG ReadOperationCount, ULONG
WriteOperationCount, ULONG FlushOperationCount);
-typedef BOOLEAN (*tCcCopyWriteEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset,
ULONG Length, BOOLEAN Wait,
- PVOID Buffer, PETHREAD IoIssuerThread);
+typedef BOOLEAN (__stdcall *tCcCopyWriteEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER
FileOffset, ULONG Length, BOOLEAN Wait,
+ PVOID Buffer, PETHREAD IoIssuerThread);
-typedef BOOLEAN (*tCcCopyReadEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER FileOffset,
ULONG Length, BOOLEAN Wait,
- PVOID Buffer, PIO_STATUS_BLOCK IoStatus, PETHREAD
IoIssuerThread);
+typedef BOOLEAN (__stdcall *tCcCopyReadEx)(PFILE_OBJECT FileObject, PLARGE_INTEGER
FileOffset, ULONG Length, BOOLEAN Wait,
+ PVOID Buffer, PIO_STATUS_BLOCK IoStatus,
PETHREAD IoIssuerThread);
#ifndef CC_ENABLE_DISK_IO_ACCOUNTING
#define CC_ENABLE_DISK_IO_ACCOUNTING 0x00000010
@@ -1758,22 +1810,26 @@ typedef struct _ECP_LIST ECP_LIST;
typedef struct _ECP_LIST *PECP_LIST;
#endif
-typedef VOID (*tCcSetAdditionalCacheAttributesEx)(PFILE_OBJECT FileObject, ULONG Flags);
+typedef VOID (__stdcall *tCcSetAdditionalCacheAttributesEx)(PFILE_OBJECT FileObject,
ULONG Flags);
+
+typedef VOID (__stdcall *tFsRtlUpdateDiskCounters)(ULONG64 BytesRead, ULONG64
BytesWritten);
+
+typedef NTSTATUS (__stdcall *tIoUnregisterPlugPlayNotificationEx)(PVOID
NotificationEntry);
-typedef VOID (*tFsRtlUpdateDiskCounters)(ULONG64 BytesRead, ULONG64 BytesWritten);
+typedef NTSTATUS (__stdcall *tFsRtlGetEcpListFromIrp)(PIRP Irp, PECP_LIST* EcpList);
-typedef NTSTATUS (*tIoUnregisterPlugPlayNotificationEx)(PVOID NotificationEntry);
+typedef NTSTATUS (__stdcall *tFsRtlGetNextExtraCreateParameter)(PECP_LIST EcpList, PVOID
CurrentEcpContext, LPGUID NextEcpType,
+ PVOID* NextEcpContext,
ULONG* NextEcpContextSize);
-typedef NTSTATUS (*tFsRtlGetEcpListFromIrp)(PIRP Irp, PECP_LIST* EcpList);
+typedef NTSTATUS (__stdcall *tFsRtlValidateReparsePointBuffer)(ULONG BufferLength,
PREPARSE_DATA_BUFFER ReparseBuffer);
-typedef NTSTATUS (*tFsRtlGetNextExtraCreateParameter)(PECP_LIST EcpList, PVOID
CurrentEcpContext, LPGUID NextEcpType,
- PVOID* NextEcpContext, ULONG*
NextEcpContextSize);
+typedef BOOLEAN (__stdcall *tFsRtlCheckLockForOplockRequest)(PFILE_LOCK FileLock,
PLARGE_INTEGER AllocationSize);
-typedef NTSTATUS (*tFsRtlValidateReparsePointBuffer)(ULONG BufferLength,
PREPARSE_DATA_BUFFER ReparseBuffer);
+typedef BOOLEAN (__stdcall *tFsRtlAreThereCurrentOrInProgressFileLocks)(PFILE_LOCK
FileLock);
#ifndef __REACTOS__
#ifndef _MSC_VER
-PEPROCESS PsGetThreadProcess(_In_ PETHREAD Thread); // not in mingw
+PEPROCESS __stdcall PsGetThreadProcess(_In_ PETHREAD Thread); // not in mingw
#endif
// not in DDK headers - taken from winternl.h
diff --git a/drivers/filesystems/btrfs/btrfsioctl.h
b/drivers/filesystems/btrfs/btrfsioctl.h
index e08713119c6..0ba18cf837a 100644
--- a/drivers/filesystems/btrfs/btrfsioctl.h
+++ b/drivers/filesystems/btrfs/btrfsioctl.h
@@ -36,6 +36,7 @@
#define FSCTL_BTRFS_SEND_SUBVOL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x846, METHOD_BUFFERED,
FILE_ANY_ACCESS)
#define FSCTL_BTRFS_READ_SEND_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x847,
METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
#define FSCTL_BTRFS_RESIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x848, METHOD_IN_DIRECT,
FILE_ANY_ACCESS)
+#define IOCTL_BTRFS_UNLOAD CTL_CODE(FILE_DEVICE_UNKNOWN, 0x849, METHOD_NEITHER,
FILE_ANY_ACCESS)
typedef struct {
uint64_t subvol;
diff --git a/drivers/filesystems/btrfs/cache.c b/drivers/filesystems/btrfs/cache.c
index 42ce02c03da..90b0e2a3547 100644
--- a/drivers/filesystems/btrfs/cache.c
+++ b/drivers/filesystems/btrfs/cache.c
@@ -17,7 +17,7 @@
#include "btrfs_drv.h"
-CACHE_MANAGER_CALLBACKS* cache_callbacks;
+CACHE_MANAGER_CALLBACKS cache_callbacks;
static BOOLEAN __stdcall acquire_for_lazy_write(PVOID Context, BOOLEAN Wait) {
PFILE_OBJECT FileObject = Context;
@@ -82,21 +82,9 @@ static void __stdcall release_from_read_ahead(PVOID Context) {
IoSetTopLevelIrp(NULL);
}
-NTSTATUS init_cache() {
- cache_callbacks = ExAllocatePoolWithTag(NonPagedPool,
sizeof(CACHE_MANAGER_CALLBACKS), ALLOC_TAG);
- if (!cache_callbacks) {
- ERR("out of memory\n");
- return STATUS_INSUFFICIENT_RESOURCES;
- }
-
- cache_callbacks->AcquireForLazyWrite = acquire_for_lazy_write;
- cache_callbacks->ReleaseFromLazyWrite = release_from_lazy_write;
- cache_callbacks->AcquireForReadAhead = acquire_for_read_ahead;
- cache_callbacks->ReleaseFromReadAhead = release_from_read_ahead;
-
- return STATUS_SUCCESS;
-}
-
-void free_cache() {
- ExFreePool(cache_callbacks);
+void init_cache() {
+ cache_callbacks.AcquireForLazyWrite = acquire_for_lazy_write;
+ cache_callbacks.ReleaseFromLazyWrite = release_from_lazy_write;
+ cache_callbacks.AcquireForReadAhead = acquire_for_read_ahead;
+ cache_callbacks.ReleaseFromReadAhead = release_from_read_ahead;
}
diff --git a/drivers/filesystems/btrfs/create.c b/drivers/filesystems/btrfs/create.c
index 039fe287f13..4eebef939b1 100644
--- a/drivers/filesystems/btrfs/create.c
+++ b/drivers/filesystems/btrfs/create.c
@@ -28,6 +28,9 @@ extern tFsRtlValidateReparsePointBuffer
fFsRtlValidateReparsePointBuffer;
static const WCHAR datastring[] = L"::$DATA";
+static const char root_dir[] = "$Root";
+static const WCHAR root_dir_utf16[] = L"$Root";
+
// Windows 10
#define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002
#define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100
@@ -101,6 +104,7 @@ fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) {
ExInitializeResourceLite(&fcb->nonpaged->dir_children_lock);
FsRtlInitializeFileLock(&fcb->lock, NULL, NULL);
+ FsRtlInitializeOplock(fcb_oplock(fcb));
InitializeListHead(&fcb->extents);
InitializeListHead(&fcb->hardlinks);
@@ -470,6 +474,7 @@ NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock)
device_extens
traverse_ptr tp, next_tp;
NTSTATUS Status;
ULONG num_children = 0;
+ uint64_t max_index = 2;
fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256,
ALLOC_TAG);
if (!fcb->hash_ptrs) {
@@ -538,6 +543,9 @@ NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock)
device_extens
dc->index = tp.item->key.offset;
dc->type = di->type;
dc->fileref = NULL;
+ dc->root_dir = false;
+
+ max_index = dc->index;
dc->utf8.MaximumLength = dc->utf8.Length = di->n;
dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, di->n, ALLOC_TAG);
@@ -592,6 +600,68 @@ cont:
break;
}
+ if (!Vcb->options.no_root_dir && fcb->inode == SUBVOL_ROOT_INODE) {
+ root* top_subvol;
+
+ if (Vcb->root_fileref && Vcb->root_fileref->fcb)
+ top_subvol = Vcb->root_fileref->fcb->subvol;
+ else
+ top_subvol = find_default_subvol(Vcb, NULL);
+
+ if (fcb->subvol == top_subvol && top_subvol->id !=
BTRFS_ROOT_FSTREE) {
+ dir_child* dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child),
ALLOC_TAG);
+ if (!dc) {
+ ERR("out of memory\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ dc->key.obj_id = BTRFS_ROOT_FSTREE;
+ dc->key.obj_type = TYPE_ROOT_ITEM;
+ dc->key.offset = 0;
+ dc->index = max_index + 1;
+ dc->type = BTRFS_TYPE_DIRECTORY;
+ dc->fileref = NULL;
+ dc->root_dir = true;
+
+ dc->utf8.MaximumLength = dc->utf8.Length = sizeof(root_dir) -
sizeof(char);
+ dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(root_dir) -
sizeof(char), ALLOC_TAG);
+ if (!dc->utf8.Buffer) {
+ ERR("out of memory\n");
+ ExFreePool(dc);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory(dc->utf8.Buffer, root_dir, sizeof(root_dir) -
sizeof(char));
+
+ dc->name.MaximumLength = dc->name.Length = sizeof(root_dir_utf16) -
sizeof(WCHAR);
+ dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(root_dir_utf16)
- sizeof(WCHAR), ALLOC_TAG);
+ if (!dc->name.Buffer) {
+ ERR("out of memory\n");
+ ExFreePool(dc->utf8.Buffer);
+ ExFreePool(dc);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory(dc->name.Buffer, root_dir_utf16, sizeof(root_dir_utf16) -
sizeof(WCHAR));
+
+ Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name,
true);
+ if (!NT_SUCCESS(Status)) {
+ ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
+ ExFreePool(dc->utf8.Buffer);
+ ExFreePool(dc->name.Buffer);
+ ExFreePool(dc);
+ goto cont;
+ }
+
+ dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer,
dc->name.Length);
+ dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer,
dc->name_uc.Length);
+
+ InsertTailList(&fcb->dir_children_index,
&dc->list_entry_index);
+
+ insert_dir_child_into_hash_lists(fcb, dc);
+ }
+ }
+
return STATUS_SUCCESS;
}
@@ -1239,6 +1309,9 @@ NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusive_lo
}
}
+ if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id ==
BTRFS_ROOT_FSTREE)
+ fcb->atts |= FILE_ATTRIBUTE_HIDDEN;
+
subvol->fcbs_version++;
InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
@@ -1517,7 +1590,7 @@ NTSTATUS
open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_ex
return STATUS_SUCCESS;
}
- if (!subvol || (subvol != Vcb->root_fileref->fcb->subvol &&
inode == SUBVOL_ROOT_INODE && subvol->parent != sf->fcb->subvol->id))
{
+ if (!subvol || (subvol != Vcb->root_fileref->fcb->subvol &&
inode == SUBVOL_ROOT_INODE && subvol->parent != sf->fcb->subvol->id
&& !dc->root_dir)) {
fcb = Vcb->dummy_fcb;
InterlockedIncrement(&fcb->refcount);
} else {
@@ -1639,8 +1712,8 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusiv
}
if (dir->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length <
sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
- WARN("passed related fileref which isn't a directory (%S) (fnus =
%.*S)\n",
- file_desc_fileref(related), fnus->Length / sizeof(WCHAR),
fnus->Buffer);
+ WARN("passed related fileref which isn't a directory (fnus =
%.*S)\n",
+ fnus->Length / sizeof(WCHAR), fnus->Buffer);
return STATUS_OBJECT_PATH_NOT_FOUND;
}
@@ -1690,7 +1763,7 @@ NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock)
_Requires_exclusiv
bool cs = case_sensitive;
if (!cs) {
- if (streampart)
+ if (streampart && sf->parent)
cs = sf->parent->fcb->case_sensitive;
else
cs = sf->fcb->case_sensitive;
@@ -2223,7 +2296,7 @@ static NTSTATUS file_create2(_In_ PIRP Irp,
_Requires_exclusive_lock_held_(_Curr
#ifdef DEBUG_FCB_REFCOUNTS
rc = InterlockedIncrement(&parfileref->fcb->refcount);
- WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc,
file_desc_fileref(parfileref));
+ WARN("fcb %p: refcount now %i\n", parfileref->fcb, rc);
#else
InterlockedIncrement(&parfileref->fcb->refcount);
#endif
@@ -2441,9 +2514,9 @@ static NTSTATUS file_create2(_In_ PIRP Irp,
_Requires_exclusive_lock_held_(_Curr
}
#ifndef __REACTOS__
- UINT32 dc_hash = calc_crc32c(0xffffffff, (UINT8*)fpusuc.Buffer, fpusuc.Length);
+ uint32_t dc_hash = calc_crc32c(0xffffffff, (uint8_t*)fpusuc.Buffer,
fpusuc.Length);
#else
- dc_hash = calc_crc32c(0xffffffff, (UINT8*)fpusuc.Buffer, fpusuc.Length);
+ dc_hash = calc_crc32c(0xffffffff, (uint8_t*)fpusuc.Buffer, fpusuc.Length);
#endif
if (parfileref->fcb->hash_ptrs_uc[dc_hash >> 24]) {
@@ -2512,7 +2585,7 @@ static NTSTATUS file_create2(_In_ PIRP Irp,
_Requires_exclusive_lock_held_(_Curr
*pfr = fileref;
- TRACE("created new file %S in subvol %I64x, inode %I64x\n",
file_desc_fileref(fileref), fcb->subvol->id, fcb->inode);
+ TRACE("created new file in subvol %I64x, inode %I64x\n",
fcb->subvol->id, fcb->inode);
return STATUS_SUCCESS;
}
@@ -2557,7 +2630,7 @@ 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))
+ if (!is_file_name_valid(fpus, false, true))
return STATUS_OBJECT_NAME_INVALID;
fpus2.Length = fpus2.MaximumLength = fpus->Length;
@@ -2590,7 +2663,7 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
return Status;
} else if (Status != STATUS_OBJECT_NAME_COLLISION) {
send_notification_fileref(newpar, options & FILE_DIRECTORY_FILE ?
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL);
- send_notification_fcb(newpar->parent, FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_ACTION_MODIFIED, NULL);
+ queue_notification_fcb(newpar->parent, FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_ACTION_MODIFIED, NULL);
}
ExFreePool(fpus2.Buffer);
@@ -2655,7 +2728,7 @@ static NTSTATUS
create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_
#ifdef DEBUG_FCB_REFCOUNTS
rc = InterlockedIncrement(&parfileref->fcb->refcount);
- WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc,
file_desc_fileref(parfileref));
+ WARN("fcb %p: refcount now %i\n", parfileref->fcb, rc);
#else
InterlockedIncrement(&parfileref->fcb->refcount);
#endif
@@ -2920,9 +2993,17 @@ static NTSTATUS file_create(PIRP Irp,
_Requires_lock_held_(_Curr_->tree_lock) _R
Status = fFsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type,
&ctx, &ctxsize);
if (NT_SUCCESS(Status)) {
- if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE,
sizeof(GUID)) == sizeof(GUID) && ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT))
{
- acec = ctx;
- break;
+ if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE,
sizeof(GUID)) == sizeof(GUID)) {
+ if (ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT))
+ acec = ctx;
+ else {
+ ERR("GUID_ECP_ATOMIC_CREATE context was too short: %u
bytes, expected %u\n", ctxsize,
+ sizeof(ATOMIC_CREATE_ECP_CONTEXT));
+ }
+ } else {
+ WARN("unhandled ECP
{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", type.Data1, type.Data2,
+ type.Data3, type.Data4[0], type.Data4[1], type.Data4[2],
type.Data4[3], type.Data4[4], type.Data4[5],
+ type.Data4[6], type.Data4[7]);
}
}
} while (NT_SUCCESS(Status));
@@ -3015,7 +3096,7 @@ 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)) {
+ if (!is_file_name_valid(&fpus, false, false)) {
Status = STATUS_OBJECT_NAME_INVALID;
goto end;
}
@@ -3056,7 +3137,7 @@ static NTSTATUS file_create(PIRP Irp,
_Requires_lock_held_(_Curr_->tree_lock) _R
IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess,
IrpSp->Parameters.Create.ShareAccess, FileObject,
&fileref->fcb->share_access);
send_notification_fileref(fileref, options & FILE_DIRECTORY_FILE ?
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL);
- send_notification_fcb(fileref->parent, FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_ACTION_MODIFIED, NULL);
+ queue_notification_fcb(fileref->parent, FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_ACTION_MODIFIED, NULL);
}
FileObject->FsContext = fileref->fcb;
@@ -3140,13 +3221,10 @@ static NTSTATUS file_create(PIRP Irp,
_Requires_lock_held_(_Curr_->tree_lock) _R
fileref->dc->type = fileref->fcb->type;
- goto end2;
-
end:
if (fpus.Buffer)
ExFreePool(fpus.Buffer);
-end2:
if (parfileref && !loaded_related)
free_fileref(parfileref);
@@ -3414,7 +3492,7 @@ static void
fcb_load_csums(_Requires_lock_held_(_Curr_->tree_lock) device_extens
while (le != &fcb->extents) {
extent* ext = CONTAINING_RECORD(le, extent, list_entry);
- if (ext->extent_data.type == EXTENT_TYPE_REGULAR) {
+ if (!ext->ignore && ext->extent_data.type == EXTENT_TYPE_REGULAR)
{
EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->extent_data.data[0];
uint64_t len;
@@ -3581,7 +3659,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
return STATUS_FILE_IS_A_DIRECTORY;
}
} else if (options & FILE_DIRECTORY_FILE) {
- TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u, %S)\n",
fileref->fcb->type, file_desc_fileref(fileref));
+ TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u)\n",
fileref->fcb->type);
free_fileref(fileref);
@@ -3617,6 +3695,15 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
}
}
+ // 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 %08x\n", Status);
+ free_fileref(fileref);
+
+ return Status;
+ }
+
if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition ==
FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) {
ULONG defda, oldatts, filter;
LARGE_INTEGER time;
@@ -3759,7 +3846,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
}
if (dc->fileref) {
- send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME,
FILE_ACTION_REMOVED_STREAM, &dc->name);
+ 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)) {
@@ -3787,7 +3874,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
fileref->parent->fcb->inode_item_changed = true;
mark_fcb_dirty(fileref->parent->fcb);
- send_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED,
&fileref->dc->name);
+ queue_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED,
&fileref->dc->name);
} else {
mark_fcb_dirty(fileref->fcb);
@@ -3813,7 +3900,7 @@ static NTSTATUS open_file2(device_extension* Vcb, ULONG
RequestedDisposition, PO
fileref->fcb->inode_item.st_mtime = now;
fileref->fcb->inode_item_changed = true;
- send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
+ queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
}
} else {
if (options & FILE_NO_EA_KNOWLEDGE &&
fileref->fcb->ea_xattr.Length > 0) {
@@ -4222,9 +4309,21 @@ NTSTATUS
open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
hl_alloc = true;
}
} else {
- ERR("couldn't find parent for subvol %I64x\n", subvol->id);
- free_fcb(fcb);
- return STATUS_INTERNAL_ERROR;
+ if (!Vcb->options.no_root_dir && subvol->id ==
BTRFS_ROOT_FSTREE && Vcb->root_fileref->fcb->subvol != subvol) {
+ Status = open_fileref_by_inode(Vcb,
Vcb->root_fileref->fcb->subvol, SUBVOL_ROOT_INODE, &parfr, Irp);
+ if (!NT_SUCCESS(Status)) {
+ ERR("open_fileref_by_inode returned %08x\n", Status);
+ free_fcb(fcb);
+ return Status;
+ }
+
+ name.Length = name.MaximumLength = sizeof(root_dir_utf16) -
sizeof(WCHAR);
+ name.Buffer = (WCHAR*)root_dir_utf16;
+ } else {
+ ERR("couldn't find parent for subvol %I64x\n",
subvol->id);
+ free_fcb(fcb);
+ return STATUS_INTERNAL_ERROR;
+ }
}
} else {
Status = open_fileref_by_inode(Vcb, subvol, parent, &parfr, Irp);
@@ -4471,7 +4570,7 @@ loaded:
if (NT_SUCCESS(Status)) {
if (RequestedDisposition == FILE_CREATE) {
- TRACE("file %S already exists, returning
STATUS_OBJECT_NAME_COLLISION\n", file_desc_fileref(fileref));
+ TRACE("file already exists, returning
STATUS_OBJECT_NAME_COLLISION\n");
Status = STATUS_OBJECT_NAME_COLLISION;
free_fileref(fileref);
@@ -4788,7 +4887,7 @@ NTSTATUS __stdcall drv_create(IN PDEVICE_OBJECT DeviceObject, IN
PIRP Irp) {
TRACE("file name: %.*S\n", IrpSp->FileObject->FileName.Length /
sizeof(WCHAR), IrpSp->FileObject->FileName.Buffer);
if (IrpSp->FileObject->RelatedFileObject)
- TRACE("related file = %S\n",
file_desc(IrpSp->FileObject->RelatedFileObject));
+ TRACE("related file = %p\n",
IrpSp->FileObject->RelatedFileObject);
// Don't lock again if we're being called from within CcCopyRead etc.
skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock);
diff --git a/drivers/filesystems/btrfs/devctrl.c b/drivers/filesystems/btrfs/devctrl.c
index 99c2e542d5e..e3c69c97124 100644
--- a/drivers/filesystems/btrfs/devctrl.c
+++ b/drivers/filesystems/btrfs/devctrl.c
@@ -212,6 +212,17 @@ static NTSTATUS probe_volume(void* data, ULONG length,
KPROCESSOR_MODE processor
return STATUS_SUCCESS;
}
+static NTSTATUS ioctl_unload(PIRP Irp) {
+ if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_LOAD_DRIVER_PRIVILEGE),
Irp->RequestorMode)) {
+ ERR("insufficient privileges\n");
+ return STATUS_PRIVILEGE_NOT_HELD;
+ }
+
+ do_shutdown(Irp);
+
+ return STATUS_SUCCESS;
+}
+
static NTSTATUS control_ioctl(PIRP Irp) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS Status;
@@ -225,6 +236,10 @@ static NTSTATUS control_ioctl(PIRP Irp) {
Status = probe_volume(Irp->AssociatedIrp.SystemBuffer,
IrpSp->Parameters.FileSystemControl.InputBufferLength, Irp->RequestorMode);
break;
+ case IOCTL_BTRFS_UNLOAD:
+ Status = ioctl_unload(Irp);
+ break;
+
default:
TRACE("unhandled ioctl %x\n",
IrpSp->Parameters.DeviceIoControl.IoControlCode);
Status = STATUS_NOT_IMPLEMENTED;
diff --git a/drivers/filesystems/btrfs/dirctrl.c b/drivers/filesystems/btrfs/dirctrl.c
index 41a68268add..e6e96fe5fa0 100644
--- a/drivers/filesystems/btrfs/dirctrl.c
+++ b/drivers/filesystems/btrfs/dirctrl.c
@@ -209,7 +209,7 @@ static NTSTATUS query_dir_item(fcb* fcb, ccb* ccb, void* buf, LONG*
len, PIRP Ir
le = le->Flink;
}
- if (r && r->parent != fcb->subvol->id)
+ if (r && r->parent != fcb->subvol->id && (!de->dc ||
!de->dc->root_dir))
r = NULL;
inode = SUBVOL_ROOT_INODE;
@@ -1115,7 +1115,7 @@ static NTSTATUS notify_change_directory(device_extension* Vcb, PIRP
Irp) {
// FIXME - raise exception if FCB marked for deletion?
- TRACE("%S\n", file_desc(FileObject));
+ TRACE("FileObject %p\n", FileObject);
if (ccb->filename.Length == 0) {
ULONG reqlen;
diff --git a/drivers/filesystems/btrfs/fastio.c b/drivers/filesystems/btrfs/fastio.c
index 79604b469ad..5c2b8aaaf8b 100644
--- a/drivers/filesystems/btrfs/fastio.c
+++ b/drivers/filesystems/btrfs/fastio.c
@@ -336,15 +336,33 @@ static NTSTATUS __stdcall fast_io_release_for_ccflush(PFILE_OBJECT
FileObject, P
_Function_class_(FAST_IO_WRITE)
static BOOLEAN __stdcall fast_io_write(PFILE_OBJECT FileObject, PLARGE_INTEGER
FileOffset, ULONG Length, BOOLEAN Wait, ULONG LockKey, PVOID Buffer, PIO_STATUS_BLOCK
IoStatus, PDEVICE_OBJECT DeviceObject) {
- if (FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus,
DeviceObject)) {
- fcb* fcb = FileObject->FsContext;
+ fcb* fcb = FileObject->FsContext;
+ bool ret;
- fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart;
+ FsRtlEnterFileSystem();
- return true;
+ if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, Wait)) {
+ FsRtlExitFileSystem();
+ return false;
}
- return false;
+ if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, Wait)) {
+ ExReleaseResourceLite(&fcb->Vcb->tree_lock);
+ FsRtlExitFileSystem();
+ return false;
+ }
+
+ ret = FsRtlCopyWrite(FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus,
DeviceObject);
+
+ if (ret)
+ fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart;
+
+ ExReleaseResourceLite(fcb->Header.Resource);
+ ExReleaseResourceLite(&fcb->Vcb->tree_lock);
+
+ FsRtlExitFileSystem();
+
+ return ret;
}
_Function_class_(FAST_IO_LOCK)
diff --git a/drivers/filesystems/btrfs/fileinfo.c b/drivers/filesystems/btrfs/fileinfo.c
index 445f4948e59..206a5529deb 100644
--- a/drivers/filesystems/btrfs/fileinfo.c
+++ b/drivers/filesystems/btrfs/fileinfo.c
@@ -210,7 +210,7 @@ static NTSTATUS set_basic_information(device_extension* Vcb, PIRP Irp,
PFILE_OBJ
return STATUS_INVALID_PARAMETER;
}
- TRACE("file = %S, attributes = %x\n", file_desc(FileObject),
fbi->FileAttributes);
+ TRACE("file = %p, attributes = %x\n", FileObject, fbi->FileAttributes);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
@@ -344,7 +344,7 @@ static NTSTATUS set_basic_information(device_extension* Vcb, PIRP Irp,
PFILE_OBJ
}
if (filter != 0)
- send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
+ queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
Status = STATUS_SUCCESS;
@@ -376,7 +376,7 @@ static NTSTATUS set_disposition_information(device_extension* Vcb,
PIRP Irp, PFI
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
- TRACE("changing delete_on_close to %s for %S (fcb %p)\n", flags &
FILE_DISPOSITION_DELETE ? "true" : "false", file_desc(FileObject),
fcb);
+ TRACE("changing delete_on_close to %s for fcb %p\n", flags &
FILE_DISPOSITION_DELETE ? "true" : "false", fcb);
if (fcb->ads) {
if (fileref->parent)
@@ -397,6 +397,12 @@ static NTSTATUS set_disposition_information(device_extension* Vcb,
PIRP Irp, PFI
goto end;
}
+ if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id ==
BTRFS_ROOT_FSTREE) {
+ WARN("not allowing \\$Root to be deleted\n");
+ Status = STATUS_ACCESS_DENIED;
+ goto end;
+ }
+
// FIXME - can we skip this bit for subvols?
if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0
&& (!fileref || fileref->fcb != Vcb->dummy_fcb)) {
TRACE("directory not empty\n");
@@ -1179,8 +1185,6 @@ static NTSTATUS move_across_subvols(file_ref* fileref, ccb* ccb,
file_ref* destd
InsertTailList(&me->dummyfileref->parent->children,
&me->dummyfileref->list_entry);
ExReleaseResourceLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock);
- me->dummyfileref->debug_desc = me->fileref->debug_desc;
-
if (me->dummyfileref->fcb->type == BTRFS_TYPE_DIRECTORY)
me->dummyfileref->fcb->fileref = me->dummyfileref;
@@ -1498,9 +1502,958 @@ void insert_dir_child_into_hash_lists(fcb* fcb, dir_child* dc) {
}
}
+static NTSTATUS rename_stream_to_file(device_extension* Vcb, file_ref* fileref, ccb* ccb,
ULONG flags,
+ PIRP Irp, LIST_ENTRY* rollback) {
+ NTSTATUS Status;
+ file_ref* ofr;
+ ANSI_STRING adsdata;
+ dir_child* dc;
+ fcb* dummyfcb;
+
+ if (fileref->fcb->type != BTRFS_TYPE_FILE)
+ return STATUS_INVALID_PARAMETER;
+
+ if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) &&
fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) {
+ WARN("trying to rename stream on readonly file\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ if (Irp->RequestorMode == UserMode && ccb && !(ccb->access
& DELETE)) {
+ WARN("insufficient permissions\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) // file will always exist
+ return STATUS_OBJECT_NAME_COLLISION;
+
+ // FIXME - POSIX overwrites of stream?
+
+ ofr = fileref->parent;
+
+ if (ofr->open_count > 0) {
+ WARN("trying to overwrite open file\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ if (ofr->fcb->inode_item.st_size > 0) {
+ WARN("can only overwrite existing stream if it is zero-length\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ dummyfcb = create_fcb(Vcb, PagedPool);
+ if (!dummyfcb) {
+ ERR("out of memory\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ // copy parent fcb onto this one
+
+ fileref->fcb->subvol = ofr->fcb->subvol;
+ fileref->fcb->inode = ofr->fcb->inode;
+ fileref->fcb->hash = ofr->fcb->hash;
+ fileref->fcb->type = ofr->fcb->type;
+ fileref->fcb->inode_item = ofr->fcb->inode_item;
+
+ fileref->fcb->sd = ofr->fcb->sd;
+ ofr->fcb->sd = NULL;
+
+ fileref->fcb->deleted = ofr->fcb->deleted;
+ fileref->fcb->atts = ofr->fcb->atts;
+
+ fileref->fcb->reparse_xattr = ofr->fcb->reparse_xattr;
+ ofr->fcb->reparse_xattr.Buffer = NULL;
+ ofr->fcb->reparse_xattr.Length = ofr->fcb->reparse_xattr.MaximumLength =
0;
+
+ fileref->fcb->ea_xattr = ofr->fcb->ea_xattr;
+ ofr->fcb->ea_xattr.Buffer = NULL;
+ ofr->fcb->ea_xattr.Length = ofr->fcb->ea_xattr.MaximumLength = 0;
+
+ fileref->fcb->ealen = ofr->fcb->ealen;
+
+ while (!IsListEmpty(&ofr->fcb->hardlinks)) {
+ InsertTailList(&fileref->fcb->hardlinks,
RemoveHeadList(&ofr->fcb->hardlinks));
+ }
+
+ fileref->fcb->inode_item_changed = true;
+ fileref->fcb->prop_compression = ofr->fcb->prop_compression;
+
+ while (!IsListEmpty(&ofr->fcb->xattrs)) {
+ InsertTailList(&fileref->fcb->xattrs,
RemoveHeadList(&ofr->fcb->xattrs));
+ }
+
+ fileref->fcb->marked_as_orphan = ofr->fcb->marked_as_orphan;
+ fileref->fcb->case_sensitive = ofr->fcb->case_sensitive;
+ fileref->fcb->case_sensitive_set = ofr->fcb->case_sensitive_set;
+
+ while (!IsListEmpty(&ofr->fcb->dir_children_index)) {
+ InsertTailList(&fileref->fcb->dir_children_index,
RemoveHeadList(&ofr->fcb->dir_children_index));
+ }
+
+ while (!IsListEmpty(&ofr->fcb->dir_children_hash)) {
+ InsertTailList(&fileref->fcb->dir_children_hash,
RemoveHeadList(&ofr->fcb->dir_children_hash));
+ }
+
+ while (!IsListEmpty(&ofr->fcb->dir_children_hash_uc)) {
+ InsertTailList(&fileref->fcb->dir_children_hash_uc,
RemoveHeadList(&ofr->fcb->dir_children_hash_uc));
+ }
+
+ fileref->fcb->hash_ptrs = ofr->fcb->hash_ptrs;
+ fileref->fcb->hash_ptrs_uc = ofr->fcb->hash_ptrs_uc;
+
+ ofr->fcb->hash_ptrs = NULL;
+ ofr->fcb->hash_ptrs_uc = NULL;
+
+ fileref->fcb->sd_dirty = ofr->fcb->sd_dirty;
+ fileref->fcb->sd_deleted = ofr->fcb->sd_deleted;
+ fileref->fcb->atts_changed = ofr->fcb->atts_changed;
+ fileref->fcb->atts_deleted = ofr->fcb->atts_deleted;
+ fileref->fcb->extents_changed = true;
+ fileref->fcb->reparse_xattr_changed = ofr->fcb->reparse_xattr_changed;
+ fileref->fcb->ea_changed = ofr->fcb->ea_changed;
+ fileref->fcb->prop_compression_changed =
ofr->fcb->prop_compression_changed;
+ fileref->fcb->xattrs_changed = ofr->fcb->xattrs_changed;
+ fileref->fcb->created = ofr->fcb->created;
+ fileref->fcb->ads = false;
+
+ if (fileref->fcb->adsxattr.Buffer) {
+ ExFreePool(fileref->fcb->adsxattr.Buffer);
+ fileref->fcb->adsxattr.Length = fileref->fcb->adsxattr.MaximumLength
= 0;
+ fileref->fcb->adsxattr.Buffer = NULL;
+ }
+
+ adsdata = fileref->fcb->adsdata;
+
+ fileref->fcb->adsdata.Buffer = NULL;
+ fileref->fcb->adsdata.Length = fileref->fcb->adsdata.MaximumLength = 0;
+
+ InsertHeadList(ofr->fcb->list_entry.Blink,
&fileref->fcb->list_entry);
+
+ if (fileref->fcb->subvol->fcbs_ptrs[fileref->fcb->hash >> 24] ==
&ofr->fcb->list_entry)
+ fileref->fcb->subvol->fcbs_ptrs[fileref->fcb->hash >> 24] =
&fileref->fcb->list_entry;
+
+ RemoveEntryList(&ofr->fcb->list_entry);
+ ofr->fcb->list_entry.Flink = ofr->fcb->list_entry.Blink = NULL;
+
+ mark_fcb_dirty(fileref->fcb);
+
+ // mark old parent fcb so it gets ignored by flush_fcb
+ ofr->fcb->created = true;
+ ofr->fcb->deleted = true;
+
+ mark_fcb_dirty(ofr->fcb);
+
+ // copy parent fileref onto this one
+
+ fileref->oldutf8 = ofr->oldutf8;
+ ofr->oldutf8.Buffer = NULL;
+ ofr->oldutf8.Length = ofr->oldutf8.MaximumLength = 0;
+
+ fileref->oldindex = ofr->oldindex;
+ fileref->delete_on_close = ofr->delete_on_close;
+ fileref->posix_delete = ofr->posix_delete;
+ fileref->deleted = ofr->deleted;
+ fileref->created = ofr->created;
+
+ fileref->parent = ofr->parent;
+
+ RemoveEntryList(&fileref->list_entry);
+ InsertHeadList(ofr->list_entry.Blink, &fileref->list_entry);
+ RemoveEntryList(&ofr->list_entry);
+ ofr->list_entry.Flink = ofr->list_entry.Blink = NULL;
+
+ while (!IsListEmpty(&ofr->children)) {
+ file_ref* fr = CONTAINING_RECORD(RemoveHeadList(&ofr->children), file_ref,
list_entry);
+
+ free_fileref(fr->parent);
+
+ fr->parent = fileref;
+ InterlockedIncrement(&fileref->refcount);
+
+ InsertTailList(&fileref->children, &fr->list_entry);
+ }
+
+ dc = fileref->dc;
+
+ fileref->dc = ofr->dc;
+ fileref->dc->fileref = fileref;
+
+ mark_fileref_dirty(fileref);
+
+ // mark old parent fileref so it gets ignored by flush_fileref
+ ofr->created = true;
+ ofr->deleted = true;
+
+ // write file data
+
+ fileref->fcb->inode_item.st_size = adsdata.Length;
+
+ if (adsdata.Length > 0) {
+ bool make_inline = adsdata.Length <= Vcb->options.max_inline;
+
+ if (make_inline) {
+ EXTENT_DATA* ed = ExAllocatePoolWithTag(PagedPool,
(uint16_t)(offsetof(EXTENT_DATA, data[0]) + adsdata.Length), ALLOC_TAG);
+ if (!ed) {
+ ERR("out of memory\n");
+ ExFreePool(adsdata.Buffer);
+ reap_fcb(dummyfcb);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ed->generation = Vcb->superblock.generation;
+ ed->decoded_size = adsdata.Length;
+ ed->compression = BTRFS_COMPRESSION_NONE;
+ ed->encryption = BTRFS_ENCRYPTION_NONE;
+ ed->encoding = BTRFS_ENCODING_NONE;
+ ed->type = EXTENT_TYPE_INLINE;
+
+ RtlCopyMemory(ed->data, adsdata.Buffer, adsdata.Length);
+
+ ExFreePool(adsdata.Buffer);
+
+ Status = add_extent_to_fcb(fileref->fcb, 0, ed,
(uint16_t)(offsetof(EXTENT_DATA, data[0]) + adsdata.Length), false, NULL, rollback);
+ if (!NT_SUCCESS(Status)) {
+ ERR("add_extent_to_fcb returned %08x\n", Status);
+ ExFreePool(ed);
+ reap_fcb(dummyfcb);
+ return Status;
+ }
+
+ ExFreePool(ed);
+ } else if (adsdata.Length % Vcb->superblock.sector_size) {
+ char* newbuf = ExAllocatePoolWithTag(PagedPool,
(uint16_t)sector_align(adsdata.Length, Vcb->superblock.sector_size), ALLOC_TAG);
+ if (!newbuf) {
+ ERR("out of memory\n");
+ ExFreePool(adsdata.Buffer);
+ reap_fcb(dummyfcb);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ RtlCopyMemory(newbuf, adsdata.Buffer, adsdata.Length);
+ RtlZeroMemory(newbuf + adsdata.Length,
(uint16_t)(sector_align(adsdata.Length, Vcb->superblock.sector_size) -
adsdata.Length));
+
+ ExFreePool(adsdata.Buffer);
+
+ adsdata.Buffer = newbuf;
+ adsdata.Length = adsdata.MaximumLength =
(uint16_t)sector_align(adsdata.Length, Vcb->superblock.sector_size);
+ }
+
+ if (!make_inline) {
+ Status = do_write_file(fileref->fcb, 0, adsdata.Length, adsdata.Buffer,
Irp, false, 0, rollback);
+ if (!NT_SUCCESS(Status)) {
+ ERR("do_write_file returned %08x\n", Status);
+ ExFreePool(adsdata.Buffer);
+ reap_fcb(dummyfcb);
+ return Status;
+ }
+
+ ExFreePool(adsdata.Buffer);
+ }
+
+ fileref->fcb->inode_item.st_blocks = adsdata.Length;
+ fileref->fcb->inode_item_changed = true;
+ }
+
+ RemoveEntryList(&dc->list_entry_index);
+
+ if (dc->utf8.Buffer)
+ ExFreePool(dc->utf8.Buffer);
+
+ if (dc->name.Buffer)
+ ExFreePool(dc->name.Buffer);
+
+ if (dc->name_uc.Buffer)
+ ExFreePool(dc->name_uc.Buffer);
+
+ ExFreePool(dc);
+
+ // FIXME - csums?
+
+ // add dummy deleted xattr with old name
+
+ dummyfcb->Vcb = Vcb;
+ dummyfcb->subvol = fileref->fcb->subvol;
+ dummyfcb->inode = fileref->fcb->inode;
+ dummyfcb->adsxattr = fileref->fcb->adsxattr;
+ dummyfcb->adshash = fileref->fcb->adshash;
+ dummyfcb->ads = true;
+ dummyfcb->deleted = true;
+
+ // FIXME - dummyfileref as well?
+
+ mark_fcb_dirty(dummyfcb);
+
+ free_fcb(dummyfcb);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS rename_stream(device_extension* Vcb, file_ref* fileref, ccb* ccb,
FILE_RENAME_INFORMATION_EX* fri,
+ ULONG flags, PIRP Irp, LIST_ENTRY* rollback) {
+ NTSTATUS Status;
+ UNICODE_STRING fn;
+ file_ref* sf = NULL;
+ uint16_t newmaxlen;
+ ULONG utf8len;
+ ANSI_STRING utf8;
+ UNICODE_STRING utf16, utf16uc;
+ ANSI_STRING adsxattr;
+ uint32_t crc32;
+ fcb* dummyfcb;
+
+ static const WCHAR datasuf[] = L":$DATA";
+ static const char xapref[] = "user.";
+
+ if (!fileref) {
+ ERR("fileref not set\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!fileref->parent) {
+ ERR("fileref->parent not set\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (fri->FileNameLength < sizeof(WCHAR)) {
+ WARN("filename too short\n");
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ if (fri->FileName[0] != ':') {
+ WARN("destination filename must begin with a colon\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (Irp->RequestorMode == UserMode && ccb && !(ccb->access
& DELETE)) {
+ WARN("insufficient permissions\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ fn.Buffer = &fri->FileName[1];
+ fn.Length = fn.MaximumLength = (USHORT)(fri->FileNameLength - sizeof(WCHAR));
+
+ // remove :$DATA suffix
+ if (fn.Length >= sizeof(datasuf) - sizeof(WCHAR) &&
+ RtlCompareMemory(&fn.Buffer[(fn.Length - sizeof(datasuf) +
sizeof(WCHAR))/sizeof(WCHAR)], datasuf, sizeof(datasuf) - sizeof(WCHAR)) ==
sizeof(datasuf) - sizeof(WCHAR))
+ fn.Length -= sizeof(datasuf) - sizeof(WCHAR);
+
+ if (fn.Length == 0)
+ return rename_stream_to_file(Vcb, fileref, ccb, flags, Irp, rollback);
+
+ if (!is_file_name_valid(&fn, false, true)) {
+ WARN("invalid stream name %.*S\n", fn.Length / sizeof(WCHAR),
fn.Buffer);
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) &&
fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) {
+ WARN("trying to rename stream on readonly file\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ Status = open_fileref_child(Vcb, fileref->parent, &fn,
fileref->parent->fcb->case_sensitive, true, true, PagedPool, &sf, Irp);
+ if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+ if (Status == STATUS_SUCCESS) {
+ if (fileref == sf || sf->deleted) {
+ free_fileref(sf);
+ sf = NULL;
+ } else {
+ if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) {
+ Status = STATUS_OBJECT_NAME_COLLISION;
+ goto end;
+ }
+
+ // FIXME - POSIX overwrites of stream?
+
+ if (sf->open_count > 0) {
+ WARN("trying to overwrite open file\n");
+ Status = STATUS_ACCESS_DENIED;
+ goto end;
+ }
+
+ if (sf->fcb->adsdata.Length > 0) {
+ WARN("can only overwrite existing stream if it is
zero-length\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ Status = delete_fileref(sf, NULL, false, Irp, rollback);
+ if (!NT_SUCCESS(Status)) {
+ ERR("delete_fileref returned %08x\n", Status);
+ goto end;
+ }
+ }
+ } else {
+ ERR("open_fileref_child returned %08x\n", Status);
+ goto end;
+ }
+ }
+
+ Status = utf16_to_utf8(NULL, 0, &utf8len, fn.Buffer, fn.Length);
+ if (!NT_SUCCESS(Status))
+ goto end;
+
+ utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
+ utf8.Buffer = ExAllocatePoolWithTag(PagedPool, utf8.MaximumLength, ALLOC_TAG);
+ if (!utf8.Buffer) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto end;
+ }
+
+ Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn.Buffer, fn.Length);
+ if (!NT_SUCCESS(Status)) {
+ ExFreePool(utf8.Buffer);
+ goto end;
+ }
+
+ adsxattr.Length = adsxattr.MaximumLength = sizeof(xapref) - 1 + utf8.Length;
+ adsxattr.Buffer = ExAllocatePoolWithTag(PagedPool, adsxattr.MaximumLength,
ALLOC_TAG);
+ if (!adsxattr.Buffer) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(utf8.Buffer);
+ goto end;
+ }
+
+ RtlCopyMemory(adsxattr.Buffer, xapref, sizeof(xapref) - 1);
+ RtlCopyMemory(&adsxattr.Buffer[sizeof(xapref) - 1], utf8.Buffer, utf8.Length);
+
+ // don't allow if it's one of our reserved names
+
+ if ((adsxattr.Length == sizeof(EA_DOSATTRIB) - sizeof(WCHAR) &&
RtlCompareMemory(adsxattr.Buffer, EA_DOSATTRIB, adsxattr.Length) == adsxattr.Length) ||
+ (adsxattr.Length == sizeof(EA_EA) - sizeof(WCHAR) &&
RtlCompareMemory(adsxattr.Buffer, EA_EA, adsxattr.Length) == adsxattr.Length) ||
+ (adsxattr.Length == sizeof(EA_REPARSE) - sizeof(WCHAR) &&
RtlCompareMemory(adsxattr.Buffer, EA_REPARSE, adsxattr.Length) == adsxattr.Length) ||
+ (adsxattr.Length == sizeof(EA_CASE_SENSITIVE) - sizeof(WCHAR) &&
RtlCompareMemory(adsxattr.Buffer, EA_CASE_SENSITIVE, adsxattr.Length) == adsxattr.Length))
{
+ Status = STATUS_OBJECT_NAME_INVALID;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ utf16.Length = utf16.MaximumLength = fn.Length;
+ utf16.Buffer = ExAllocatePoolWithTag(PagedPool, utf16.MaximumLength, ALLOC_TAG);
+ if (!utf16.Buffer) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ RtlCopyMemory(utf16.Buffer, fn.Buffer, fn.Length);
+
+ newmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) -
+ offsetof(DIR_ITEM, name[0]);
+
+ if (newmaxlen < adsxattr.Length) {
+ WARN("cannot rename as data too long\n");
+ Status = STATUS_INVALID_PARAMETER;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ newmaxlen -= adsxattr.Length;
+
+ if (newmaxlen < fileref->fcb->adsdata.Length) {
+ WARN("cannot rename as data too long\n");
+ Status = STATUS_INVALID_PARAMETER;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ Status = RtlUpcaseUnicodeString(&utf16uc, &fn, true);
+ if (!NT_SUCCESS(Status)) {
+ ERR("RtlUpcaseUnicodeString returned %08x\n");
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ // add dummy deleted xattr with old name
+
+ dummyfcb = create_fcb(Vcb, PagedPool);
+ if (!dummyfcb) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(utf16uc.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ dummyfcb->Vcb = Vcb;
+ dummyfcb->subvol = fileref->fcb->subvol;
+ dummyfcb->inode = fileref->fcb->inode;
+ dummyfcb->adsxattr = fileref->fcb->adsxattr;
+ dummyfcb->adshash = fileref->fcb->adshash;
+ dummyfcb->ads = true;
+ dummyfcb->deleted = true;
+
+ mark_fcb_dirty(dummyfcb);
+
+ free_fcb(dummyfcb);
+
+ // change fcb values
+
+ fileref->dc->utf8 = utf8;
+ fileref->dc->name = utf16;
+ fileref->dc->name_uc = utf16uc;
+
+ crc32 = calc_crc32c(0xfffffffe, (uint8_t*)adsxattr.Buffer, adsxattr.Length);
+
+ fileref->fcb->adsxattr = adsxattr;
+ fileref->fcb->adshash = crc32;
+ fileref->fcb->adsmaxlen = newmaxlen;
+
+ fileref->fcb->created = true;
+
+ mark_fcb_dirty(fileref->fcb);
+
+ Status = STATUS_SUCCESS;
+
+end:
+ if (sf)
+ free_fileref(sf);
+
+ return Status;
+}
+
+static NTSTATUS rename_file_to_stream(device_extension* Vcb, file_ref* fileref, ccb* ccb,
FILE_RENAME_INFORMATION_EX* fri,
+ ULONG flags, PIRP Irp, LIST_ENTRY* rollback) {
+ NTSTATUS Status;
+ UNICODE_STRING fn;
+ file_ref* sf = NULL;
+ uint16_t newmaxlen;
+ ULONG utf8len;
+ ANSI_STRING utf8;
+ UNICODE_STRING utf16, utf16uc;
+ ANSI_STRING adsxattr, adsdata;
+ uint32_t crc32;
+ fcb* dummyfcb;
+ file_ref* dummyfileref;
+ dir_child* dc;
+ LIST_ENTRY* le;
+
+ static const WCHAR datasuf[] = L":$DATA";
+ static const char xapref[] = "user.";
+
+ if (!fileref) {
+ ERR("fileref not set\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (fri->FileNameLength < sizeof(WCHAR)) {
+ WARN("filename too short\n");
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ if (fri->FileName[0] != ':') {
+ WARN("destination filename must begin with a colon\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (Irp->RequestorMode == UserMode && ccb && !(ccb->access
& DELETE)) {
+ WARN("insufficient permissions\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ if (fileref->fcb->type != BTRFS_TYPE_FILE)
+ return STATUS_INVALID_PARAMETER;
+
+ fn.Buffer = &fri->FileName[1];
+ fn.Length = fn.MaximumLength = (USHORT)(fri->FileNameLength - sizeof(WCHAR));
+
+ // remove :$DATA suffix
+ if (fn.Length >= sizeof(datasuf) - sizeof(WCHAR) &&
+ RtlCompareMemory(&fn.Buffer[(fn.Length - sizeof(datasuf) +
sizeof(WCHAR))/sizeof(WCHAR)], datasuf, sizeof(datasuf) - sizeof(WCHAR)) ==
sizeof(datasuf) - sizeof(WCHAR))
+ fn.Length -= sizeof(datasuf) - sizeof(WCHAR);
+
+ if (fn.Length == 0) {
+ WARN("not allowing overwriting file with itself\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!is_file_name_valid(&fn, false, true)) {
+ WARN("invalid stream name %.*S\n", fn.Length / sizeof(WCHAR),
fn.Buffer);
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+
+ if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) &&
fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) {
+ WARN("trying to rename stream on readonly file\n");
+ return STATUS_ACCESS_DENIED;
+ }
+
+ Status = open_fileref_child(Vcb, fileref, &fn,
fileref->fcb->case_sensitive, true, true, PagedPool, &sf, Irp);
+ if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+ if (Status == STATUS_SUCCESS) {
+ if (fileref == sf || sf->deleted) {
+ free_fileref(sf);
+ sf = NULL;
+ } else {
+ if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) {
+ Status = STATUS_OBJECT_NAME_COLLISION;
+ goto end;
+ }
+
+ // FIXME - POSIX overwrites of stream?
+
+ if (sf->open_count > 0) {
+ WARN("trying to overwrite open file\n");
+ Status = STATUS_ACCESS_DENIED;
+ goto end;
+ }
+
+ if (sf->fcb->adsdata.Length > 0) {
+ WARN("can only overwrite existing stream if it is
zero-length\n");
+ Status = STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ Status = delete_fileref(sf, NULL, false, Irp, rollback);
+ if (!NT_SUCCESS(Status)) {
+ ERR("delete_fileref returned %08x\n", Status);
+ goto end;
+ }
+ }
+ } else {
+ ERR("open_fileref_child returned %08x\n", Status);
+ goto end;
+ }
+ }
+
+ Status = utf16_to_utf8(NULL, 0, &utf8len, fn.Buffer, fn.Length);
+ if (!NT_SUCCESS(Status))
+ goto end;
+
+ utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
+ utf8.Buffer = ExAllocatePoolWithTag(PagedPool, utf8.MaximumLength, ALLOC_TAG);
+ if (!utf8.Buffer) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto end;
+ }
+
+ Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn.Buffer, fn.Length);
+ if (!NT_SUCCESS(Status)) {
+ ExFreePool(utf8.Buffer);
+ goto end;
+ }
+
+ adsxattr.Length = adsxattr.MaximumLength = sizeof(xapref) - 1 + utf8.Length;
+ adsxattr.Buffer = ExAllocatePoolWithTag(PagedPool, adsxattr.MaximumLength,
ALLOC_TAG);
+ if (!adsxattr.Buffer) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(utf8.Buffer);
+ goto end;
+ }
+
+ RtlCopyMemory(adsxattr.Buffer, xapref, sizeof(xapref) - 1);
+ RtlCopyMemory(&adsxattr.Buffer[sizeof(xapref) - 1], utf8.Buffer, utf8.Length);
+
+ // don't allow if it's one of our reserved names
+
+ if ((adsxattr.Length == sizeof(EA_DOSATTRIB) - sizeof(WCHAR) &&
RtlCompareMemory(adsxattr.Buffer, EA_DOSATTRIB, adsxattr.Length) == adsxattr.Length) ||
+ (adsxattr.Length == sizeof(EA_EA) - sizeof(WCHAR) &&
RtlCompareMemory(adsxattr.Buffer, EA_EA, adsxattr.Length) == adsxattr.Length) ||
+ (adsxattr.Length == sizeof(EA_REPARSE) - sizeof(WCHAR) &&
RtlCompareMemory(adsxattr.Buffer, EA_REPARSE, adsxattr.Length) == adsxattr.Length) ||
+ (adsxattr.Length == sizeof(EA_CASE_SENSITIVE) - sizeof(WCHAR) &&
RtlCompareMemory(adsxattr.Buffer, EA_CASE_SENSITIVE, adsxattr.Length) == adsxattr.Length))
{
+ Status = STATUS_OBJECT_NAME_INVALID;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ utf16.Length = utf16.MaximumLength = fn.Length;
+ utf16.Buffer = ExAllocatePoolWithTag(PagedPool, utf16.MaximumLength, ALLOC_TAG);
+ if (!utf16.Buffer) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ RtlCopyMemory(utf16.Buffer, fn.Buffer, fn.Length);
+
+ newmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) -
+ offsetof(DIR_ITEM, name[0]);
+
+ if (newmaxlen < adsxattr.Length) {
+ WARN("cannot rename as data too long\n");
+ Status = STATUS_INVALID_PARAMETER;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ newmaxlen -= adsxattr.Length;
+
+ if (newmaxlen < fileref->fcb->inode_item.st_size) {
+ WARN("cannot rename as data too long\n");
+ Status = STATUS_INVALID_PARAMETER;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ Status = RtlUpcaseUnicodeString(&utf16uc, &fn, true);
+ if (!NT_SUCCESS(Status)) {
+ ERR("RtlUpcaseUnicodeString returned %08x\n");
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ // read existing file data
+
+ if (fileref->fcb->inode_item.st_size > 0) {
+ ULONG bytes_read;
+
+ adsdata.Length = adsdata.MaximumLength =
(uint16_t)fileref->fcb->inode_item.st_size;
+
+ adsdata.Buffer = ExAllocatePoolWithTag(PagedPool, adsdata.MaximumLength,
ALLOC_TAG);
+ if (!adsdata.Buffer) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(utf16uc.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ goto end;
+ }
+
+ Status = read_file(fileref->fcb, (uint8_t*)adsdata.Buffer, 0, adsdata.Length,
&bytes_read, Irp);
+ if (!NT_SUCCESS(Status)) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(utf16uc.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ ExFreePool(adsdata.Buffer);
+ goto end;
+ }
+
+ if (bytes_read < fileref->fcb->inode_item.st_size) {
+ ERR("short read\n");
+ Status = STATUS_INTERNAL_ERROR;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(utf16uc.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ ExFreePool(adsdata.Buffer);
+ goto end;
+ }
+ } else
+ adsdata.Buffer = NULL;
+
+ dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
+ if (!dc) {
+ ERR("short read\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(utf16uc.Buffer);
+ ExFreePool(adsxattr.Buffer);
+
+ if (adsdata.Buffer)
+ ExFreePool(adsdata.Buffer);
+
+ goto end;
+ }
+
+ // add dummy deleted fcb with old name
+
+ Status = duplicate_fcb(fileref->fcb, &dummyfcb);
+ if (!NT_SUCCESS(Status)) {
+ ERR("duplicate_fcb returned %08x\n", Status);
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(utf16uc.Buffer);
+ ExFreePool(adsxattr.Buffer);
+
+ if (adsdata.Buffer)
+ ExFreePool(adsdata.Buffer);
+
+ ExFreePool(dc);
+
+ goto end;
+ }
+
+ dummyfileref = create_fileref(Vcb);
+ if (!dummyfileref) {
+ ERR("out of memory\n");
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(utf16uc.Buffer);
+ ExFreePool(adsxattr.Buffer);
+
+ if (adsdata.Buffer)
+ ExFreePool(adsdata.Buffer);
+
+ ExFreePool(dc);
+
+ reap_fcb(dummyfcb);
+
+ goto end;
+ }
+
+ dummyfileref->fcb = dummyfcb;
+
+ dummyfcb->Vcb = Vcb;
+ dummyfcb->subvol = fileref->fcb->subvol;
+ dummyfcb->inode = fileref->fcb->inode;
+ dummyfcb->hash = fileref->fcb->hash;
+
+ if (fileref->fcb->inode_item.st_size > 0) {
+ Status = excise_extents(Vcb, dummyfcb, 0,
sector_align(fileref->fcb->inode_item.st_size, Vcb->superblock.sector_size),
+ Irp, rollback);
+ if (!NT_SUCCESS(Status)) {
+ ERR("excise_extents returned %08x\n", Status);
+ ExFreePool(utf8.Buffer);
+ ExFreePool(utf16.Buffer);
+ ExFreePool(utf16uc.Buffer);
+ ExFreePool(adsxattr.Buffer);
+ ExFreePool(adsdata.Buffer);
+ ExFreePool(dc);
+
+ reap_fileref(Vcb, dummyfileref);
+ reap_fcb(dummyfcb);
+
+ goto end;
+ }
+
+ dummyfcb->inode_item.st_size = 0;
+ dummyfcb->Header.AllocationSize.QuadPart = 0;
+ dummyfcb->Header.FileSize.QuadPart = 0;
+ dummyfcb->Header.ValidDataLength.QuadPart = 0;
+ }
+
+ dummyfcb->hash_ptrs = fileref->fcb->hash_ptrs;
+ dummyfcb->hash_ptrs_uc = fileref->fcb->hash_ptrs_uc;
+ dummyfcb->created = fileref->fcb->created;
+
+ le = fileref->fcb->extents.Flink;
+ while (le != &fileref->fcb->extents) {
+ extent* ext = CONTAINING_RECORD(le, extent, list_entry);
+
+ ext->ignore = true;
+
+ le = le->Flink;
+ }
+
+ while (!IsListEmpty(&fileref->fcb->dir_children_index)) {
+ InsertTailList(&dummyfcb->dir_children_index,
RemoveHeadList(&fileref->fcb->dir_children_index));
+ }
+
+ while (!IsListEmpty(&fileref->fcb->dir_children_hash)) {
+ InsertTailList(&dummyfcb->dir_children_hash,
RemoveHeadList(&fileref->fcb->dir_children_hash));
+ }
+
+ while (!IsListEmpty(&fileref->fcb->dir_children_hash_uc)) {
+ InsertTailList(&dummyfcb->dir_children_hash_uc,
RemoveHeadList(&fileref->fcb->dir_children_hash_uc));
+ }
+
+ InsertTailList(&Vcb->all_fcbs, &dummyfcb->list_entry_all);
+
+ InsertHeadList(fileref->fcb->list_entry.Blink, &dummyfcb->list_entry);
+
+ if (fileref->fcb->subvol->fcbs_ptrs[dummyfcb->hash >> 24] ==
&fileref->fcb->list_entry)
+ fileref->fcb->subvol->fcbs_ptrs[dummyfcb->hash >> 24] =
&dummyfcb->list_entry;
+
+ RemoveEntryList(&fileref->fcb->list_entry);
+ fileref->fcb->list_entry.Flink = fileref->fcb->list_entry.Blink = NULL;
+
+ mark_fcb_dirty(dummyfcb);
+
+ // create dummy fileref
+
+ dummyfileref->oldutf8 = fileref->oldutf8;
+ dummyfileref->oldindex = fileref->oldindex;
+ dummyfileref->delete_on_close = fileref->delete_on_close;
+ dummyfileref->posix_delete = fileref->posix_delete;
+ dummyfileref->deleted = fileref->deleted;
+ dummyfileref->created = fileref->created;
+ dummyfileref->parent = fileref->parent;
+
+ while (!IsListEmpty(&fileref->children)) {
+ file_ref* fr = CONTAINING_RECORD(RemoveHeadList(&fileref->children),
file_ref, list_entry);
+
+ free_fileref(fr->parent);
+
+ fr->parent = dummyfileref;
+ InterlockedIncrement(&dummyfileref->refcount);
+
+ InsertTailList(&dummyfileref->children, &fr->list_entry);
+ }
+
+ InsertTailList(fileref->list_entry.Blink, &dummyfileref->list_entry);
+
+ RemoveEntryList(&fileref->list_entry);
+ InsertTailList(&dummyfileref->children, &fileref->list_entry);
+
+ dummyfileref->dc = fileref->dc;
+ dummyfileref->dc->fileref = dummyfileref;
+
+ mark_fileref_dirty(dummyfileref);
+
+ free_fileref(dummyfileref);
+
+ // change fcb values
+
+ fileref->fcb->hash_ptrs = NULL;
+ fileref->fcb->hash_ptrs_uc = NULL;
+
+ fileref->fcb->ads = true;
+
+ fileref->oldutf8.Length = fileref->oldutf8.MaximumLength = 0;
+ fileref->oldutf8.Buffer = NULL;
+
+ RtlZeroMemory(dc, sizeof(dir_child));
+
+ dc->utf8 = utf8;
+ dc->name = utf16;
+ dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer,
dc->name.Length);
+ dc->name_uc = utf16uc;
+ dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer,
dc->name_uc.Length);
+ dc->fileref = fileref;
+ InsertTailList(&dummyfcb->dir_children_index, &dc->list_entry_index);
+
+ fileref->dc = dc;
+ fileref->parent = dummyfileref;
+
+ crc32 = calc_crc32c(0xfffffffe, (uint8_t*)adsxattr.Buffer, adsxattr.Length);
+
+ fileref->fcb->adsxattr = adsxattr;
+ fileref->fcb->adshash = crc32;
+ fileref->fcb->adsmaxlen = newmaxlen;
+ fileref->fcb->adsdata = adsdata;
+
+ fileref->fcb->created = true;
+
+ mark_fcb_dirty(fileref->fcb);
+
+ Status = STATUS_SUCCESS;
+
+end:
+ if (sf)
+ free_fileref(sf);
+
+ return Status;
+}
+
static NTSTATUS set_rename_information(device_extension* Vcb, PIRP Irp, PFILE_OBJECT
FileObject, PFILE_OBJECT tfo, bool ex) {
FILE_RENAME_INFORMATION_EX* fri = Irp->AssociatedIrp.SystemBuffer;
- fcb *fcb = FileObject->FsContext;
+ fcb* fcb = FileObject->FsContext;
ccb* ccb = FileObject->FsContext2;
file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related =
NULL, *fr2 = NULL;
WCHAR* fn;
@@ -1515,6 +2468,9 @@ 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);
@@ -1558,11 +2514,39 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP
Irp, PFILE_OB
ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, true);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
+ if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id ==
BTRFS_ROOT_FSTREE) {
+ WARN("not allowing \\$Root to be renamed\n");
+ Status = STATUS_ACCESS_DENIED;
+ goto end;
+ }
+
if (fcb->ads) {
- // MSDN says that NTFS data streams can be renamed
(
https://msdn.microsoft.com/en-us/library/windows/hardware/ff540344.aspx),
- // but if you try it always seems to return STATUS_INVALID_PARAMETER. There is a
function in ntfs.sys called NtfsStreamRename,
- // but it never seems to get invoked... If you know what's going on here,
I'd appreciate it if you let me know.
- Status = STATUS_INVALID_PARAMETER;
+ if (FileObject->SectionObjectPointer &&
FileObject->SectionObjectPointer->DataSectionObject) {
+ IO_STATUS_BLOCK iosb;
+
+ CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
+ if (!NT_SUCCESS(iosb.Status)) {
+ ERR("CcFlushCache returned %08x\n", iosb.Status);
+ Status = iosb.Status;
+ goto end;
+ }
+ }
+
+ Status = rename_stream(Vcb, fileref, ccb, fri, flags, Irp, &rollback);
+ goto end;
+ } else if (fnlen >= 1 && fn[0] == ':') {
+ if (FileObject->SectionObjectPointer &&
FileObject->SectionObjectPointer->DataSectionObject) {
+ IO_STATUS_BLOCK iosb;
+
+ CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
+ if (!NT_SUCCESS(iosb.Status)) {
+ ERR("CcFlushCache returned %08x\n", iosb.Status);
+ Status = iosb.Status;
+ goto end;
+ }
+ }
+
+ Status = rename_file_to_stream(Vcb, fileref, ccb, fri, flags, Irp,
&rollback);
goto end;
}
@@ -1571,6 +2555,18 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP
Irp, PFILE_OB
TRACE("fnus = %.*S\n", 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;
+ goto end;
+ }
+ }
+
origutf8len = fileref->dc->utf8.Length;
Status = utf16_to_utf8(NULL, 0, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
@@ -1602,7 +2598,7 @@ static NTSTATUS set_rename_information(device_extension* Vcb, PIRP
Irp, PFILE_OB
Status = open_fileref(Vcb, &oldfileref, &fnus, related, false, NULL, NULL,
PagedPool, ccb->case_sensitive, Irp);
if (NT_SUCCESS(Status)) {
- TRACE("destination file %S already exists\n",
file_desc_fileref(oldfileref));
+ TRACE("destination file already exists\n");
if (fileref != oldfileref && !oldfileref->deleted) {
if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) {
@@ -2237,12 +3233,12 @@ static NTSTATUS set_end_of_file_information(device_extension* Vcb,
PIRP Irp, PFI
mark_fcb_dirty(fileref->parent->fcb);
}
- send_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED_STREAM,
&fileref->dc->name);
+ queue_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED_STREAM,
&fileref->dc->name);
goto end;
}
- TRACE("file: %S\n", file_desc(FileObject));
+ TRACE("file: %p\n", FileObject);
TRACE("paging IO: %s\n", Irp->Flags & IRP_PAGING_IO ?
"true" : "false");
TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength =
%I64x\n",
fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart,
fcb->Header.ValidDataLength.QuadPart);
@@ -2301,7 +3297,7 @@ static NTSTATUS set_end_of_file_information(device_extension* Vcb,
PIRP Irp, PFI
fcb->inode_item_changed = true;
mark_fcb_dirty(fcb);
- send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
+ queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
Status = STATUS_SUCCESS;
@@ -2332,7 +3328,7 @@ end:
static NTSTATUS set_position_information(PFILE_OBJECT FileObject, PIRP Irp) {
FILE_POSITION_INFORMATION* fpi =
(FILE_POSITION_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
- TRACE("setting the position on %S to %I64x\n", file_desc(FileObject),
fpi->CurrentByteOffset.QuadPart);
+ TRACE("setting the position on %p to %I64x\n", FileObject,
fpi->CurrentByteOffset.QuadPart);
// FIXME - make sure aligned for FO_NO_INTERMEDIATE_BUFFERING
@@ -2460,7 +3456,7 @@ static NTSTATUS set_link_information(device_extension* Vcb, PIRP
Irp, PFILE_OBJE
if (NT_SUCCESS(Status)) {
if (!oldfileref->deleted) {
- WARN("destination file %S already exists\n",
file_desc_fileref(oldfileref));
+ WARN("destination file already exists\n");
if (!(flags & FILE_LINK_REPLACE_IF_EXISTS)) {
Status = STATUS_OBJECT_NAME_COLLISION;
@@ -2755,7 +3751,7 @@ static NTSTATUS set_valid_data_length_information(device_extension*
Vcb, PIRP Ir
fcb->inode_item_changed = true;
mark_fcb_dirty(fcb);
- send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
+ queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
Status = STATUS_SUCCESS;
@@ -2879,6 +3875,8 @@ NTSTATUS __stdcall drv_set_information(IN PDEVICE_OBJECT
DeviceObject, IN PIRP I
TRACE("set information\n");
+ FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
+
switch (IrpSp->Parameters.SetFile.FileInformationClass) {
case FileAllocationInformation:
{
@@ -2951,7 +3949,6 @@ NTSTATUS __stdcall drv_set_information(IN PDEVICE_OBJECT
DeviceObject, IN PIRP I
case FileRenameInformation:
TRACE("FileRenameInformation\n");
- // FIXME - make this work with streams
Status = set_rename_information(Vcb, Irp, IrpSp->FileObject,
IrpSp->Parameters.SetFile.FileObject, false);
break;
diff --git a/drivers/filesystems/btrfs/flushthread.c
b/drivers/filesystems/btrfs/flushthread.c
index ef847a59cca..456c8541370 100644
--- a/drivers/filesystems/btrfs/flushthread.c
+++ b/drivers/filesystems/btrfs/flushthread.c
@@ -545,6 +545,9 @@ nextdev:
for (num = 0; num < total_num; num++) {
if (context.stripes[num].dmdsa)
ExFreePool(context.stripes[num].dmdsa);
+
+ if (context.stripes[num].Irp)
+ IoFreeIrp(context.stripes[num].Irp);
}
ExFreePool(context.stripes);
@@ -1633,13 +1636,14 @@ NTSTATUS do_tree_writes(device_extension* Vcb, LIST_ENTRY*
tree_writes, bool no_
RtlCopyMemory(data, tw2->data, tw2->length);
RtlCopyMemory(&data[tw2->length], tw->data, tw->length);
- if (!no_free)
+ if (!no_free || tw2->allocated)
ExFreePool(tw2->data);
tw2->data = data;
tw2->length += tw->length;
+ tw2->allocated = true;
- if (!no_free) // FIXME - what if we allocated this just now?
+ if (!no_free || tw->allocated)
ExFreePool(tw->data);
RemoveEntryList(&tw->list_entry);
@@ -2025,6 +2029,7 @@ static NTSTATUS write_trees(device_extension* Vcb, PIRP Irp) {
tw->address = t->new_address;
tw->length = Vcb->superblock.node_size;
tw->data = data;
+ tw->allocated = false;
if (IsListEmpty(&tree_writes))
InsertTailList(&tree_writes, &tw->list_entry);
@@ -6482,8 +6487,6 @@ static NTSTATUS flush_fileref(file_ref* fileref, LIST_ENTRY*
batchlist, PIRP Irp
crc32 = calc_crc32c(0xfffffffe, (uint8_t*)name->Buffer, name->Length);
- TRACE("deleting %.*S\n", file_desc_fileref(fileref));
-
di = ExAllocatePoolWithTag(PagedPool, sizeof(DIR_ITEM) - 1 + name->Length,
ALLOC_TAG);
if (!di) {
ERR("out of memory\n");
@@ -6750,6 +6753,9 @@ static void flush_disk_caches(device_extension* Vcb) {
LIST_ENTRY* le;
ioctl_context context;
ULONG num;
+#ifdef __REACTOS__
+ unsigned int i;
+#endif
context.left = 0;
@@ -6827,6 +6833,15 @@ nextdev:
KeWaitForSingleObject(&context.Event, Executive, KernelMode, false, NULL);
+#ifndef __REACTOS__
+ for (unsigned int i = 0; i < num; i++) {
+#else
+ for (i = 0; i < num; i++) {
+#endif
+ if (context.stripes[i].Irp)
+ IoFreeIrp(context.stripes[i].Irp);
+ }
+
ExFreePool(context.stripes);
}
diff --git a/drivers/filesystems/btrfs/fsctl.c b/drivers/filesystems/btrfs/fsctl.c
index 039e828e962..52698383d3f 100644
--- a/drivers/filesystems/btrfs/fsctl.c
+++ b/drivers/filesystems/btrfs/fsctl.c
@@ -44,6 +44,8 @@
extern LIST_ENTRY VcbList;
extern ERESOURCE global_loading_lock;
extern PDRIVER_OBJECT drvobj;
+extern tFsRtlCheckLockForOplockRequest fFsRtlCheckLockForOplockRequest;
+extern tFsRtlAreThereCurrentOrInProgressFileLocks
fFsRtlAreThereCurrentOrInProgressFileLocks;
static void mark_subvol_dirty(device_extension* Vcb, root* r);
@@ -598,7 +600,7 @@ 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))
+ if (!is_file_name_valid(&nameus, posix, false))
return STATUS_OBJECT_NAME_INVALID;
utf8.Buffer = NULL;
@@ -820,7 +822,7 @@ 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))
+ if (!is_file_name_valid(&nameus, bcs->posix, false))
return STATUS_OBJECT_NAME_INVALID;
utf8.Buffer = NULL;
@@ -1789,7 +1791,7 @@ static NTSTATUS set_sparse(device_extension* Vcb, PFILE_OBJECT
FileObject, void*
}
mark_fcb_dirty(fcb);
- send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED,
NULL);
+ queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED,
NULL);
Status = STATUS_SUCCESS;
@@ -2059,7 +2061,7 @@ static NTSTATUS set_zero_data(device_extension* Vcb, PFILE_OBJECT
FileObject, vo
fcb->inode_item_changed = true;
mark_fcb_dirty(fcb);
- send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED,
NULL);
+ queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED,
NULL);
fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
fcb->subvol->root_item.ctime = now;
@@ -2568,22 +2570,25 @@ static void update_volumes(device_extension* Vcb) {
ExReleaseResourceLite(&Vcb->tree_lock);
}
-static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) {
+NTSTATUS dismount_volume(device_extension* Vcb, bool shutdown, PIRP Irp) {
NTSTATUS Status;
+ bool open_files;
TRACE("FSCTL_DISMOUNT_VOLUME\n");
if (!(Vcb->Vpb->Flags & VPB_MOUNTED))
return STATUS_SUCCESS;
- if (Vcb->disallow_dismount || Vcb->page_file_count != 0) {
- WARN("attempting to dismount boot volume or one containing a
pagefile\n");
- return STATUS_ACCESS_DENIED;
- }
+ if (!shutdown) {
+ if (Vcb->disallow_dismount || Vcb->page_file_count != 0) {
+ WARN("attempting to dismount boot volume or one containing a
pagefile\n");
+ return STATUS_ACCESS_DENIED;
+ }
- Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT);
- if (!NT_SUCCESS(Status)) {
- WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status);
+ Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT);
+ if (!NT_SUCCESS(Status)) {
+ WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status);
+ }
}
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
@@ -2603,6 +2608,8 @@ static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) {
Vcb->removing = true;
+ open_files = Vcb->open_files > 0;
+
if (Vcb->vde) {
update_volumes(Vcb);
Vcb->vde->mounted_device = NULL;
@@ -2610,6 +2617,9 @@ static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) {
ExReleaseResourceLite(&Vcb->tree_lock);
+ if (!open_files)
+ uninit(Vcb);
+
return STATUS_SUCCESS;
}
@@ -3647,7 +3657,7 @@ static NTSTATUS duplicate_extents(device_extension* Vcb,
PFILE_OBJECT FileObject
if (!ccb->user_set_write_time) {
fcb->inode_item.st_mtime = now;
- send_notification_fcb(ccb->fileref, FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_ACTION_MODIFIED, NULL);
+ queue_notification_fcb(ccb->fileref, FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_ACTION_MODIFIED, NULL);
}
fcb->inode_item_changed = true;
@@ -4040,7 +4050,7 @@ static NTSTATUS mknod(device_extension* Vcb, PFILE_OBJECT
FileObject, void* data
send_notification_fileref(fileref, bmn->type == BTRFS_TYPE_DIRECTORY ?
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL);
if (!parccb->user_set_write_time)
- send_notification_fcb(parfileref, FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_ACTION_MODIFIED, NULL);
+ queue_notification_fcb(parfileref, FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_ACTION_MODIFIED, NULL);
Status = STATUS_SUCCESS;
@@ -4727,6 +4737,7 @@ static NTSTATUS resize_device(device_extension* Vcb, void* data,
ULONG len, PIRP
delta = dev->devitem.num_bytes - br->size;
if (need_balance) {
+ OBJECT_ATTRIBUTES oa;
int i;
if (Vcb->balance.thread) {
@@ -4751,7 +4762,9 @@ static NTSTATUS resize_device(device_extension* Vcb, void* data,
ULONG len, PIRP
space_list_subtract2(&dev->space, NULL, br->size, delta, NULL,
NULL);
- Status = PsCreateSystemThread(&Vcb->balance.thread, 0, NULL, NULL,
NULL, balance_thread, Vcb);
+ InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ Status = PsCreateSystemThread(&Vcb->balance.thread, 0, &oa, NULL,
NULL, balance_thread, Vcb);
if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status);
goto end;
@@ -4835,57 +4848,145 @@ end:
return Status;
}
-NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t type) {
+static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* Pirp) {
+ NTSTATUS Status;
PIRP Irp = *Pirp;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
- NTSTATUS Status;
+ uint32_t fsctl = IrpSp->Parameters.FileSystemControl.FsControlCode;
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ fcb* fcb = FileObject ? FileObject->FsContext : NULL;
+ ccb* ccb = FileObject ? FileObject->FsContext2 : NULL;
+ file_ref* fileref = ccb ? ccb->fileref : NULL;
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+ PREQUEST_OPLOCK_INPUT_BUFFER buf = NULL;
+ bool oplock_request = false, oplock_ack = false;
+#else
+ bool oplock_request = false;
+#endif
+ ULONG oplock_count = 0;
+#ifdef __REACTOS__
+ bool shared_request;
+#endif
+
+ if (!fcb) {
+ ERR("fcb was NULL\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!fileref) {
+ ERR("fileref was NULL\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (fcb->type != BTRFS_TYPE_FILE && fcb->type != BTRFS_TYPE_DIRECTORY)
+ return STATUS_INVALID_PARAMETER;
- switch (type) {
#if (NTDDI_VERSION >= NTDDI_WIN7)
- case FSCTL_REQUEST_OPLOCK:
- WARN("STUB: FSCTL_REQUEST_OPLOCK\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ if (fsctl == FSCTL_REQUEST_OPLOCK) {
+ if (IrpSp->Parameters.FileSystemControl.InputBufferLength <
sizeof(REQUEST_OPLOCK_INPUT_BUFFER))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ if (IrpSp->Parameters.FileSystemControl.OutputBufferLength <
sizeof(REQUEST_OPLOCK_OUTPUT_BUFFER))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ buf = Irp->AssociatedIrp.SystemBuffer;
+
+ // flags are mutually exclusive
+ if (buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_REQUEST &&
buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_ACK)
+ return STATUS_INVALID_PARAMETER;
+
+ oplock_request = buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_REQUEST;
+ oplock_ack = buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_ACK;
+
+ if (!oplock_request && !oplock_ack)
+ return STATUS_INVALID_PARAMETER;
+ }
#endif
- case FSCTL_REQUEST_OPLOCK_LEVEL_1:
- WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_1\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+ bool shared_request = (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2) || (fsctl ==
FSCTL_REQUEST_OPLOCK && !(buf->RequestedOplockLevel &
OPLOCK_LEVEL_CACHE_WRITE));
+#else
+ shared_request = (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2);
+#endif
- case FSCTL_REQUEST_OPLOCK_LEVEL_2:
- WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_2\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+ if (fcb->type == BTRFS_TYPE_DIRECTORY && (fsctl != FSCTL_REQUEST_OPLOCK ||
!shared_request)) {
+#else
+ if (fcb->type == BTRFS_TYPE_DIRECTORY && !shared_request) {
+#endif
+ WARN("oplock requests on directories can only be for read or read-handle
oplocks\n");
+ return STATUS_INVALID_PARAMETER;
+ }
- case FSCTL_REQUEST_BATCH_OPLOCK:
- WARN("STUB: FSCTL_REQUEST_BATCH_OPLOCK\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
- case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
- WARN("STUB: FSCTL_OPLOCK_BREAK_ACKNOWLEDGE\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ 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);
- case FSCTL_OPLOCK_BREAK_ACK_NO_2:
- WARN("STUB: FSCTL_OPLOCK_BREAK_ACK_NO_2\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ if (shared_request) {
+ if (fcb->type == BTRFS_TYPE_FILE) {
+ if (fFsRtlCheckLockForOplockRequest)
+ oplock_count = !fFsRtlCheckLockForOplockRequest(&fcb->lock,
&fcb->Header.AllocationSize);
+ else if (fFsRtlAreThereCurrentOrInProgressFileLocks)
+ oplock_count =
fFsRtlAreThereCurrentOrInProgressFileLocks(&fcb->lock);
+ else
+ oplock_count = FsRtlAreThereCurrentFileLocks(&fcb->lock);
+ }
+ } else
+ oplock_count = fileref->open_count;
+ } else
+ ExAcquireResourceSharedLite(fcb->Header.Resource, true);
- case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
- WARN("STUB: FSCTL_OPBATCH_ACK_CLOSE_PENDING\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+ if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK ||
+ (fsctl == FSCTL_REQUEST_OPLOCK && buf->RequestedOplockLevel &
OPLOCK_LEVEL_CACHE_HANDLE)) &&
+#else
+ if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK)
&&
+#endif
+ fileref->delete_on_close) {
+ ExReleaseResourceLite(fcb->Header.Resource);
+ ExReleaseResourceLite(&Vcb->tree_lock);
+ return STATUS_DELETE_PENDING;
+ }
- case FSCTL_OPLOCK_BREAK_NOTIFY:
- WARN("STUB: FSCTL_OPLOCK_BREAK_NOTIFY\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ Status = FsRtlOplockFsctrl(fcb_oplock(fcb), Irp, oplock_count);
+
+ *Pirp = NULL;
+
+ fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
+ ExReleaseResourceLite(fcb->Header.Resource);
+ ExReleaseResourceLite(&Vcb->tree_lock);
+
+ return Status;
+}
+
+NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t type) {
+ PIRP Irp = *Pirp;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ NTSTATUS Status;
+
+ if (IrpSp->FileObject && IrpSp->FileObject->FsContext) {
+ device_extension* Vcb = DeviceObject->DeviceExtension;
+
+ if (Vcb->type == VCB_TYPE_FS)
+ FsRtlCheckOplock(fcb_oplock(IrpSp->FileObject->FsContext), Irp, NULL,
NULL, NULL);
+ }
+
+ switch (type) {
+ case FSCTL_REQUEST_OPLOCK_LEVEL_1:
+ case FSCTL_REQUEST_OPLOCK_LEVEL_2:
+ case FSCTL_REQUEST_BATCH_OPLOCK:
+ case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
+ case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
+ case FSCTL_OPLOCK_BREAK_NOTIFY:
+ case FSCTL_OPLOCK_BREAK_ACK_NO_2:
case FSCTL_REQUEST_FILTER_OPLOCK:
- WARN("STUB: FSCTL_REQUEST_FILTER_OPLOCK\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+ case FSCTL_REQUEST_OPLOCK:
+#endif
+ Status = fsctl_oplock(DeviceObject->DeviceExtension, Pirp);
break;
case FSCTL_LOCK_VOLUME:
@@ -4897,7 +4998,7 @@ NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp,
uint32_t type) {
break;
case FSCTL_DISMOUNT_VOLUME:
- Status = dismount_volume(DeviceObject->DeviceExtension, Irp);
+ Status = dismount_volume(DeviceObject->DeviceExtension, false, Irp);
break;
case FSCTL_IS_VOLUME_MOUNTED:
diff --git a/drivers/filesystems/btrfs/fsrtl.c b/drivers/filesystems/btrfs/fsrtl.c
index 8654d84e5ae..fab85bc6572 100644
--- a/drivers/filesystems/btrfs/fsrtl.c
+++ b/drivers/filesystems/btrfs/fsrtl.c
@@ -29,7 +29,7 @@ IsEven(IN USHORT Digit)
return ((Digit & 1) != 1);
}
-NTSTATUS compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN
PREPARSE_DATA_BUFFER ReparseBuffer)
+NTSTATUS __stdcall compat_FsRtlValidateReparsePointBuffer(IN ULONG BufferLength, IN
PREPARSE_DATA_BUFFER ReparseBuffer)
{
USHORT DataLength;
ULONG ReparseTag;
diff --git a/drivers/filesystems/btrfs/pnp.c b/drivers/filesystems/btrfs/pnp.c
index 2b012ed002c..3313d82831b 100644
--- a/drivers/filesystems/btrfs/pnp.c
+++ b/drivers/filesystems/btrfs/pnp.c
@@ -185,14 +185,15 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP
Irp) {
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
if (Vcb->root_fileref && Vcb->root_fileref->fcb &&
(Vcb->root_fileref->open_count > 0 || has_open_children(Vcb->root_fileref)))
{
- Status = STATUS_ACCESS_DENIED;
- goto end;
+ ExReleaseResourceLite(&Vcb->tree_lock);
+ return STATUS_ACCESS_DENIED;
}
Status = send_disks_pnp_message(Vcb, IRP_MN_QUERY_REMOVE_DEVICE);
if (!NT_SUCCESS(Status)) {
WARN("send_disks_pnp_message returned %08x\n", Status);
- goto end;
+ ExReleaseResourceLite(&Vcb->tree_lock);
+ return Status;
}
Vcb->removing = true;
@@ -204,16 +205,17 @@ NTSTATUS pnp_query_remove_device(PDEVICE_OBJECT DeviceObject, PIRP
Irp) {
if (!NT_SUCCESS(Status)) {
ERR("do_write returned %08x\n", Status);
- goto end;
+ ExReleaseResourceLite(&Vcb->tree_lock);
+ return Status;
}
}
-
- Status = STATUS_SUCCESS;
-end:
ExReleaseResourceLite(&Vcb->tree_lock);
- return Status;
+ if (Vcb->open_files == 0)
+ uninit(Vcb);
+
+ return STATUS_SUCCESS;
}
static NTSTATUS pnp_remove_device(PDEVICE_OBJECT DeviceObject) {
@@ -294,7 +296,10 @@ static NTSTATUS bus_query_device_relations(PIRP Irp) {
le = pdo_list.Flink;
while (le != &pdo_list) {
- num_children++;
+ pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension,
list_entry);
+
+ if (!pdode->dont_report)
+ num_children++;
le = le->Flink;
}
@@ -315,9 +320,11 @@ static NTSTATUS bus_query_device_relations(PIRP Irp) {
while (le != &pdo_list) {
pdo_device_extension* pdode = CONTAINING_RECORD(le, pdo_device_extension,
list_entry);
- ObReferenceObject(pdode->pdo);
- dr->Objects[i] = pdode->pdo;
- i++;
+ if (!pdode->dont_report) {
+ ObReferenceObject(pdode->pdo);
+ dr->Objects[i] = pdode->pdo;
+ i++;
+ }
le = le->Flink;
}
@@ -539,6 +546,29 @@ static NTSTATUS pdo_device_usage_notification(pdo_device_extension*
pdode, PIRP
return STATUS_SUCCESS;
}
+static NTSTATUS pdo_query_device_relations(PDEVICE_OBJECT pdo, PIRP Irp) {
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ PDEVICE_RELATIONS device_relations;
+
+ if (IrpSp->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
+ return Irp->IoStatus.Status;
+
+ device_relations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS),
ALLOC_TAG);
+ if (!device_relations) {
+ ERR("out of memory\n");
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ device_relations->Count = 1;
+ device_relations->Objects[0] = pdo;
+
+ ObReferenceObject(pdo);
+
+ Irp->IoStatus.Information = (ULONG_PTR)device_relations;
+
+ return STATUS_SUCCESS;
+}
+
static NTSTATUS pdo_pnp(PDEVICE_OBJECT pdo, PIRP Irp) {
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
pdo_device_extension* pdode = pdo->DeviceExtension;
@@ -559,6 +589,8 @@ static NTSTATUS pdo_pnp(PDEVICE_OBJECT pdo, PIRP Irp) {
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
return pdo_device_usage_notification(pdode, Irp);
+ case IRP_MN_QUERY_DEVICE_RELATIONS:
+ return pdo_query_device_relations(pdo, Irp);
}
return Irp->IoStatus.Status;
diff --git a/drivers/filesystems/btrfs/read.c b/drivers/filesystems/btrfs/read.c
index 5934821beb2..ae7a270bb18 100644
--- a/drivers/filesystems/btrfs/read.c
+++ b/drivers/filesystems/btrfs/read.c
@@ -3114,7 +3114,7 @@ NTSTATUS do_read(PIRP Irp, bool wait, ULONG* bytes_read) {
if (!fcb || !fcb->Vcb || !fcb->subvol)
return STATUS_INTERNAL_ERROR;
- TRACE("file = %S (fcb = %p)\n", file_desc(FileObject), fcb);
+ TRACE("fcb = %p\n", fcb);
TRACE("offset = %I64x, length = %x\n", start, length);
TRACE("paging_io = %s, no cache = %s\n", Irp->Flags & IRP_PAGING_IO
? "true" : "false", Irp->Flags & IRP_NOCACHE ? "true"
: "false");
@@ -3318,6 +3318,9 @@ NTSTATUS __stdcall drv_read(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
goto exit2;
}
+ if (!(Irp->Flags & IRP_PAGING_IO))
+ FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
+
wait = IoIsOperationSynchronous(Irp);
// Don't offload jobs when doing paging IO - otherwise this can lead to
diff --git a/drivers/filesystems/btrfs/registry.c b/drivers/filesystems/btrfs/registry.c
index a13baf35aba..398d700b637 100644
--- a/drivers/filesystems/btrfs/registry.c
+++ b/drivers/filesystems/btrfs/registry.c
@@ -37,7 +37,8 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
BTRFS_UUID* uuid = &Vcb->superblock.uuid;
mount_options* options = &Vcb->options;
UNICODE_STRING path, ignoreus, compressus, compressforceus, compresstypeus,
readonlyus, zliblevelus, flushintervalus,
- maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus,
clearcacheus, allowdegradedus, zstdlevelus;
+ maxinlineus, subvolidus, skipbalanceus, nobarrierus, notrimus,
clearcacheus, allowdegradedus, zstdlevelus,
+ norootdirus;
OBJECT_ATTRIBUTES oa;
NTSTATUS Status;
ULONG i, j, kvfilen, index, retlen;
@@ -121,6 +122,7 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
RtlInitUnicodeString(&clearcacheus, L"ClearCache");
RtlInitUnicodeString(&allowdegradedus, L"AllowDegraded");
RtlInitUnicodeString(&zstdlevelus, L"ZstdLevel");
+ RtlInitUnicodeString(&norootdirus, L"NoRootDir");
do {
Status = ZwEnumerateValueKey(h, index, KeyValueFullInformation, kvfi, kvfilen,
&retlen);
@@ -193,6 +195,10 @@ NTSTATUS registry_load_volume_options(device_extension* Vcb) {
DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
options->zstd_level = *val;
+ } else if (FsRtlAreNamesEqual(&norootdirus, &us, true, NULL)
&& kvfi->DataOffset > 0 && kvfi->DataLength > 0 &&
kvfi->Type == REG_DWORD) {
+ DWORD* val = (DWORD*)((uint8_t*)kvfi + kvfi->DataOffset);
+
+ options->no_root_dir = *val;
}
} else if (Status != STATUS_NO_MORE_ENTRIES) {
ERR("ZwEnumerateValueKey returned %08x\n", Status);
@@ -805,6 +811,7 @@ void read_registry(PUNICODE_STRING regpath, bool refresh) {
get_registry_value(h, L"AllowDegraded", REG_DWORD,
&mount_allow_degraded, sizeof(mount_allow_degraded));
get_registry_value(h, L"Readonly", REG_DWORD, &mount_readonly,
sizeof(mount_readonly));
get_registry_value(h, L"ZstdLevel", REG_DWORD, &mount_zstd_level,
sizeof(mount_zstd_level));
+ get_registry_value(h, L"NoRootDir", REG_DWORD, &mount_no_root_dir,
sizeof(mount_no_root_dir));
if (!refresh)
get_registry_value(h, L"NoPNP", REG_DWORD, &no_pnp,
sizeof(no_pnp));
diff --git a/drivers/filesystems/btrfs/reparse.c b/drivers/filesystems/btrfs/reparse.c
index fb6a98808b8..a926bbd4a73 100644
--- a/drivers/filesystems/btrfs/reparse.c
+++ b/drivers/filesystems/btrfs/reparse.c
@@ -414,8 +414,6 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
fcb = fileref->fcb;
}
- TRACE("%S\n", file_desc(FileObject));
-
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
@@ -425,7 +423,7 @@ NTSTATUS set_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
goto end;
}
- send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL);
+ queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL);
end:
if (NT_SUCCESS(Status))
@@ -488,8 +486,6 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
- TRACE("%S\n", file_desc(FileObject));
-
if (buflen < offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) {
ERR("buffer was too short\n");
Status = STATUS_INVALID_PARAMETER;
@@ -619,7 +615,7 @@ NTSTATUS delete_reparse_point(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
Status = STATUS_SUCCESS;
- send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL);
+ queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_ATTRIBUTES, FILE_ACTION_MODIFIED, NULL);
end:
if (NT_SUCCESS(Status))
diff --git a/drivers/filesystems/btrfs/scrub.c b/drivers/filesystems/btrfs/scrub.c
index d1994b7fe63..e4d70d02e5e 100644
--- a/drivers/filesystems/btrfs/scrub.c
+++ b/drivers/filesystems/btrfs/scrub.c
@@ -3265,6 +3265,7 @@ end:
NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE processor_mode) {
NTSTATUS Status;
+ OBJECT_ATTRIBUTES oa;
if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE),
processor_mode))
return STATUS_PRIVILEGE_NOT_HELD;
@@ -3292,7 +3293,9 @@ NTSTATUS start_scrub(device_extension* Vcb, KPROCESSOR_MODE
processor_mode) {
Vcb->scrub.error = STATUS_SUCCESS;
KeInitializeEvent(&Vcb->scrub.event, NotificationEvent,
!Vcb->scrub.paused);
- Status = PsCreateSystemThread(&Vcb->scrub.thread, 0, NULL, NULL, NULL,
scrub_thread, Vcb);
+ InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ Status = PsCreateSystemThread(&Vcb->scrub.thread, 0, &oa, NULL, NULL,
scrub_thread, Vcb);
if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status);
return Status;
diff --git a/drivers/filesystems/btrfs/search.c b/drivers/filesystems/btrfs/search.c
index a1a4217aec9..3d824d9f767 100644
--- a/drivers/filesystems/btrfs/search.c
+++ b/drivers/filesystems/btrfs/search.c
@@ -23,6 +23,7 @@
#include <windef.h>
#include <ntddstor.h>
#include <ntdddisk.h>
+#include <ntddvol.h>
#include <initguid.h>
#include <wdmguid.h>
@@ -35,6 +36,7 @@ extern HANDLE mountmgr_thread_handle;
extern bool shutting_down;
extern PDEVICE_OBJECT busobj;
extern tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx;
+extern ERESOURCE boot_lock;
typedef void (*pnp_callback)(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath);
@@ -270,8 +272,11 @@ void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING
devpath) {
UNUSED(DriverObject);
+ ExAcquireResourceSharedLite(&boot_lock, TRUE);
+
Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &fileobj,
&devobj);
if (!NT_SUCCESS(Status)) {
+ ExReleaseResourceLite(&boot_lock);
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
return;
}
@@ -323,6 +328,8 @@ void disk_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING
devpath) {
end:
ObDereferenceObject(fileobj);
+
+ ExReleaseResourceLite(&boot_lock);
}
void remove_volume_child(_Inout_ _Requires_exclusive_lock_held_(_Curr_->child_lock)
_Releases_exclusive_lock_(_Curr_->child_lock) _In_ volume_device_extension* vde,
@@ -496,8 +503,11 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING
devpath) {
TRACE("%.*S\n", devpath->Length / sizeof(WCHAR), devpath->Buffer);
+ ExAcquireResourceSharedLite(&boot_lock, TRUE);
+
Status = IoGetDeviceObjectPointer(devpath, FILE_READ_ATTRIBUTES, &fileobj,
&devobj);
if (!NT_SUCCESS(Status)) {
+ ExReleaseResourceLite(&boot_lock);
ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
return;
}
@@ -507,6 +517,10 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING
devpath) {
if (devobj->DriverObject == DriverObject)
goto end;
+ Status = dev_ioctl(devobj, IOCTL_VOLUME_ONLINE, NULL, 0, NULL, 0, true, NULL);
+ if (!NT_SUCCESS(Status))
+ TRACE("IOCTL_VOLUME_ONLINE returned %08x\n", Status);
+
Status = dev_ioctl(devobj, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli,
sizeof(gli), true, NULL);
if (!NT_SUCCESS(Status)) {
ERR("IOCTL_DISK_GET_LENGTH_INFO returned %08x\n", Status);
@@ -570,6 +584,8 @@ void volume_arrival(PDRIVER_OBJECT DriverObject, PUNICODE_STRING
devpath) {
end:
ObDereferenceObject(fileobj);
+
+ ExReleaseResourceLite(&boot_lock);
}
void volume_removal(PDRIVER_OBJECT DriverObject, PUNICODE_STRING devpath) {
@@ -648,6 +664,8 @@ static void __stdcall do_pnp_callback(PDEVICE_OBJECT DeviceObject,
PVOID con) {
ExFreePool(context->name.Buffer);
IoFreeWorkItem(context->work_item);
+
+ ExFreePool(context);
}
static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject, PUNICODE_STRING name,
pnp_callback func) {
@@ -655,6 +673,10 @@ static void enqueue_pnp_callback(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING na
pnp_callback_context* context;
work_item = IoAllocateWorkItem(master_devobj);
+ if (!work_item) {
+ ERR("out of memory\n");
+ return;
+ }
context = ExAllocatePoolWithTag(PagedPool, sizeof(pnp_callback_context), ALLOC_TAG);
diff --git a/drivers/filesystems/btrfs/security.c b/drivers/filesystems/btrfs/security.c
index 42ff987723a..bf5cff0fdfc 100644
--- a/drivers/filesystems/btrfs/security.c
+++ b/drivers/filesystems/btrfs/security.c
@@ -432,7 +432,7 @@ static void get_top_level_sd(fcb* fcb) {
goto end;
}
- RtlSetOwnerSecurityDescriptor(&sd, usersid, false);
+ Status = RtlSetOwnerSecurityDescriptor(&sd, usersid, false);
if (!NT_SUCCESS(Status)) {
ERR("RtlSetOwnerSecurityDescriptor returned %08x\n", Status);
@@ -442,11 +442,10 @@ static void get_top_level_sd(fcb* fcb) {
gid_to_sid(fcb->inode_item.st_gid, &groupsid);
if (!groupsid) {
ERR("out of memory\n");
- Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
- RtlSetGroupSecurityDescriptor(&sd, groupsid, false);
+ Status = RtlSetGroupSecurityDescriptor(&sd, groupsid, false);
if (!NT_SUCCESS(Status)) {
ERR("RtlSetGroupSecurityDescriptor returned %08x\n", Status);
@@ -486,7 +485,6 @@ static void get_top_level_sd(fcb* fcb) {
fcb->sd = ExAllocatePoolWithTag(PagedPool, buflen, ALLOC_TAG);
if (!fcb->sd) {
ERR("out of memory\n");
- Status = STATUS_INSUFFICIENT_RESOURCES;
goto end;
}
@@ -494,6 +492,8 @@ static void get_top_level_sd(fcb* fcb) {
if (!NT_SUCCESS(Status)) {
ERR("RtlAbsoluteToSelfRelativeSD 2 returned %08x\n", Status);
+ ExFreePool(fcb->sd);
+ fcb->sd = NULL;
goto end;
}
@@ -528,6 +528,7 @@ void fcb_get_sd(fcb* fcb, struct _fcb* parent, bool look_for_xattr,
PIRP Irp) {
&subjcont, IoGetFileObjectGenericMapping(),
PagedPool);
if (!NT_SUCCESS(Status)) {
ERR("SeAssignSecurityEx returned %08x\n", Status);
+ return;
}
Status = uid_to_sid(fcb->inode_item.st_uid, &usersid);
@@ -541,6 +542,7 @@ void fcb_get_sd(fcb* fcb, struct _fcb* parent, bool look_for_xattr,
PIRP Irp) {
gid_to_sid(fcb->inode_item.st_gid, &groupsid);
if (!groupsid) {
ERR("out of memory\n");
+ ExFreePool(usersid);
return;
}
@@ -733,7 +735,7 @@ static NTSTATUS set_file_security(device_extension* Vcb, PFILE_OBJECT
FileObject
mark_fcb_dirty(fcb);
- send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED,
NULL);
+ queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED,
NULL);
end:
ExReleaseResourceLite(fcb->Header.Resource);
diff --git a/drivers/filesystems/btrfs/send.c b/drivers/filesystems/btrfs/send.c
index 4737be0a85a..2090131dc99 100644
--- a/drivers/filesystems/btrfs/send.c
+++ b/drivers/filesystems/btrfs/send.c
@@ -3598,6 +3598,7 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG
datalen, PFILE_OBJ
send_info* send;
ULONG num_clones = 0;
root** clones = NULL;
+ OBJECT_ATTRIBUTES oa;
if (!FileObject || !FileObject->FsContext || !FileObject->FsContext2 ||
FileObject->FsContext == Vcb->volume_fcb)
return STATUS_INVALID_PARAMETER;
@@ -3810,7 +3811,9 @@ NTSTATUS send_subvol(device_extension* Vcb, void* data, ULONG
datalen, PFILE_OBJ
InterlockedIncrement(&Vcb->running_sends);
- Status = PsCreateSystemThread(&send->thread, 0, NULL, NULL, NULL, send_thread,
context);
+ InitializeObjectAttributes(&oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
+
+ Status = PsCreateSystemThread(&send->thread, 0, &oa, NULL, NULL,
send_thread, context);
if (!NT_SUCCESS(Status)) {
ERR("PsCreateSystemThread returned %08x\n", Status);
ccb->send = NULL;
diff --git a/drivers/filesystems/btrfs/volume.c b/drivers/filesystems/btrfs/volume.c
index d50852b5952..0718bb8d9de 100644
--- a/drivers/filesystems/btrfs/volume.c
+++ b/drivers/filesystems/btrfs/volume.c
@@ -31,6 +31,7 @@ extern PDEVICE_OBJECT busobj;
extern ERESOURCE pdo_list_lock;
extern LIST_ENTRY pdo_list;
extern UNICODE_STRING registry_path;
+extern tIoUnregisterPlugPlayNotificationEx fIoUnregisterPlugPlayNotificationEx;
NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
volume_device_extension* vde = DeviceObject->DeviceExtension;
@@ -46,6 +47,51 @@ NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
return STATUS_SUCCESS;
}
+void free_vol(volume_device_extension* vde) {
+ PDEVICE_OBJECT pdo;
+
+ vde->dead = true;
+
+ if (vde->mounted_device) {
+ device_extension* Vcb = vde->mounted_device->DeviceExtension;
+
+ Vcb->vde = NULL;
+ }
+
+ if (vde->name.Buffer)
+ ExFreePool(vde->name.Buffer);
+
+ ExDeleteResourceLite(&vde->pdode->child_lock);
+
+ if (vde->pdo->AttachedDevice)
+ IoDetachDevice(vde->pdo);
+
+ while (!IsListEmpty(&vde->pdode->children)) {
+ volume_child* vc =
CONTAINING_RECORD(RemoveHeadList(&vde->pdode->children), volume_child,
list_entry);
+
+ if (vc->notification_entry) {
+ if (fIoUnregisterPlugPlayNotificationEx)
+ fIoUnregisterPlugPlayNotificationEx(vc->notification_entry);
+ else
+ IoUnregisterPlugPlayNotification(vc->notification_entry);
+ }
+
+ if (vc->pnp_name.Buffer)
+ ExFreePool(vc->pnp_name.Buffer);
+
+ ExFreePool(vc);
+ }
+
+ if (no_pnp)
+ ExFreePool(vde->pdode);
+
+ pdo = vde->pdo;
+ IoDeleteDevice(vde->device);
+
+ if (!no_pnp)
+ IoDeleteDevice(pdo);
+}
+
NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
volume_device_extension* vde = DeviceObject->DeviceExtension;
pdo_device_extension* pdode = vde->pdode;
@@ -54,47 +100,22 @@ NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
Irp->IoStatus.Information = 0;
+ if (vde->dead)
+ return STATUS_SUCCESS;
+
ExAcquireResourceExclusiveLite(&pdo_list_lock, true);
+ if (vde->dead) {
+ ExReleaseResourceLite(&pdo_list_lock);
+ return STATUS_SUCCESS;
+ }
+
ExAcquireResourceSharedLite(&pdode->child_lock, true);
if (InterlockedDecrement(&vde->open_count) == 0 && vde->removing)
{
- NTSTATUS Status;
- UNICODE_STRING mmdevpath;
- PDEVICE_OBJECT mountmgr;
- PFILE_OBJECT mountmgrfo;
- PDEVICE_OBJECT pdo;
-
- RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
- Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES,
&mountmgrfo, &mountmgr);
- if (!NT_SUCCESS(Status))
- ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
- else {
- remove_drive_letter(mountmgr, &vde->name);
-
- ObDereferenceObject(mountmgrfo);
- }
-
- if (vde->mounted_device) {
- device_extension* Vcb = vde->mounted_device->DeviceExtension;
-
- Vcb->vde = NULL;
- }
-
- if (vde->name.Buffer)
- ExFreePool(vde->name.Buffer);
-
ExReleaseResourceLite(&pdode->child_lock);
- ExDeleteResourceLite(&pdode->child_lock);
-
- if (vde->pdo->AttachedDevice)
- IoDetachDevice(vde->pdo);
-
- pdo = vde->pdo;
- IoDeleteDevice(vde->device);
- if (!no_pnp)
- IoDeleteDevice(pdo);
+ free_vol(vde);
} else
ExReleaseResourceLite(&pdode->child_lock);
@@ -767,6 +788,8 @@ static NTSTATUS vol_ioctl_passthrough(volume_device_extension* vde,
PIRP Irp) {
ExReleaseResourceLite(&pdode->child_lock);
+ IoFreeIrp(Irp2);
+
return Status;
}
@@ -998,108 +1021,129 @@ end:
}
typedef struct {
- PIO_WORKITEM work_item;
- pdo_device_extension* pdode;
-} drive_letter_callback_context;
-
-_Function_class_(IO_WORKITEM_ROUTINE)
-static void __stdcall drive_letter_callback(PDEVICE_OBJECT DeviceObject, PVOID con) {
- drive_letter_callback_context* context = con;
+ LIST_ENTRY list_entry;
+ UNICODE_STRING name;
NTSTATUS Status;
- UNICODE_STRING mmdevpath;
- PDEVICE_OBJECT mountmgr;
- PFILE_OBJECT mountmgrfo;
- LIST_ENTRY* le;
-
- UNUSED(DeviceObject);
+ BTRFS_UUID uuid;
+} drive_letter_removal;
- RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
- Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES,
&mountmgrfo, &mountmgr);
- if (!NT_SUCCESS(Status)) {
- ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
- return;
- }
-
- 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);
+static void drive_letter_callback2(pdo_device_extension* pdode, PDEVICE_OBJECT mountmgr)
{
+ LIST_ENTRY* le;
+ LIST_ENTRY dlrlist;
- if (pdode == context->pdode) {
- LIST_ENTRY* le2;
+ InitializeListHead(&dlrlist);
- ExAcquireResourceExclusiveLite(&pdode->child_lock, true);
+ ExAcquireResourceExclusiveLite(&pdode->child_lock, true);
- le2 = pdode->children.Flink;
+ le = pdode->children.Flink;
- while (le2 != &pdode->children) {
- UNICODE_STRING name;
+ while (le != &pdode->children) {
+ drive_letter_removal* dlr;
- volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry);
+ volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
- name.Length = name.MaximumLength = vc->pnp_name.Length + (3 *
sizeof(WCHAR));
- name.Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG);
+ dlr = ExAllocatePoolWithTag(PagedPool, sizeof(drive_letter_removal), ALLOC_TAG);
+ if (!dlr) {
+ ERR("out of memory\n");
- if (!name.Buffer) {
- ERR("out of memory\n");
+ while (!IsListEmpty(&dlrlist)) {
+ dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist),
drive_letter_removal, list_entry);
- ExReleaseResourceLite(&pdode->child_lock);
- ExReleaseResourceLite(&pdo_list_lock);
- ObDereferenceObject(mountmgrfo);
- IoFreeWorkItem(context->work_item);
- return;
- }
+ ExFreePool(dlr->name.Buffer);
+ ExFreePool(dlr);
+ }
- RtlCopyMemory(name.Buffer, L"\\??", 3 * sizeof(WCHAR));
- RtlCopyMemory(&name.Buffer[3], vc->pnp_name.Buffer,
vc->pnp_name.Length);
+ ExReleaseResourceLite(&pdode->child_lock);
+ return;
+ }
- Status = remove_drive_letter(mountmgr, &name);
+ dlr->name.Length = dlr->name.MaximumLength = vc->pnp_name.Length + (3 *
sizeof(WCHAR));
+ dlr->name.Buffer = ExAllocatePoolWithTag(PagedPool, dlr->name.Length,
ALLOC_TAG);
- if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND)
- WARN("remove_drive_letter returned %08x\n", Status);
+ if (!dlr->name.Buffer) {
+ ERR("out of memory\n");
- ExFreePool(name.Buffer);
+ ExFreePool(dlr);
- vc->had_drive_letter = NT_SUCCESS(Status);
+ while (!IsListEmpty(&dlrlist)) {
+ dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist),
drive_letter_removal, list_entry);
- le2 = le2->Flink;
+ ExFreePool(dlr->name.Buffer);
+ ExFreePool(dlr);
}
ExReleaseResourceLite(&pdode->child_lock);
- ExReleaseResourceLite(&pdo_list_lock);
- ObDereferenceObject(mountmgrfo);
- IoFreeWorkItem(context->work_item);
return;
}
+ RtlCopyMemory(dlr->name.Buffer, L"\\??", 3 * sizeof(WCHAR));
+ RtlCopyMemory(&dlr->name.Buffer[3], vc->pnp_name.Buffer,
vc->pnp_name.Length);
+
+ dlr->uuid = vc->uuid;
+
+ InsertTailList(&dlrlist, &dlr->list_entry);
+
le = le->Flink;
}
- ExReleaseResourceLite(&pdo_list_lock);
+ ExReleaseResourceLite(&pdode->child_lock);
- ObDereferenceObject(mountmgrfo);
- IoFreeWorkItem(context->work_item);
-}
+ le = dlrlist.Flink;
+ while (le != &dlrlist) {
+ drive_letter_removal* dlr = CONTAINING_RECORD(le, drive_letter_removal,
list_entry);
-static void add_drive_letter_work_item(pdo_device_extension* pdode) {
- PIO_WORKITEM work_item;
- drive_letter_callback_context* context;
+ dlr->Status = remove_drive_letter(mountmgr, &dlr->name);
- work_item = IoAllocateWorkItem(master_devobj);
+ if (!NT_SUCCESS(dlr->Status) && dlr->Status != STATUS_NOT_FOUND)
+ WARN("remove_drive_letter returned %08x\n", dlr->Status);
- context = ExAllocatePoolWithTag(PagedPool, sizeof(drive_letter_callback_context),
ALLOC_TAG);
+ le = le->Flink;
+ }
- if (!context) {
- ERR("out of memory\n");
- IoFreeWorkItem(work_item);
+ // set vc->had_drive_letter
+
+ ExAcquireResourceExclusiveLite(&pdode->child_lock, true);
+
+ while (!IsListEmpty(&dlrlist)) {
+ drive_letter_removal* dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist),
drive_letter_removal, list_entry);
+
+ le = pdode->children.Flink;
+
+ while (le != &pdode->children) {
+ volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
+
+ if (RtlCompareMemory(&vc->uuid, &dlr->uuid, sizeof(BTRFS_UUID))
== sizeof(BTRFS_UUID)) {
+ vc->had_drive_letter = NT_SUCCESS(dlr->Status);
+ break;
+ }
+
+ le = le->Flink;
+ }
+
+ ExFreePool(dlr->name.Buffer);
+ ExFreePool(dlr);
+ }
+
+ ExReleaseResourceLite(&pdode->child_lock);
+}
+
+_Function_class_(IO_WORKITEM_ROUTINE)
+static void __stdcall drive_letter_callback(pdo_device_extension* pdode) {
+ NTSTATUS Status;
+ UNICODE_STRING mmdevpath;
+ PDEVICE_OBJECT mountmgr;
+ PFILE_OBJECT mountmgrfo;
+
+ RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
+ Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES,
&mountmgrfo, &mountmgr);
+ if (!NT_SUCCESS(Status)) {
+ ERR("IoGetDeviceObjectPointer returned %08x\n", Status);
return;
}
- context->work_item = work_item;
- context->pdode = pdode;
+ drive_letter_callback2(pdode, mountmgr);
- IoQueueWorkItem(work_item, drive_letter_callback, DelayedWorkQueue, context);
+ ObDereferenceObject(mountmgrfo);
}
void add_volume_device(superblock* sb, PUNICODE_STRING devpath, uint64_t length, ULONG
disk_num, ULONG part_num) {
@@ -1112,6 +1156,7 @@ void add_volume_device(superblock* sb, PUNICODE_STRING devpath,
uint64_t length,
bool inserted = false, new_pdo = false;
pdo_device_extension* pdode = NULL;
PDEVICE_OBJECT pdo = NULL;
+ bool process_drive_letters = false;
if (devpath->Length == 0)
return;
@@ -1312,7 +1357,7 @@ void add_volume_device(superblock* sb, PUNICODE_STRING devpath,
uint64_t length,
WARN("IoSetDeviceInterfaceState returned %08x\n", Status);
}
- add_drive_letter_work_item(pdode);
+ process_drive_letters = true;
}
ExReleaseResourceLite(&pdode->child_lock);
@@ -1322,6 +1367,9 @@ void add_volume_device(superblock* sb, PUNICODE_STRING devpath,
uint64_t length,
ExReleaseResourceLite(&pdo_list_lock);
+ if (process_drive_letters)
+ drive_letter_callback(pdode);
+
if (new_pdo) {
if (no_pnp)
AddDevice(drvobj, pdo);
diff --git a/drivers/filesystems/btrfs/write.c b/drivers/filesystems/btrfs/write.c
index c982e939b17..96ae287e02c 100644
--- a/drivers/filesystems/btrfs/write.c
+++ b/drivers/filesystems/btrfs/write.c
@@ -4164,7 +4164,7 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER
offset, void
TRACE("(%p, %p, %I64x, %p, %x, %u, %u)\n", Vcb, FileObject,
offset.QuadPart, buf, *length, paging_io, no_cache);
if (*length == 0) {
- WARN("returning success for zero-length write\n");
+ TRACE("returning success for zero-length write\n");
return STATUS_SUCCESS;
}
@@ -4231,20 +4231,18 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp,
LARGE_INTEGER offset, void
acquired_tree_lock = true;
}
- if (no_cache) {
- if (pagefile) {
- if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
- Status = STATUS_PENDING;
- goto end;
- } else
- acquired_fcb_lock = true;
- } else if (!ExIsResourceAcquiredExclusiveLite(fcb->Header.Resource)) {
- if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, wait)) {
- Status = STATUS_PENDING;
- goto end;
- } else
- acquired_fcb_lock = true;
- }
+ if (pagefile) {
+ if (!ExAcquireResourceSharedLite(fcb->Header.Resource, wait)) {
+ Status = STATUS_PENDING;
+ goto end;
+ } else
+ acquired_fcb_lock = true;
+ } else if (!ExIsResourceAcquiredExclusiveLite(fcb->Header.Resource)) {
+ if (!ExAcquireResourceExclusiveLite(fcb->Header.Resource, wait)) {
+ Status = STATUS_PENDING;
+ goto end;
+ } else
+ acquired_fcb_lock = true;
}
newlength = fcb->ads ? fcb->adsdata.Length : fcb->inode_item.st_size;
@@ -4258,7 +4256,6 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER
offset, void
if (paging_io) {
if (off64 >= newlength) {
TRACE("paging IO tried to write beyond end of file (file size =
%I64x, offset = %I64x, length = %x)\n", newlength, off64, *length);
- TRACE("filename %S\n", file_desc(FileObject));
TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x,
ValidDataLength = %I64x\n",
fcb->Header.AllocationSize.QuadPart,
fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
Status = STATUS_SUCCESS;
@@ -4354,8 +4351,8 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER
offset, void
} _SEH2_END;
if (changed_length) {
- send_notification_fcb(fcb->ads ? fileref->parent : fileref, fcb->ads
? FILE_NOTIFY_CHANGE_STREAM_SIZE : FILE_NOTIFY_CHANGE_SIZE,
- fcb->ads ? FILE_ACTION_MODIFIED_STREAM :
FILE_ACTION_MODIFIED, fcb->ads && fileref->dc ? &fileref->dc->name
: NULL);
+ queue_notification_fcb(fcb->ads ? fileref->parent : fileref,
fcb->ads ? FILE_NOTIFY_CHANGE_STREAM_SIZE : FILE_NOTIFY_CHANGE_SIZE,
+ fcb->ads ? FILE_ACTION_MODIFIED_STREAM :
FILE_ACTION_MODIFIED, fcb->ads && fileref->dc ? &fileref->dc->name
: NULL);
}
goto end;
@@ -4609,8 +4606,8 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER
offset, void
Status = STATUS_SUCCESS;
if (filter != 0)
- send_notification_fcb(fcb->ads ? fileref->parent : fileref, filter,
fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED,
- fcb->ads && fileref->dc ?
&fileref->dc->name : NULL);
+ queue_notification_fcb(fcb->ads ? fileref->parent : fileref, filter,
fcb->ads ? FILE_ACTION_MODIFIED_STREAM : FILE_ACTION_MODIFIED,
+ fcb->ads && fileref->dc ?
&fileref->dc->name : NULL);
end:
if (NT_SUCCESS(Status) && FileObject->Flags & FO_SYNCHRONOUS_IO
&& !paging_io) {
@@ -4779,6 +4776,9 @@ NTSTATUS __stdcall drv_write(IN PDEVICE_OBJECT DeviceObject, IN PIRP
Irp) {
Irp->MdlAddress = NULL;
Status = STATUS_SUCCESS;
} else {
+ if (!(Irp->Flags & IRP_PAGING_IO))
+ FsRtlCheckOplock(fcb_oplock(fcb), Irp, NULL, NULL, NULL);
+
// Don't offload jobs when doing paging IO - otherwise this can lead to
// deadlocks in CcCopyWrite.
if (Irp->Flags & IRP_PAGING_IO)
diff --git a/media/doc/README.FSD b/media/doc/README.FSD
index 534e264b010..9ce6e3a7d29 100644
--- a/media/doc/README.FSD
+++ b/media/doc/README.FSD
@@ -3,7 +3,7 @@
The following FSD are shared with:
https://github.com/maharmstone/btrfs.
-reactos/drivers/filesystems/btrfs # Synced to 1.4
+reactos/drivers/filesystems/btrfs # Synced to 1.5
reactos/dll/shellext/shellbtrfs # Synced to 1.1
reactos/sdk/lib/fslib/btrfslib # Synced to 1.4