mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
[BTRFS] Upgrade to 1.5
CORE-16494
This commit is contained in:
parent
c214c04964
commit
62e630de4c
27 changed files with 2216 additions and 566 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 - mprus.Length) / sizeof(WCHAR)];
|
||||
name.Length = name.MaximumLength = mprus.Length;
|
||||
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usmpr.Length) / sizeof(WCHAR)];
|
||||
name.Length = name.MaximumLength = usmpr.Length;
|
||||
|
||||
blacklist = FsRtlAreNamesEqual(&name, &mprus, true, NULL);
|
||||
blacklist = FsRtlAreNamesEqual(&name, &usmpr, true, NULL);
|
||||
}
|
||||
|
||||
if (!blacklist && entry->FullDllName.Length >= cmdus.Length) {
|
||||
if (!blacklist && entry->FullDllName.Length >= uscmd.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 - uscmd.Length) / sizeof(WCHAR)];
|
||||
name.Length = name.MaximumLength = uscmd.Length;
|
||||
|
||||
blacklist = FsRtlAreNamesEqual(&name, &cmdus, true, NULL);
|
||||
blacklist = FsRtlAreNamesEqual(&name, &uscmd, true, NULL);
|
||||
}
|
||||
|
||||
if (!blacklist && entry->FullDllName.Length >= fsutilus.Length) {
|
||||
if (!blacklist && entry->FullDllName.Length >= usfsutil.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 - usfsutil.Length) / sizeof(WCHAR)];
|
||||
name.Length = name.MaximumLength = usfsutil.Length;
|
||||
|
||||
blacklist = FsRtlAreNamesEqual(&name, &fsutilus, true, NULL);
|
||||
blacklist = FsRtlAreNamesEqual(&name, &usfsutil, true, NULL);
|
||||
}
|
||||
|
||||
if (!blacklist && entry->FullDllName.Length >= usstorsvc.Length) {
|
||||
UNICODE_STRING name;
|
||||
|
||||
name.Buffer = &entry->FullDllName.Buffer[(entry->FullDllName.Length - usstorsvc.Length) / sizeof(WCHAR)];
|
||||
name.Length = name.MaximumLength = usstorsvc.Length;
|
||||
|
||||
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,13 +5209,109 @@ exit:
|
|||
return Status;
|
||||
}
|
||||
|
||||
void do_shutdown(PIRP Irp) {
|
||||
LIST_ENTRY* le;
|
||||
bus_device_extension* bde;
|
||||
|
||||
shutting_down = true;
|
||||
KeSetEvent(&mountmgr_thread_event, 0, false);
|
||||
|
||||
le = VcbList.Flink;
|
||||
while (le != &VcbList) {
|
||||
LIST_ENTRY* le2 = le->Flink;
|
||||
|
||||
device_extension* Vcb = CONTAINING_RECORD(le, device_extension, list_entry);
|
||||
volume_device_extension* vde = Vcb->vde;
|
||||
|
||||
TRACE("shutting down Vcb %p\n", Vcb);
|
||||
|
||||
if (vde)
|
||||
InterlockedIncrement(&vde->open_count);
|
||||
|
||||
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("IoGetDeviceObjectPointer returned %08x\n", Status);
|
||||
else {
|
||||
remove_drive_letter(mountmgr, &vde->name);
|
||||
|
||||
ObDereferenceObject(mountmgrfo);
|
||||
}
|
||||
|
||||
vde->removing = true;
|
||||
|
||||
IoAcquireVpbSpinLock(&irql);
|
||||
vde->device->Vpb->DeviceObject = vde->device;
|
||||
IoReleaseVpbSpinLock(irql);
|
||||
|
||||
if (InterlockedDecrement(&vde->open_count) == 0)
|
||||
free_vol(vde);
|
||||
}
|
||||
|
||||
le = le2;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (comfo) {
|
||||
ObDereferenceObject(comfo);
|
||||
comdo = NULL;
|
||||
comfo = NULL;
|
||||
}
|
||||
#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;
|
||||
LIST_ENTRY* le;
|
||||
|
||||
FsRtlEnterFileSystem();
|
||||
|
||||
|
@ -5221,45 +5326,7 @@ static NTSTATUS __stdcall drv_shutdown(_In_ PDEVICE_OBJECT DeviceObject, _In_ PI
|
|||
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
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);
|
||||
|
||||
TRACE("shutting down Vcb %p\n", Vcb);
|
||||
|
||||
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
|
||||
Vcb->removing = true;
|
||||
open_files = Vcb->open_files > 0;
|
||||
|
||||
if (Vcb->need_write && !Vcb->readonly) {
|
||||
Status = do_write(Vcb, Irp);
|
||||
if (!NT_SUCCESS(Status))
|
||||
ERR("do_write returned %08x\n", Status);
|
||||
}
|
||||
|
||||
free_trees(Vcb);
|
||||
|
||||
ExReleaseResourceLite(&Vcb->tree_lock);
|
||||
|
||||
if (!open_files)
|
||||
uninit(Vcb);
|
||||
|
||||
le = le2;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (comfo) {
|
||||
ObDereferenceObject(comfo);
|
||||
comdo = NULL;
|
||||
comfo = NULL;
|
||||
}
|
||||
#endif
|
||||
do_shutdown(Irp);
|
||||
|
||||
end:
|
||||
Irp->IoStatus.Status = Status;
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 (*tFsRtlUpdateDiskCounters)(ULONG64 BytesRead, ULONG64 BytesWritten);
|
||||
typedef VOID (__stdcall *tFsRtlUpdateDiskCounters)(ULONG64 BytesRead, ULONG64 BytesWritten);
|
||||
|
||||
typedef NTSTATUS (*tIoUnregisterPlugPlayNotificationEx)(PVOID NotificationEntry);
|
||||
typedef NTSTATUS (__stdcall *tIoUnregisterPlugPlayNotificationEx)(PVOID NotificationEntry);
|
||||
|
||||
typedef NTSTATUS (*tFsRtlGetEcpListFromIrp)(PIRP Irp, PECP_LIST* EcpList);
|
||||
typedef NTSTATUS (__stdcall *tFsRtlGetEcpListFromIrp)(PIRP Irp, PECP_LIST* EcpList);
|
||||
|
||||
typedef NTSTATUS (*tFsRtlGetNextExtraCreateParameter)(PECP_LIST EcpList, PVOID CurrentEcpContext, LPGUID NextEcpType,
|
||||
PVOID* NextEcpContext, ULONG* NextEcpContextSize);
|
||||
typedef NTSTATUS (__stdcall *tFsRtlGetNextExtraCreateParameter)(PECP_LIST EcpList, PVOID CurrentEcpContext, LPGUID NextEcpType,
|
||||
PVOID* NextEcpContext, ULONG* NextEcpContextSize);
|
||||
|
||||
typedef NTSTATUS (*tFsRtlValidateReparsePointBuffer)(ULONG BufferLength, PREPARSE_DATA_BUFFER ReparseBuffer);
|
||||
typedef NTSTATUS (__stdcall *tFsRtlValidateReparsePointBuffer)(ULONG BufferLength, PREPARSE_DATA_BUFFER ReparseBuffer);
|
||||
|
||||
typedef BOOLEAN (__stdcall *tFsRtlCheckLockForOplockRequest)(PFILE_LOCK FileLock, PLARGE_INTEGER AllocationSize);
|
||||
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* Pirp) {
|
||||
NTSTATUS Status;
|
||||
PIRP Irp = *Pirp;
|
||||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||||
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;
|
||||
|
||||
#if (NTDDI_VERSION >= NTDDI_WIN7)
|
||||
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
|
||||
|
||||
#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
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
|
||||
|
||||
if (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_1 || fsctl == FSCTL_REQUEST_BATCH_OPLOCK || fsctl == FSCTL_REQUEST_FILTER_OPLOCK ||
|
||||
fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2 || oplock_request) {
|
||||
ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
|
||||
|
||||
if (shared_request) {
|
||||
if (fcb->type == BTRFS_TYPE_FILE) {
|
||||
if (fFsRtlCheckLockForOplockRequest)
|
||||
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);
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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:
|
||||
#if (NTDDI_VERSION >= NTDDI_WIN7)
|
||||
case FSCTL_REQUEST_OPLOCK:
|
||||
WARN("STUB: FSCTL_REQUEST_OPLOCK\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case FSCTL_REQUEST_OPLOCK_LEVEL_1:
|
||||
WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_1\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
|
||||
case FSCTL_REQUEST_OPLOCK_LEVEL_2:
|
||||
WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_2\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
|
||||
case FSCTL_REQUEST_BATCH_OPLOCK:
|
||||
WARN("STUB: FSCTL_REQUEST_BATCH_OPLOCK\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
|
||||
case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
|
||||
WARN("STUB: FSCTL_OPLOCK_BREAK_ACKNOWLEDGE\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
|
||||
case FSCTL_OPLOCK_BREAK_ACK_NO_2:
|
||||
WARN("STUB: FSCTL_OPLOCK_BREAK_ACK_NO_2\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
|
||||
case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
|
||||
WARN("STUB: FSCTL_OPBATCH_ACK_CLOSE_PENDING\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
|
||||
case FSCTL_OPLOCK_BREAK_NOTIFY:
|
||||
WARN("STUB: FSCTL_OPLOCK_BREAK_NOTIFY\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
break;
|
||||
|
||||
case FSCTL_REQUEST_FILTER_OPLOCK:
|
||||
WARN("STUB: FSCTL_REQUEST_FILTER_OPLOCK\n");
|
||||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||||
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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,20 +1021,118 @@ end:
|
|||
}
|
||||
|
||||
typedef struct {
|
||||
PIO_WORKITEM work_item;
|
||||
pdo_device_extension* pdode;
|
||||
} drive_letter_callback_context;
|
||||
LIST_ENTRY list_entry;
|
||||
UNICODE_STRING name;
|
||||
NTSTATUS Status;
|
||||
BTRFS_UUID uuid;
|
||||
} drive_letter_removal;
|
||||
|
||||
static void drive_letter_callback2(pdo_device_extension* pdode, PDEVICE_OBJECT mountmgr) {
|
||||
LIST_ENTRY* le;
|
||||
LIST_ENTRY dlrlist;
|
||||
|
||||
InitializeListHead(&dlrlist);
|
||||
|
||||
ExAcquireResourceExclusiveLite(&pdode->child_lock, true);
|
||||
|
||||
le = pdode->children.Flink;
|
||||
|
||||
while (le != &pdode->children) {
|
||||
drive_letter_removal* dlr;
|
||||
|
||||
volume_child* vc = CONTAINING_RECORD(le, volume_child, list_entry);
|
||||
|
||||
dlr = ExAllocatePoolWithTag(PagedPool, sizeof(drive_letter_removal), ALLOC_TAG);
|
||||
if (!dlr) {
|
||||
ERR("out of memory\n");
|
||||
|
||||
while (!IsListEmpty(&dlrlist)) {
|
||||
dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist), drive_letter_removal, list_entry);
|
||||
|
||||
ExFreePool(dlr->name.Buffer);
|
||||
ExFreePool(dlr);
|
||||
}
|
||||
|
||||
ExReleaseResourceLite(&pdode->child_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
dlr->name.Length = dlr->name.MaximumLength = vc->pnp_name.Length + (3 * sizeof(WCHAR));
|
||||
dlr->name.Buffer = ExAllocatePoolWithTag(PagedPool, dlr->name.Length, ALLOC_TAG);
|
||||
|
||||
if (!dlr->name.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
|
||||
ExFreePool(dlr);
|
||||
|
||||
while (!IsListEmpty(&dlrlist)) {
|
||||
dlr = CONTAINING_RECORD(RemoveHeadList(&dlrlist), drive_letter_removal, list_entry);
|
||||
|
||||
ExFreePool(dlr->name.Buffer);
|
||||
ExFreePool(dlr);
|
||||
}
|
||||
|
||||
ExReleaseResourceLite(&pdode->child_lock);
|
||||
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(&pdode->child_lock);
|
||||
|
||||
le = dlrlist.Flink;
|
||||
while (le != &dlrlist) {
|
||||
drive_letter_removal* dlr = CONTAINING_RECORD(le, drive_letter_removal, list_entry);
|
||||
|
||||
dlr->Status = remove_drive_letter(mountmgr, &dlr->name);
|
||||
|
||||
if (!NT_SUCCESS(dlr->Status) && dlr->Status != STATUS_NOT_FOUND)
|
||||
WARN("remove_drive_letter returned %08x\n", dlr->Status);
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
// 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(PDEVICE_OBJECT DeviceObject, PVOID con) {
|
||||
drive_letter_callback_context* context = con;
|
||||
static void __stdcall drive_letter_callback(pdo_device_extension* pdode) {
|
||||
NTSTATUS Status;
|
||||
UNICODE_STRING mmdevpath;
|
||||
PDEVICE_OBJECT mountmgr;
|
||||
PFILE_OBJECT mountmgrfo;
|
||||
LIST_ENTRY* le;
|
||||
|
||||
UNUSED(DeviceObject);
|
||||
|
||||
RtlInitUnicodeString(&mmdevpath, MOUNTMGR_DEVICE_NAME);
|
||||
Status = IoGetDeviceObjectPointer(&mmdevpath, FILE_READ_ATTRIBUTES, &mountmgrfo, &mountmgr);
|
||||
|
@ -1020,86 +1141,9 @@ static void __stdcall drive_letter_callback(PDEVICE_OBJECT DeviceObject, PVOID c
|
|||
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);
|
||||
|
||||
if (pdode == context->pdode) {
|
||||
LIST_ENTRY* le2;
|
||||
|
||||
ExAcquireResourceExclusiveLite(&pdode->child_lock, true);
|
||||
|
||||
le2 = pdode->children.Flink;
|
||||
|
||||
while (le2 != &pdode->children) {
|
||||
UNICODE_STRING name;
|
||||
|
||||
volume_child* vc = CONTAINING_RECORD(le2, volume_child, list_entry);
|
||||
|
||||
name.Length = name.MaximumLength = vc->pnp_name.Length + (3 * sizeof(WCHAR));
|
||||
name.Buffer = ExAllocatePoolWithTag(PagedPool, name.Length, ALLOC_TAG);
|
||||
|
||||
if (!name.Buffer) {
|
||||
ERR("out of memory\n");
|
||||
|
||||
ExReleaseResourceLite(&pdode->child_lock);
|
||||
ExReleaseResourceLite(&pdo_list_lock);
|
||||
ObDereferenceObject(mountmgrfo);
|
||||
IoFreeWorkItem(context->work_item);
|
||||
return;
|
||||
}
|
||||
|
||||
RtlCopyMemory(name.Buffer, L"\\??", 3 * sizeof(WCHAR));
|
||||
RtlCopyMemory(&name.Buffer[3], vc->pnp_name.Buffer, vc->pnp_name.Length);
|
||||
|
||||
Status = remove_drive_letter(mountmgr, &name);
|
||||
|
||||
if (!NT_SUCCESS(Status) && Status != STATUS_NOT_FOUND)
|
||||
WARN("remove_drive_letter returned %08x\n", Status);
|
||||
|
||||
ExFreePool(name.Buffer);
|
||||
|
||||
vc->had_drive_letter = NT_SUCCESS(Status);
|
||||
|
||||
le2 = le2->Flink;
|
||||
}
|
||||
|
||||
ExReleaseResourceLite(&pdode->child_lock);
|
||||
ExReleaseResourceLite(&pdo_list_lock);
|
||||
ObDereferenceObject(mountmgrfo);
|
||||
IoFreeWorkItem(context->work_item);
|
||||
return;
|
||||
}
|
||||
|
||||
le = le->Flink;
|
||||
}
|
||||
|
||||
ExReleaseResourceLite(&pdo_list_lock);
|
||||
drive_letter_callback2(pdode, mountmgr);
|
||||
|
||||
ObDereferenceObject(mountmgrfo);
|
||||
IoFreeWorkItem(context->work_item);
|
||||
}
|
||||
|
||||
static void add_drive_letter_work_item(pdo_device_extension* pdode) {
|
||||
PIO_WORKITEM work_item;
|
||||
drive_letter_callback_context* context;
|
||||
|
||||
work_item = IoAllocateWorkItem(master_devobj);
|
||||
|
||||
context = ExAllocatePoolWithTag(PagedPool, sizeof(drive_letter_callback_context), ALLOC_TAG);
|
||||
|
||||
if (!context) {
|
||||
ERR("out of memory\n");
|
||||
IoFreeWorkItem(work_item);
|
||||
return;
|
||||
}
|
||||
|
||||
context->work_item = work_item;
|
||||
context->pdode = pdode;
|
||||
|
||||
IoQueueWorkItem(work_item, drive_letter_callback, DelayedWorkQueue, context);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue