[BTRFS] Upgrade to 1.5

CORE-16494
This commit is contained in:
Pierre Schweitzer 2019-11-12 19:32:46 +01:00
parent c214c04964
commit 62e630de4c
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
27 changed files with 2216 additions and 566 deletions

View file

@ -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;

View file

@ -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;
}
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);
}
}

View file

@ -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(&degraded_wait_handle, 0, NULL, NULL, NULL, degraded_wait_thread, NULL);
InitializeObjectAttributes(&system_thread_attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
Status = PsCreateSystemThread(&degraded_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, &notification_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);

View file

@ -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

View file

@ -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"

View file

@ -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,15 +1790,15 @@ 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,
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,
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,
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
@ -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,
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

View file

@ -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;

View file

@ -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;
}

View file

@ -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)) {
if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID)) {
if (ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT))
acec = ctx;
break;
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) {
@ -4221,11 +4308,23 @@ NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock)
hl_alloc = true;
}
} else {
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);
if (!NT_SUCCESS(Status)) {
@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;
bool ret;
fcb->inode_item.st_size = fcb->Header.FileSize.QuadPart;
FsRtlEnterFileSystem();
return true;
if (!ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, Wait)) {
FsRtlExitFileSystem();
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

View file

@ -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);
}

View file

@ -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,14 +2570,16 @@ 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 (!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;
@ -2585,6 +2589,7 @@ static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) {
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:

View file

@ -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;

View file

@ -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,6 +296,9 @@ static NTSTATUS bus_query_device_relations(PIRP Irp) {
le = pdo_list.Flink;
while (le != &pdo_list) {
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);
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;

View file

@ -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

View file

@ -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));

View file

@ -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))

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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,34 +47,10 @@ NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
return STATUS_SUCCESS;
}
NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
volume_device_extension* vde = DeviceObject->DeviceExtension;
pdo_device_extension* pdode = vde->pdode;
TRACE("(%p, %p)\n", DeviceObject, Irp);
Irp->IoStatus.Information = 0;
ExAcquireResourceExclusiveLite(&pdo_list_lock, true);
ExAcquireResourceSharedLite(&pdode->child_lock, true);
if (InterlockedDecrement(&vde->open_count) == 0 && vde->removing) {
NTSTATUS Status;
UNICODE_STRING mmdevpath;
PDEVICE_OBJECT mountmgr;
PFILE_OBJECT mountmgrfo;
void free_vol(volume_device_extension* vde) {
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);
}
vde->dead = true;
if (vde->mounted_device) {
device_extension* Vcb = vde->mounted_device->DeviceExtension;
@ -84,17 +61,61 @@ NTSTATUS vol_close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
if (vde->name.Buffer)
ExFreePool(vde->name.Buffer);
ExReleaseResourceLite(&pdode->child_lock);
ExDeleteResourceLite(&pdode->child_lock);
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;
TRACE("(%p, %p)\n", DeviceObject, 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) {
ExReleaseResourceLite(&pdode->child_lock);
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);

View file

@ -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,7 +4231,6 @@ 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;
@ -4245,7 +4244,6 @@ NTSTATUS write_file2(device_extension* Vcb, PIRP Irp, LARGE_INTEGER offset, void
} 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,7 +4351,7 @@ 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,
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);
}
@ -4609,7 +4606,7 @@ 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,
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:
@ -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)

View file

@ -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