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);
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;
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;
}
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;
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;
ExReleaseResourceLite(&Vcb->tree_lock);
}
-static NTSTATUS dismount_volume(device_extension* Vcb, PIRP Irp) {
+NTSTATUS dismount_volume(device_extension* Vcb, bool shutdown, PIRP Irp) {
NTSTATUS Status;
+ bool open_files;
TRACE("FSCTL_DISMOUNT_VOLUME\n");
if (!(Vcb->Vpb->Flags & VPB_MOUNTED))
return STATUS_SUCCESS;
- if (Vcb->disallow_dismount || Vcb->page_file_count != 0) {
- WARN("attempting to dismount boot volume or one containing a pagefile\n");
- return STATUS_ACCESS_DENIED;
- }
+ if (!shutdown) {
+ if (Vcb->disallow_dismount || Vcb->page_file_count != 0) {
+ WARN("attempting to dismount boot volume or one containing a pagefile\n");
+ return STATUS_ACCESS_DENIED;
+ }
- Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT);
- if (!NT_SUCCESS(Status)) {
- WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status);
+ Status = FsRtlNotifyVolumeEvent(Vcb->root_file, FSRTL_VOLUME_DISMOUNT);
+ if (!NT_SUCCESS(Status)) {
+ WARN("FsRtlNotifyVolumeEvent returned %08x\n", Status);
+ }
}
ExAcquireResourceExclusiveLite(&Vcb->tree_lock, true);
Vcb->removing = true;
+ open_files = Vcb->open_files > 0;
+
if (Vcb->vde) {
update_volumes(Vcb);
Vcb->vde->mounted_device = NULL;
ExReleaseResourceLite(&Vcb->tree_lock);
+ if (!open_files)
+ uninit(Vcb);
+
return STATUS_SUCCESS;
}
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;
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;
delta = dev->devitem.num_bytes - br->size;
if (need_balance) {
+ OBJECT_ATTRIBUTES oa;
int i;
if (Vcb->balance.thread) {
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;
return Status;
}
-NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t type) {
+static NTSTATUS fsctl_oplock(device_extension* Vcb, PIRP* Pirp) {
+ NTSTATUS Status;
PIRP Irp = *Pirp;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
- NTSTATUS Status;
+ uint32_t fsctl = IrpSp->Parameters.FileSystemControl.FsControlCode;
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ fcb* fcb = FileObject ? FileObject->FsContext : NULL;
+ ccb* ccb = FileObject ? FileObject->FsContext2 : NULL;
+ file_ref* fileref = ccb ? ccb->fileref : NULL;
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+ PREQUEST_OPLOCK_INPUT_BUFFER buf = NULL;
+ bool oplock_request = false, oplock_ack = false;
+#else
+ bool oplock_request = false;
+#endif
+ ULONG oplock_count = 0;
+#ifdef __REACTOS__
+ bool shared_request;
+#endif
+
+ if (!fcb) {
+ ERR("fcb was NULL\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!fileref) {
+ ERR("fileref was NULL\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (fcb->type != BTRFS_TYPE_FILE && fcb->type != BTRFS_TYPE_DIRECTORY)
+ return STATUS_INVALID_PARAMETER;
- switch (type) {
#if (NTDDI_VERSION >= NTDDI_WIN7)
- case FSCTL_REQUEST_OPLOCK:
- WARN("STUB: FSCTL_REQUEST_OPLOCK\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ if (fsctl == FSCTL_REQUEST_OPLOCK) {
+ if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof(REQUEST_OPLOCK_INPUT_BUFFER))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(REQUEST_OPLOCK_OUTPUT_BUFFER))
+ return STATUS_BUFFER_TOO_SMALL;
+
+ buf = Irp->AssociatedIrp.SystemBuffer;
+
+ // flags are mutually exclusive
+ if (buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_REQUEST && buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_ACK)
+ return STATUS_INVALID_PARAMETER;
+
+ oplock_request = buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_REQUEST;
+ oplock_ack = buf->Flags & REQUEST_OPLOCK_INPUT_FLAG_ACK;
+
+ if (!oplock_request && !oplock_ack)
+ return STATUS_INVALID_PARAMETER;
+ }
#endif
- case FSCTL_REQUEST_OPLOCK_LEVEL_1:
- WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_1\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+ bool shared_request = (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2) || (fsctl == FSCTL_REQUEST_OPLOCK && !(buf->RequestedOplockLevel & OPLOCK_LEVEL_CACHE_WRITE));
+#else
+ shared_request = (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2);
+#endif
- case FSCTL_REQUEST_OPLOCK_LEVEL_2:
- WARN("STUB: FSCTL_REQUEST_OPLOCK_LEVEL_2\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+ if (fcb->type == BTRFS_TYPE_DIRECTORY && (fsctl != FSCTL_REQUEST_OPLOCK || !shared_request)) {
+#else
+ if (fcb->type == BTRFS_TYPE_DIRECTORY && !shared_request) {
+#endif
+ WARN("oplock requests on directories can only be for read or read-handle oplocks\n");
+ return STATUS_INVALID_PARAMETER;
+ }
- case FSCTL_REQUEST_BATCH_OPLOCK:
- WARN("STUB: FSCTL_REQUEST_BATCH_OPLOCK\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
- case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
- WARN("STUB: FSCTL_OPLOCK_BREAK_ACKNOWLEDGE\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ if (fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_1 || fsctl == FSCTL_REQUEST_BATCH_OPLOCK || fsctl == FSCTL_REQUEST_FILTER_OPLOCK ||
+ fsctl == FSCTL_REQUEST_OPLOCK_LEVEL_2 || oplock_request) {
+ ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
- case FSCTL_OPLOCK_BREAK_ACK_NO_2:
- WARN("STUB: FSCTL_OPLOCK_BREAK_ACK_NO_2\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ if (shared_request) {
+ if (fcb->type == BTRFS_TYPE_FILE) {
+ if (fFsRtlCheckLockForOplockRequest)
+ oplock_count = !fFsRtlCheckLockForOplockRequest(&fcb->lock, &fcb->Header.AllocationSize);
+ else if (fFsRtlAreThereCurrentOrInProgressFileLocks)
+ oplock_count = fFsRtlAreThereCurrentOrInProgressFileLocks(&fcb->lock);
+ else
+ oplock_count = FsRtlAreThereCurrentFileLocks(&fcb->lock);
+ }
+ } else
+ oplock_count = fileref->open_count;
+ } else
+ ExAcquireResourceSharedLite(fcb->Header.Resource, true);
- case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
- WARN("STUB: FSCTL_OPBATCH_ACK_CLOSE_PENDING\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+ if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK ||
+ (fsctl == FSCTL_REQUEST_OPLOCK && buf->RequestedOplockLevel & OPLOCK_LEVEL_CACHE_HANDLE)) &&
+#else
+ if ((fsctl == FSCTL_REQUEST_FILTER_OPLOCK || fsctl == FSCTL_REQUEST_BATCH_OPLOCK) &&
+#endif
+ fileref->delete_on_close) {
+ ExReleaseResourceLite(fcb->Header.Resource);
+ ExReleaseResourceLite(&Vcb->tree_lock);
+ return STATUS_DELETE_PENDING;
+ }
- case FSCTL_OPLOCK_BREAK_NOTIFY:
- WARN("STUB: FSCTL_OPLOCK_BREAK_NOTIFY\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ Status = FsRtlOplockFsctrl(fcb_oplock(fcb), Irp, oplock_count);
+
+ *Pirp = NULL;
+
+ fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
+ ExReleaseResourceLite(fcb->Header.Resource);
+ ExReleaseResourceLite(&Vcb->tree_lock);
+
+ return Status;
+}
+
+NTSTATUS fsctl_request(PDEVICE_OBJECT DeviceObject, PIRP* Pirp, uint32_t type) {
+ PIRP Irp = *Pirp;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ NTSTATUS Status;
+
+ if (IrpSp->FileObject && IrpSp->FileObject->FsContext) {
+ device_extension* Vcb = DeviceObject->DeviceExtension;
+
+ if (Vcb->type == VCB_TYPE_FS)
+ FsRtlCheckOplock(fcb_oplock(IrpSp->FileObject->FsContext), Irp, NULL, NULL, NULL);
+ }
+
+ switch (type) {
+ case FSCTL_REQUEST_OPLOCK_LEVEL_1:
+ case FSCTL_REQUEST_OPLOCK_LEVEL_2:
+ case FSCTL_REQUEST_BATCH_OPLOCK:
+ case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
+ case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
+ case FSCTL_OPLOCK_BREAK_NOTIFY:
+ case FSCTL_OPLOCK_BREAK_ACK_NO_2:
case FSCTL_REQUEST_FILTER_OPLOCK:
- WARN("STUB: FSCTL_REQUEST_FILTER_OPLOCK\n");
- Status = STATUS_INVALID_DEVICE_REQUEST;
+#if (NTDDI_VERSION >= NTDDI_WIN7)
+ case FSCTL_REQUEST_OPLOCK:
+#endif
+ Status = fsctl_oplock(DeviceObject->DeviceExtension, Pirp);
break;
case FSCTL_LOCK_VOLUME:
break;
case FSCTL_DISMOUNT_VOLUME:
- Status = dismount_volume(DeviceObject->DeviceExtension, Irp);
+ Status = dismount_volume(DeviceObject->DeviceExtension, false, Irp);
break;
case FSCTL_IS_VOLUME_MOUNTED: