mirror of
https://github.com/reactos/reactos.git
synced 2024-08-05 11:00:55 +00:00
1f377076d7
Not all files are included, but these are necessary to compile cdrom driver. So far it can only be statically linked with drivers, a proper implementation requires wdfldr helper driver
566 lines
15 KiB
C++
566 lines
15 KiB
C++
/*++
|
|
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
FxFileObject.hpp
|
|
|
|
Abstract:
|
|
|
|
This module implements a frameworks managed FileObject
|
|
|
|
Author:
|
|
|
|
|
|
|
|
Environment:
|
|
|
|
Both kernel and user mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "coreprivshared.hpp"
|
|
|
|
// Tracing support
|
|
extern "C" {
|
|
// #include "FxFileObject.tmh"
|
|
}
|
|
|
|
//
|
|
// Public constructors
|
|
//
|
|
|
|
|
|
FxFileObject::FxFileObject(
|
|
__in PFX_DRIVER_GLOBALS FxDriverGlobals,
|
|
__in MdFileObject pWdmFileObject,
|
|
__in FxDevice* pDevice
|
|
) :
|
|
FxNonPagedObject(FX_TYPE_FILEOBJECT, sizeof(FxFileObject), FxDriverGlobals)
|
|
{
|
|
m_FileObject.SetFileObject(pWdmFileObject);
|
|
m_PkgContext = NULL;
|
|
m_Device = pDevice;
|
|
|
|
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
|
RtlInitUnicodeString(&m_FileName, NULL);
|
|
m_RelatedFileObject = NULL;
|
|
#endif
|
|
|
|
//
|
|
// Cannot be deleted by the device driver
|
|
//
|
|
MarkNoDeleteDDI();
|
|
}
|
|
|
|
FxFileObject::~FxFileObject()
|
|
{
|
|
#if (FX_CORE_MODE == FX_CORE_USER_MODE)
|
|
SAFE_RELEASE(m_RelatedFileObject);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Create the WDFFILEOBJECT and associate it with the WDM PFILE_OBJECT.
|
|
//
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxFileObject::_CreateFileObject(
|
|
__in FxDevice* pDevice,
|
|
__in MdIrp Irp,
|
|
__in WDF_FILEOBJECT_CLASS FileObjectClass,
|
|
__in_opt PWDF_OBJECT_ATTRIBUTES pObjectAttributes,
|
|
__in_opt MdFileObject pWdmFileObject,
|
|
__deref_out_opt FxFileObject** pFileObject
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
FxFileObject* pfo;
|
|
KIRQL irql;
|
|
WDF_FILEOBJECT_CLASS normalizedFileClass;
|
|
|
|
PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals();
|
|
|
|
//
|
|
// Create does require a WDM file obj based on the normalized file obj
|
|
// class value.
|
|
//
|
|
normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass);
|
|
|
|
//
|
|
// No FileObject support
|
|
//
|
|
if( normalizedFileClass == WdfFileObjectNotRequired ) {
|
|
if( pFileObject != NULL ) *pFileObject = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// If fileobject support was specified, and a NULL
|
|
// WDM PFILE_OBJECT is supplied, then it's an error
|
|
//
|
|
if( pWdmFileObject == NULL ) {
|
|
|
|
//
|
|
// Seems like some filter driver above us sending a create without fileobject.
|
|
// We support this only if the FileObjectClass class is set to
|
|
// WdfFileObjectWdfCannotUseFsContexts and device is created to be
|
|
// exclusive.
|
|
//
|
|
if ( normalizedFileClass == WdfFileObjectWdfCannotUseFsContexts &&
|
|
pDevice->IsExclusive() ) {
|
|
|
|
DO_NOTHING();
|
|
|
|
} else {
|
|
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
|
|
"WdfFileObjectWdfCanUseFsContexts is specified, but the Create "
|
|
"IRP %p doesn't have a fileObject\n",
|
|
Irp);
|
|
FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
|
|
return STATUS_DEVICE_CONFIGURATION_ERROR;
|
|
}
|
|
|
|
}
|
|
|
|
// Allocate a new FxFileObject with context
|
|
pfo = new(pDevice->GetDriverGlobals(), pObjectAttributes)
|
|
FxFileObject(pDevice->GetDriverGlobals(), pWdmFileObject, pDevice);
|
|
|
|
if( pfo == NULL ) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
pfo->Initialize(Irp);
|
|
|
|
// Assign FxDevice as the parent for the file object
|
|
Status = pfo->Commit(pObjectAttributes, NULL, pDevice);
|
|
if( !NT_SUCCESS(Status) ) {
|
|
pfo->DeleteFromFailedCreate();
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Place it on the list of FxFileObject's for this FxDevice
|
|
//
|
|
pDevice->Lock(&irql);
|
|
InsertHeadList(&pDevice->m_FileObjectListHead, &pfo->m_Link);
|
|
pDevice->Unlock(irql);
|
|
|
|
//
|
|
// Set file object context in mode-specific manner
|
|
//
|
|
pfo->SetFileObjectContext(pWdmFileObject,
|
|
normalizedFileClass,
|
|
Irp,
|
|
pDevice);
|
|
|
|
// FxFileObject* to caller
|
|
if( pFileObject != NULL ) {
|
|
*pFileObject = pfo;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Destroy (dereference) the WDFFILEOBJECT related to the
|
|
// WDM PFILE_OBJECT according to its FileObjectClass.
|
|
//
|
|
VOID
|
|
FxFileObject::_DestroyFileObject(
|
|
__in FxDevice* pDevice,
|
|
__in WDF_FILEOBJECT_CLASS FileObjectClass,
|
|
__in_opt MdFileObject pWdmFileObject
|
|
)
|
|
{
|
|
FxFileObject* pfo = NULL;
|
|
PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals();
|
|
WDF_FILEOBJECT_CLASS normalizedFileClass;
|
|
|
|
//
|
|
// Close does require a WDM file obj based on the normalized file obj
|
|
// class value.
|
|
//
|
|
normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass);
|
|
|
|
if( normalizedFileClass == WdfFileObjectNotRequired ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Driver has specified file object support, and we
|
|
// allocated one at Create, so they must pass one
|
|
// to close, otherwise it's an error and we will leak
|
|
// the file object.
|
|
//
|
|
MxFileObject wdmFileObject(pWdmFileObject);
|
|
if( pWdmFileObject == NULL &&
|
|
normalizedFileClass != WdfFileObjectWdfCannotUseFsContexts) {
|
|
|
|
//
|
|
// It's likely that IRP_MJ_CREATE had NULL for the Wdm FileObject as well.
|
|
//
|
|
// If a driver passes != NULL for Wdm FileObject to create, and NULL to
|
|
// this routine, a WDF FxFileObject object leak will occur, which will
|
|
// be reported at driver unload.
|
|
//
|
|
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO,
|
|
"PFILE_OBJECT in close IRP is NULL, *Possible Leak of FxFileObject*\n");
|
|
|
|
FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
|
|
|
|
return;
|
|
}
|
|
else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext ) {
|
|
pfo = (FxFileObject*)wdmFileObject.GetFsContext();
|
|
wdmFileObject.SetFsContext(NULL);
|
|
|
|
}
|
|
else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext2 ) {
|
|
pfo = (FxFileObject*)wdmFileObject.GetFsContext2();
|
|
wdmFileObject.SetFsContext2(NULL);
|
|
}
|
|
else {
|
|
NTSTATUS status;
|
|
//
|
|
// We must find the associated FxFileObject from the list
|
|
// on the device
|
|
//
|
|
status = FxFileObject::_GetFileObjectFromWdm(
|
|
pDevice,
|
|
WdfFileObjectWdfCannotUseFsContexts,
|
|
pWdmFileObject,
|
|
&pfo
|
|
);
|
|
|
|
//
|
|
// We should find it, unless a different one was passed to IRP_MJ_CLOSE
|
|
// than to IRP_MJ_CREATE, which is an error.
|
|
//
|
|
if (NT_SUCCESS(status) == FALSE || pfo == NULL) {
|
|
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
|
"Could not find WDFFILEOBJECT for PFILE_OBJECT 0x%p",
|
|
pWdmFileObject);
|
|
|
|
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
|
"Did a different PFILE_OBJECT get passed to "
|
|
"IRP_MJ_CLOSE than did to IRP_MJ_CREATE?");
|
|
FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
|
|
}
|
|
}
|
|
|
|
if( pfo != NULL ) {
|
|
KIRQL irql;
|
|
|
|
//
|
|
// Remove it from the list of FxFileObjects on the FxDevice
|
|
//
|
|
pDevice->Lock(&irql);
|
|
RemoveEntryList(&pfo->m_Link);
|
|
pDevice->Unlock(irql);
|
|
|
|
// Delete the file object
|
|
pfo->DeleteObject();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Return the FxFileObject* for the given WDM PFILE_OBJECT
|
|
//
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxFileObject::_GetFileObjectFromWdm(
|
|
__in FxDevice* pDevice,
|
|
__in WDF_FILEOBJECT_CLASS FileObjectClass,
|
|
__in_opt MdFileObject pWdmFileObject,
|
|
__deref_out_opt FxFileObject** ppFxFileObject
|
|
)
|
|
{
|
|
FxFileObject* pfo = NULL;
|
|
PFX_DRIVER_GLOBALS FxDriverGlobals = pDevice->GetDriverGlobals();
|
|
WDF_FILEOBJECT_CLASS normalizedFileClass;
|
|
|
|
//
|
|
// Normalize file object class value.
|
|
//
|
|
normalizedFileClass = FxFileObjectClassNormalize(FileObjectClass);
|
|
|
|
//
|
|
// No FileObject support
|
|
//
|
|
if( normalizedFileClass == WdfFileObjectNotRequired ) {
|
|
*ppFxFileObject = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if( pWdmFileObject == NULL ) {
|
|
|
|
//
|
|
// Warn if an I/O request has NULL for the WDM PFILE_OBJECT
|
|
//
|
|
if ( pDevice->IsExclusive() &&
|
|
normalizedFileClass == WdfFileObjectWdfCannotUseFsContexts ) {
|
|
//
|
|
// We allow a NULL file object iff the device is exclusive and
|
|
// we have to look up the WDFFILEOBJECT by PFILE_OBJECT value
|
|
//
|
|
DO_NOTHING();
|
|
}
|
|
else if ( FxIsFileObjectOptional(FileObjectClass) ) {
|
|
//
|
|
// Driver told us that it's able to handle this case.
|
|
//
|
|
*ppFxFileObject = NULL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else {
|
|
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
|
"NULL passed for PFILE_OBJECT when FileObject "
|
|
"support is requested in an I/O request");
|
|
FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Depending on the drivers configuration, we can quickly
|
|
// get the FxFileObject* from FxContext, or FxContext2.
|
|
//
|
|
// Some drivers can not touch either of the FxContext(s), and
|
|
// in that case we must resort to a list or hashtable.
|
|
//
|
|
MxFileObject wdmFileObject(pWdmFileObject);
|
|
if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext ) {
|
|
pfo = (FxFileObject*)wdmFileObject.GetFsContext();
|
|
}
|
|
else if( normalizedFileClass == WdfFileObjectWdfCanUseFsContext2 ) {
|
|
pfo = (FxFileObject*)wdmFileObject.GetFsContext2();
|
|
}
|
|
else {
|
|
PLIST_ENTRY next;
|
|
FxFileObject* f;
|
|
KIRQL irql;
|
|
|
|
//
|
|
// Must look it up from the FxDevice->m_FileObjectListHead.
|
|
//
|
|
pfo = NULL;
|
|
|
|
pDevice->Lock(&irql);
|
|
|
|
next = pDevice->m_FileObjectListHead.Flink;
|
|
|
|
if(pWdmFileObject == NULL) {
|
|
//
|
|
// If the pWdmFileObject is NULL then we will pass the first entry
|
|
// in the list because the device must be exclusive and there
|
|
// can be only one fileobject in the list.
|
|
//
|
|
ASSERT(IsListEmpty(&pDevice->m_FileObjectListHead) == FALSE);
|
|
|
|
f = CONTAINING_RECORD(next, FxFileObject, m_Link);
|
|
pfo = f;
|
|
|
|
} else {
|
|
|
|
while( next != &pDevice->m_FileObjectListHead ) {
|
|
f = CONTAINING_RECORD(next, FxFileObject, m_Link);
|
|
|
|
if( f->m_FileObject.GetFileObject()== pWdmFileObject ) {
|
|
pfo = f;
|
|
break;
|
|
}
|
|
|
|
next = next->Flink;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(pfo == NULL
|
|
&& pDevice->IsExclusive()
|
|
&& pDevice->GetMxDeviceObject()->GetDeviceType() == FILE_DEVICE_SERIAL_PORT
|
|
&& !IsListEmpty(&pDevice->m_FileObjectListHead)) {
|
|
|
|
f = CONTAINING_RECORD(pDevice->m_FileObjectListHead.Flink,
|
|
FxFileObject, m_Link);
|
|
pfo = f;
|
|
|
|
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE,
|
|
"The PFILE_OBJECT 0x%p in this request (cleanup/close) "
|
|
"is different from the one specified in "
|
|
"create request 0x%p.This is bad!", pWdmFileObject,
|
|
((f != NULL) ? f->m_FileObject.GetFileObject(): NULL));
|
|
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE,
|
|
"Since this is a serial port device, framework is "
|
|
"using a workaround to allow this");
|
|
}
|
|
|
|
pDevice->Unlock(irql);
|
|
}
|
|
|
|
//
|
|
// This can happen if a different PFILE_OBJECT is passed to an I/O
|
|
// request than was presented to IRP_MJ_CREATE
|
|
//
|
|
if (pfo == NULL && FxIsFileObjectOptional(FileObjectClass) == FALSE) {
|
|
|
|
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
|
"Could not locate WDFFILEOBJECT for "
|
|
"PFILE_OBJECT 0x%p",pWdmFileObject);
|
|
|
|
DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE,
|
|
"Did a different PFILE_OBJECT get passed to the "
|
|
"request than was to IRP_MJ_CREATE?");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) {
|
|
FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals());
|
|
}
|
|
}
|
|
|
|
//
|
|
// We don't do an extra reference count since the file objects
|
|
// lifetime is controlled by the IoMgr. When the IRP_MJ_CLOSE
|
|
// occurs, the reference is released after the optional
|
|
// driver event callback.
|
|
//
|
|
|
|
*ppFxFileObject = pfo;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
FxFileObject::DeleteFileObjectFromFailedCreate(
|
|
VOID
|
|
)
|
|
{
|
|
KIRQL irql;
|
|
|
|
//
|
|
// Remove it from the list of FxFileObjects on the FxDevice
|
|
//
|
|
m_Device->Lock(&irql);
|
|
RemoveEntryList(&m_Link);
|
|
m_Device->Unlock(irql);
|
|
|
|
// Delete the file object
|
|
DeleteFromFailedCreate();
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
NTSTATUS
|
|
FxFileObject::QueryInterface(
|
|
__in FxQueryInterfaceParams* Params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine is used to return the pointer to the Object itself.
|
|
|
|
Arguments:
|
|
Params - query interface parameters.
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (Params->Type) {
|
|
case FX_TYPE_FILEOBJECT:
|
|
*Params->Object = (FxFileObject*) this;
|
|
break;
|
|
|
|
case FX_TYPE_IHASCALLBACKS:
|
|
*Params->Object = (IFxHasCallbacks*) this;
|
|
break;
|
|
|
|
default:
|
|
return FxNonPagedObject::QueryInterface(Params); // __super call
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
FxFileObject::GetConstraints(
|
|
__in WDF_EXECUTION_LEVEL* ExecutionLevel,
|
|
__in WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine implements the GetConstraints IfxCallback. The caller gets the
|
|
ExecutionLevel and the SynchronizationScope of the FileObject. The FileObject's
|
|
SynchronizationScope and ExecutionLevel is strored in the FxPkgGeneral object.
|
|
|
|
Arguments:
|
|
ExecutionLevel - (opt) receives the execution level.
|
|
|
|
SynchronizationScope - (opt) receives the synchronization scope.
|
|
|
|
Return Value:
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Get it from FxPkgGeneral which has the File attributes passed to it at device Creation time.
|
|
//
|
|
return GetDevice()->m_PkgGeneral->GetConstraintsHelper(ExecutionLevel, SynchronizationScope);
|
|
}
|
|
|
|
_Must_inspect_result_
|
|
FxCallbackLock*
|
|
FxFileObject::GetCallbackLockPtr(
|
|
__deref_out_opt FxObject** LockObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine implements the GetCallbackLockPtr IfxCallback. The caller gets the
|
|
LockObject to be used before calling the driver callbacks.
|
|
|
|
Arguments:
|
|
LockObject - receives the lock object.
|
|
|
|
Return Value:
|
|
FxCallbackLock *
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Get it from FxPkgGeneral which has the File attributes passed to it at device Creation time.
|
|
//
|
|
return GetDevice()->m_PkgGeneral->GetCallbackLockPtrHelper(LockObject);
|
|
}
|
|
|
|
|