[NTOSKRNL] Implement support for FileFsDriverPathInformation in NtQueryVolumeInformat...
authorPierre Schweitzer <pierre@reactos.org>
Fri, 29 Mar 2019 20:42:42 +0000 (21:42 +0100)
committerPierre Schweitzer <pierre@reactos.org>
Fri, 29 Mar 2019 20:42:42 +0000 (21:42 +0100)
ntoskrnl/io/iomgr/iofunc.c

index e6ecefc..5831b55 100644 (file)
@@ -1052,6 +1052,88 @@ IopGetMountFlag(IN PDEVICE_OBJECT DeviceObject)
     return Mounted;
 }
 
+static
+BOOLEAN
+IopVerifyDriverObjectOnStack(IN PDEVICE_OBJECT DeviceObject,
+                             IN PDRIVER_OBJECT DriverObject)
+{
+    PDEVICE_OBJECT StackDO;
+
+    /* Browse our whole device stack, trying to find the appropriate driver */
+    StackDO = IopGetDeviceAttachmentBase(DeviceObject);
+    while (StackDO != NULL)
+    {
+        /* We've found the driver, return success */
+        if (StackDO->DriverObject == DriverObject)
+        {
+            return TRUE;
+        }
+
+        /* Move to the next */
+        StackDO = StackDO->AttachedDevice;
+    }
+
+    /* We only reach there if driver was not found */
+    return FALSE;
+}
+
+static
+NTSTATUS
+IopGetDriverPathInformation(IN PFILE_OBJECT FileObject,
+                            IN PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo,
+                            IN ULONG Length)
+{
+    KIRQL OldIrql;
+    NTSTATUS Status;
+    UNICODE_STRING DriverName;
+    PDRIVER_OBJECT DriverObject;
+
+    /* Make sure the structure is consistent (ie, driver name fits into the buffer) */
+    if (Length - FIELD_OFFSET(FILE_FS_DRIVER_PATH_INFORMATION, DriverName) < DriverPathInfo->DriverNameLength)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Setup the whole driver name */
+    DriverName.Length = DriverPathInfo->DriverNameLength;
+    DriverName.MaximumLength = DriverPathInfo->DriverNameLength;
+    DriverName.Buffer = &DriverPathInfo->DriverName[0];
+
+    /* Ask Ob for such driver */
+    Status = ObReferenceObjectByName(&DriverName,
+                                     OBJ_CASE_INSENSITIVE,
+                                     NULL,
+                                     0,
+                                     IoDriverObjectType,
+                                     KernelMode,
+                                     NULL,
+                                     (PVOID*)&DriverObject);
+    /* No such driver, bail out */
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Lock the devices database, we'll browse it */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
+    /* If we have a VPB, browse the stack from the volume */
+    if (FileObject->Vpb != NULL && FileObject->Vpb->DeviceObject != NULL)
+    {
+        DriverPathInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->Vpb->DeviceObject, DriverObject);
+    }
+    /* Otherwise, do it from the normal device */
+    else
+    {
+        DriverPathInfo->DriverInPath = IopVerifyDriverObjectOnStack(FileObject->DeviceObject, DriverObject);
+    }
+    KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
+
+    /* No longer needed */
+    ObDereferenceObject(DriverObject);
+
+    return STATUS_SUCCESS;
+}
+
 /* PUBLIC FUNCTIONS **********************************************************/
 
 /*
@@ -4136,6 +4218,55 @@ NtQueryVolumeInformationFile(IN HANDLE FileHandle,
 
         return STATUS_SUCCESS;
     }
+    /* This is to be handled by the kernel, not by FSD */
+    else if (FsInformationClass == FileFsDriverPathInformation)
+    {
+        PFILE_FS_DRIVER_PATH_INFORMATION DriverPathInfo;
+
+        _SEH2_TRY
+        {
+            /* Allocate our local structure */
+            DriverPathInfo = ExAllocatePoolWithQuotaTag(NonPagedPool, Length, TAG_IO);
+
+            /* And copy back caller data */
+            RtlCopyMemory(DriverPathInfo, FsInformation, Length);
+
+            /* Is the driver in the IO path? */
+            Status = IopGetDriverPathInformation(FileObject, DriverPathInfo, Length);
+            /* We failed, don't continue execution */
+            if (!NT_SUCCESS(Status))
+            {
+                RtlRaiseStatus(Status);
+            }
+
+            /* We succeed, copy back info */
+            ((PFILE_FS_DRIVER_PATH_INFORMATION)FsInformation)->DriverInPath = DriverPathInfo->DriverInPath;
+
+            /* We're done */
+            IoStatusBlock->Information = sizeof(FILE_FS_DRIVER_PATH_INFORMATION);
+            IoStatusBlock->Status = STATUS_SUCCESS;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Status = _SEH2_GetExceptionCode();
+        }
+        _SEH2_END;
+
+        /* Don't leak */
+        if (DriverPathInfo != NULL)
+        {
+            ExFreePoolWithTag(DriverPathInfo, TAG_IO);
+        }
+
+        /*
+         * We didn't have an exception, but we didn't issue an IRP
+         * to complete either, so avoid duplicating code and
+         * call appropriate helper
+         */
+        IopCleanupAfterException(FileObject, NULL, NULL, Event);
+
+        return Status;
+    }
 
     /* Get the device object */
     DeviceObject = IoGetRelatedDeviceObject(FileObject);