|
|
/*++
� 1998 Seagate Software, Inc. All rights reserved
Module Name:
fsaftrcl.cpp
Abstract:
This class represents a filter initiated recall request that is still in-progress.
Author:
Chuck Bardeen [cbardeen] 12-Feb-1997
Revision History:
--*/
#include "stdafx.h"
#include "devioctl.h"
#define WSB_TRACE_IS WSB_TRACE_BIT_FSA
#include "wsb.h"
#include "fsa.h"
#include "job.h"
#include "fsaftrcl.h"
#include "rpdata.h"
#include "rpio.h"
static USHORT iCountFtrcl = 0; // Count of existing objects
HRESULT CFsaFilterRecall::Cancel( void )
/*++
Implements:
IFsaFilterRecallPriv::Cancel().
--*/ { CComPtr<IFsaFilterClient> pClient; CComPtr<IWsbEnum> pEnum; HRESULT hr = S_OK, hr2; DWORD dwStatus;
WsbTraceIn(OLESTR("CFsaFilterRecall::Cancel"), OLESTR("filter Id = %I64x"), m_driversRecallId); try {
WsbAffirm(!m_wasCancelled, E_UNEXPECTED);
try { //
// Tell the filter to fail the open of the file.
//
if (m_kernelCompletionSent == FALSE) { WsbAffirmHr(m_pFilterPriv->SendCancel((IFsaFilterRecallPriv *) this)); m_kernelCompletionSent = TRUE; m_wasCancelled = TRUE; } if (m_pClient != 0) { // Reporting on recall end must be synchronized with the recall start notification,
// because such notification might be sent after the recall starts
switch (WaitForSingleObject(m_notifyEvent, INFINITE)) { case WAIT_OBJECT_0: m_pClient->SendRecallInfo((IFsaFilterRecall *) this, FALSE, HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED)); SetEvent(m_notifyEvent); break;
case WAIT_FAILED: default: WsbTrace(OLESTR("CFsaFilterRecall::Cancel: WaitForSingleObject returned error %lu\n"), GetLastError());
// Notify anyway
m_pClient->SendRecallInfo((IFsaFilterRecall *) this, FALSE, HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED)); break; } }
dwStatus = WaitForSingleObject(m_waitingClientEvent, INFINITE);
// Notify on recall end no matter what the status is
if (m_pWaitingClients != 0) { //
// Send recall notifications to all clients waiting for
// the recall to finish
//
hr2 = m_pWaitingClients->Enum(&pEnum); if (S_OK == hr2) { hr2 = pEnum->First(IID_IFsaFilterClient, (void**) &pClient); while (S_OK == hr2) { pClient->SendRecallInfo((IFsaFilterRecall *) this, FALSE, HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED)); m_pWaitingClients->RemoveAndRelease(pClient); pClient = NULL; pEnum->Reset(); hr2 = pEnum->First(IID_IFsaFilterClient, (void**) &pClient); } } }
m_waitingClientsNotified = TRUE;
switch (dwStatus) { case WAIT_OBJECT_0: SetEvent(m_waitingClientEvent); break;
case WAIT_FAILED: default: WsbTrace(OLESTR("CFsaFilterRecall::Cancel: WaitForSingleObject returned error %lu\n"), dwStatus); break; } //
// Now get the engine to cancel it, if possible..
//
if (m_pSession != 0) { WsbAffirmHr(m_pSession->Cancel(HSM_JOB_PHASE_ALL)); }
} WsbCatch(hr);
} WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::Cancel"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::CancelByDriver( void )
/*++
Implements:
IFsaFilterRecallPriv::CancelByDriver().
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CFsaFilterRecall::CancelByDriver"), OLESTR("filter Id = %I64x"), m_driversRecallId); try {
WsbAffirm(!m_wasCancelled, E_UNEXPECTED);
try { //
// No need to tell the filter anymore - reset the flag.
//
m_kernelCompletionSent = TRUE; //
// Now get the engine to cancel it, if possible..
//
if (m_pSession != 0) { WsbAffirmHr(m_pSession->Cancel(HSM_JOB_PHASE_ALL)); }
} WsbCatch(hr);
} WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::CancelByDriver"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::CompareBy( IN FSA_RECALL_COMPARE by )
/*++
Implements:
IWsbCollectable::CompareBy().
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CFsaFilterRecall::CompareBy"), OLESTR("by = %ld"), static_cast<LONG>(by)); try { m_compareBy = by; } WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::CompareBy"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::CompareTo( IN IUnknown* pUnknown, OUT SHORT* pResult )
/*++
Implements:
IWsbCollectable::CompareTo().
--*/ { HRESULT hr = S_OK; CComPtr<IFsaFilterRecall> pRecall; CComPtr<IFsaFilterRecallPriv> pRecallPriv; ULONGLONG id;
// WsbTraceIn(OLESTR("CFsaFilterRecall::CompareTo"), OLESTR(""));
try {
// Did they give us a valid item to compare to?
WsbAssert(0 != pUnknown, E_POINTER);
if (m_compareBy == FSA_RECALL_COMPARE_IRECALL) { // We need the IFsaFilterRecall interface to get the value of the object.
WsbAffirmHr(pUnknown->QueryInterface(IID_IFsaFilterRecall, (void**) &pRecall)); // Compare the rules.
hr = CompareToIRecall(pRecall, pResult); } else { // We need the IFsaFilterRecallPriv interface to get the value of the object.
WsbAffirmHr(pUnknown->QueryInterface(IID_IFsaFilterRecallPriv, (void**) &pRecallPriv)); WsbAffirmHr(pRecallPriv->GetDriversRecallId(&id)); // Compare the driver id
if (m_compareBy == FSA_RECALL_COMPARE_CONTEXT_ID) { hr = CompareToDriversContextId((id&0xFFFFFFFF), pResult); } else { hr = CompareToDriversRecallId(id, pResult); } } } WsbCatch(hr);
// WsbTraceOut(OLESTR("CFsaFilterRecall::CompareTo"), OLESTR("hr = <%ls>, result = <%ls>"), WsbHrAsString(hr), WsbPtrToShortAsString(pResult));
return(hr); }
HRESULT CFsaFilterRecall::CompareToDriversRecallId( IN ULONGLONG id, OUT SHORT* pResult )
/*++
Implements:
IFsaFilterRecall::CompareToDriversRecallId().
--*/ { HRESULT hr = S_OK; SHORT aResult;
// WsbTraceIn(OLESTR("CFsaFilterRecall::CompareToDriversRecallId"), OLESTR(""));
try { if (m_driversRecallId == id) aResult = 0; else aResult = 1;
if (0 != aResult) { hr = S_FALSE; } if (0 != pResult) { *pResult = aResult; }
} WsbCatch(hr);
// WsbTraceOut(OLESTR("CFsaFilterRecall::CompareToDriversRecallId"), OLESTR("hr = <%ls>, result = <%d>"), WsbHrAsString(hr), aResult);
return(hr); }
HRESULT CFsaFilterRecall::CompareToDriversContextId( IN ULONGLONG id, OUT SHORT* pResult )
/*++
Implements:
IFsaFilterRecall::CompareToDriversContextId().
--*/ { HRESULT hr = S_OK; SHORT aResult;
// WsbTraceIn(OLESTR("CFsaFilterRecall::CompareToDriversContextId"), OLESTR(""));
try { if ((m_driversRecallId & 0xFFFFFFFF) == id) aResult = 0; else aResult = 1;
if (0 != aResult) { hr = S_FALSE; } if (0 != pResult) { *pResult = aResult; }
} WsbCatch(hr);
// WsbTraceOut(OLESTR("CFsaFilterRecall::CompareToDriversContextId"), OLESTR("hr = <%ls>, result = <%d>"), WsbHrAsString(hr), aResult);
return(hr); }
HRESULT CFsaFilterRecall::CompareToIdentifier( IN GUID id, OUT SHORT* pResult )
/*++
Implements:
IFsaFilterRecall::CompareToIdentifier().
--*/ { HRESULT hr = S_OK; SHORT aResult;
// WsbTraceIn(OLESTR("CFsaFilterRecall::CompareToIdentifier"), OLESTR(""));
try {
aResult = WsbSign( memcmp(&m_id, &id, sizeof(GUID)) );
if (0 != aResult) { hr = S_FALSE; } if (0 != pResult) { *pResult = aResult; }
} WsbCatch(hr);
// WsbTraceOut(OLESTR("CFsaFilterRecall::CompareToIdentifier"), OLESTR("hr = <%ls>, result = <%d>"), WsbHrAsString(hr), aResult);
return(hr); }
HRESULT CFsaFilterRecall::CompareToIRecall( IN IFsaFilterRecall* pRecall, OUT SHORT* pResult )
/*++
Implements:
IFsaFilterRecall::CompareToIRecall().
--*/ { HRESULT hr = S_OK; CWsbStringPtr name; GUID id;
// WsbTraceIn(OLESTR("CFsaFilterRecall::CompareToIRecall"), OLESTR(""));
try {
// Did they give us a valid item to compare to?
WsbAssert(0 != pRecall, E_POINTER);
WsbAffirmHr(pRecall->GetIdentifier(&id)); hr = CompareToIdentifier(id, pResult);
} WsbCatch(hr);
// WsbTraceOut(OLESTR("CFsaFilterRecall::CompareToIRecall"), OLESTR("hr = <%ls>, result = <%ls>"), WsbHrAsString(hr), WsbPtrToShortAsString(pResult));
return(hr); }
HRESULT CFsaFilterRecall::CreateLocalStream( OUT IStream **ppStream )
/*++
Implements:
IFsaFilterRecall::CreateLocalStream().
--*/ { HRESULT hr = S_OK; WCHAR idString[50]; CWsbStringPtr pDrv; OLECHAR volume[64];
WsbTraceIn(OLESTR("CFsaFilterRecall::CreateLocalStream"), OLESTR("filter Id = %I64x"), m_driversRecallId);
try { WsbAssert( 0 != ppStream, E_POINTER);
swprintf(idString, L"%I64u", m_driversRecallId); WsbAffirmHr( CoCreateInstance( CLSID_CFilterIo, 0, CLSCTX_SERVER, IID_IDataMover, (void **)&m_pDataMover ) ); WsbAssertHr( m_pDataMover->CreateLocalStream( idString, MVR_MODE_WRITE | MVR_FLAG_HSM_SEMANTICS | MVR_FLAG_POSIX_SEMANTICS, &m_pStream ) ); //
// Set the device name for the mover which is used to recall the file.
// This is the RsFilter's primary device object's name to which the
// the RP_PARTIAL_DATA msgs etc. will be sent
//
WsbAffirmHr(m_pResource->GetPath(&pDrv,0)); swprintf(volume, L"\\\\.\\%s", pDrv); //
// strip trailing backslash if any
//
if (volume[wcslen(volume)-1] == L'\\') { volume[wcslen(volume)-1] = L'\0'; } WsbAssertHr( m_pDataMover->SetDeviceName(RS_FILTER_SYM_LINK, volume));
*ppStream = m_pStream; m_pStream.p->AddRef();
} WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::CreateLocalStream"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); }
HRESULT CFsaFilterRecall::Delete( void )
/*++
Implements:
IFsaFilterRecallPriv::Delete().
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CFsaFilterRecall::Delete"), OLESTR("filter Id = %I64x"), m_driversRecallId); try { //
// Tell the kernel mode filter to fail the open of the file.
//
if (m_kernelCompletionSent == FALSE) { WsbAffirmHr(m_pFilterPriv->SendCancel((IFsaFilterRecallPriv *) this)); m_kernelCompletionSent = TRUE; m_wasCancelled = TRUE; }
} WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::Delete"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::FinalConstruct( void )
/*++
Implements:
CComObjectRoot::FinalConstruct().
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CFsaFilterRecall::FinalConstruct"), OLESTR("")); try {
WsbAffirmHr(CWsbCollectable::FinalConstruct());
m_notifyEvent = NULL; m_waitingClientEvent = NULL; m_driversRecallId = 0; memset(&m_placeholder, 0, sizeof(FSA_PLACEHOLDER)); m_state = HSM_JOB_STATE_IDLE; m_wasCancelled = FALSE; m_kernelCompletionSent = FALSE; m_pDataMover = 0; m_pStream = 0; m_recallFlags = 0; m_compareBy = FSA_RECALL_COMPARE_IRECALL; numRefs = 0; m_waitingClientsNotified = FALSE; m_pFilterPriv = NULL; m_threadId = 0; WsbAffirmHr(CoCreateGuid(&m_id));
// Initialize notify synchronization event and waiting clients event
WsbAffirmHandle((m_notifyEvent = CreateEvent(NULL, FALSE, TRUE, NULL))); WsbAffirmHandle((m_waitingClientEvent = CreateEvent(NULL, FALSE, TRUE, NULL))); // Create the waiting client collection.
WsbAffirmHr(CoCreateInstance(CLSID_CWsbOrderedCollection, NULL, CLSCTX_SERVER, IID_IWsbCollection, (void**) &m_pWaitingClients)); } WsbCatch(hr);
iCountFtrcl++;
WsbTraceOut(OLESTR("CFsaFilterRecall::FinalConstruct"), OLESTR("hr = %ls, Count is <%d>"), WsbHrAsString(hr), iCountFtrcl);
return(hr); }
void CFsaFilterRecall::FinalRelease( void )
/*++
Implements:
CComObjectRoot::FinalRelease().
--*/ {
WsbTraceIn(OLESTR("CFsaFilterRecall::FinalRelease"), OLESTR("")); CWsbCollectable::FinalRelease();
// Free notify synchronization event and waiting client event
if (m_waitingClientEvent != NULL) { CloseHandle(m_waitingClientEvent); m_waitingClientEvent = NULL; } if (m_notifyEvent != NULL) { CloseHandle(m_notifyEvent); m_notifyEvent = NULL; }
iCountFtrcl--;
WsbTraceOut(OLESTR("CFsaFilterRecall::FinalRelease"), OLESTR("Count is <%d>"), iCountFtrcl);
}
#ifdef FSA_RECALL_LEAK_TEST
ULONG CFsaFilterRecall::InternalAddRef( void )
/*++
Implements:
CComObjectRoot::AddRef().
--*/ {
numRefs++; WsbTrace(OLESTR("CFsaFilterRecall::AddRef (%p) - Count = %u\n"), this, numRefs); return(CComObjectRoot::InternalAddRef()); }
ULONG CFsaFilterRecall::InternalRelease( void )
/*++
Implements:
CComObjectRoot::InternalRelease().
--*/ { WsbTrace(OLESTR("CFsaFilterRecall::Release (%p) - Count = %u\n"), this, numRefs); numRefs--; return(CComObjectRoot::InternalRelease()); }
#endif
HRESULT CFsaFilterRecall::GetClassID( OUT CLSID* pClsid )
/*++
Implements:
IPersist::GetClassID().
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CFsaFilterRecall::GetClassID"), OLESTR(""));
try {
WsbAssert(0 != pClsid, E_POINTER); *pClsid = CLSID_CFsaFilterRecallNTFS;
} WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::GetClassID"), OLESTR("hr = <%ls>, CLSID = <%ls>"), WsbHrAsString(hr), WsbGuidAsString(*pClsid));
return(hr); }
HRESULT CFsaFilterRecall::GetClient( OUT IFsaFilterClient** ppClient )
/*++
Implements:
IFsaFilterRecallPriv::GetClient().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != ppClient, E_POINTER);
*ppClient = m_pClient; if (m_pClient != 0) { m_pClient.p->AddRef(); }
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetRecallFlags( OUT ULONG *pFlags )
/*++
Implements:
IFsaFilterRecall::GetRecallFlags()
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CFsaFilterRecall::GetRecallFlags"), OLESTR("")); try { WsbAssert( 0 != pFlags, E_POINTER); *pFlags = m_recallFlags; } WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::GetRecallFlags"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); }
HRESULT CFsaFilterRecall::GetStream( OUT IStream **ppStream )
/*++
Implements:
IFsaFilterRecall::GetStream()
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CFsaFilterRecall::GetStream"), OLESTR("")); try { WsbAssert( 0 != ppStream, E_POINTER); if ((m_mode & FILE_OPEN_NO_RECALL) && (m_pStream != 0)) { *ppStream = m_pStream; m_pStream.p->AddRef(); } else { *ppStream = 0; hr = WSB_E_NOTFOUND; } } WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::GetStream"), OLESTR("hr = <%ls>"), WsbHrAsString(hr)); return(hr); }
HRESULT CFsaFilterRecall::GetDriversRecallId( OUT ULONGLONG* pId )
/*++
Implements:
IFsaFilterRecallPriv::GetDriversRecallId().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != pId, E_POINTER);
*pId = m_driversRecallId;
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetIdentifier( OUT GUID* pId )
/*++
Implements:
IFsaFilterRecall::GetIdentifier().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != pId, E_POINTER);
*pId = m_id;
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetMode( OUT ULONG* pMode )
/*++
Implements:
IFsaFilterRecall::GetMode().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != pMode, E_POINTER);
*pMode = m_mode;
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetOffset( OUT LONGLONG* pOffset )
/*++
Implements:
IFsaFilterRecall::GetOffset().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != pOffset, E_POINTER);
*pOffset = m_offset;
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetPath( OUT OLECHAR** pName, IN ULONG bufferSize )
/*++
Implements:
IFsaFilterRecall::GetPath().
--*/ { HRESULT hr = S_OK; CWsbStringPtr tmpString;
try {
WsbAssert(0 != pName, E_POINTER);
WsbAffirmHr(tmpString.TakeFrom(*pName, bufferSize));
try { WsbAffirmHr(m_pResource->GetUncPath(&tmpString, 0)); WsbAffirmHr(tmpString.Append(m_path)); } WsbCatch(hr);
WsbAffirmHr(tmpString.GiveTo(pName));
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetPlaceholder( OUT FSA_PLACEHOLDER* pPlaceholder )
/*++
Implements:
IFsaFilterRecallPriv::GetPlaceholder().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != pPlaceholder, E_POINTER); *pPlaceholder = m_placeholder;
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetResource( OUT IFsaResource** ppResource )
/*++
Implements:
IFsaFilterRecall::GetResource().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != ppResource, E_POINTER);
*ppResource = m_pResource; m_pResource.p->AddRef();
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetSession( OUT IHsmSession** ppSession )
/*++
Implements:
IFsaFilterRecall::GetSession().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != ppSession, E_POINTER);
*ppSession = m_pSession; m_pSession.p->AddRef();
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetSize( OUT LONGLONG* pSize )
/*++
Implements:
IFsaFilterRecall::GetSize().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != pSize, E_POINTER);
*pSize = m_size;
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetSizeMax( OUT ULARGE_INTEGER* pSize )
/*++
Implements:
IPersistStream::GetSizeMax().
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CFsaFilterRecall::GetSizeMax"), OLESTR(""));
try {
WsbAssert(0 != pSize, E_POINTER); pSize->QuadPart = 0;
// WE don't need to persist these.
hr = E_NOTIMPL;
} WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::GetSizeMax"), OLESTR("hr = <%ls>, Size = <%ls>"), WsbHrAsString(hr), WsbPtrToUliAsString(pSize));
return(hr); }
HRESULT CFsaFilterRecall::GetState( OUT HSM_JOB_STATE* pState )
/*++
Implements:
IFsaFilterRecall::GetState().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != pState, E_POINTER); *pState = m_state;
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::GetUserName( OUT OLECHAR** pName, IN ULONG bufferSize )
/*++
Implements:
IFsaFilterRecall::GetUserName().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != pName, E_POINTER);
if (m_pClient != 0) { WsbAffirmHr(m_pClient->GetUserName(pName, bufferSize)); } else { hr = WSB_E_NOTFOUND; }
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::HasCompleted( HRESULT resultHr )
/*++
Implements:
IFsaFilterRecall::HasCompleted().
--*/ { HRESULT hr = S_OK, hr2 = S_OK; CComPtr<IFsaFilterClient> pClient; CComPtr<IWsbEnum> pEnum; FILETIME now; BOOL bSendNotify = TRUE; DWORD dwStatus;
WsbTraceIn(OLESTR("CFsaFilterRecall::HasCompleted"), OLESTR("filter Id = %I64x, recall hr = <%ls>"), m_driversRecallId, WsbHrAsString(resultHr));
try {
// The job is complete, let the kernel mode filter know what happened.
GetSystemTimeAsFileTime(&now);
if (m_pClient != 0) { m_pClient->SetLastRecallTime(now); // Not fatal if this fails
}
if (m_kernelCompletionSent == FALSE) { WsbAffirmHr(m_pFilterPriv->SendComplete((IFsaFilterRecallPriv *) this, resultHr)); m_kernelCompletionSent = TRUE; }
if (m_pClient != 0) { // Reporting on recall end must be synchronized with the recall start notification,
// because such notification might be sent after the recall starts
switch (WaitForSingleObject(m_notifyEvent, INFINITE)) { case WAIT_OBJECT_0: // Send recall notifications to the client that initiated the recall
m_pClient->SendRecallInfo((IFsaFilterRecall *) this, FALSE, resultHr); SetEvent(m_notifyEvent); break;
case WAIT_FAILED: default: WsbTrace(OLESTR("CFsaFilterRecall::HasCompleted: WaitForSingleObject returned error %lu\n"), GetLastError());
// Notify anyway
m_pClient->SendRecallInfo((IFsaFilterRecall *) this, FALSE, resultHr); break; }
bSendNotify = FALSE; }
dwStatus = WaitForSingleObject(m_waitingClientEvent, INFINITE);
// Notify on recall end no matter what the status is
if (m_pWaitingClients != 0) { //
// Send recall notifications to all clients waiting for the recall
// to finish
//
hr2 = m_pWaitingClients->Enum(&pEnum); if (S_OK == hr2) { hr2 = pEnum->First(IID_IFsaFilterClient, (void**) &pClient); while (S_OK == hr2) { pClient->SendRecallInfo((IFsaFilterRecall *) this, FALSE, resultHr); m_pWaitingClients->RemoveAndRelease(pClient); pClient = NULL; pEnum->Reset(); hr2 = pEnum->First(IID_IFsaFilterClient, (void**) &pClient); } } }
m_waitingClientsNotified = TRUE;
switch (dwStatus) { case WAIT_OBJECT_0: SetEvent(m_waitingClientEvent); break;
case WAIT_FAILED: default: WsbTrace(OLESTR("CFsaFilterRecall::HasCompleted: WaitForSingleObject returned error %lu\n"), dwStatus); break; }
//
// Detach the data mover stream
//
if (m_pDataMover != 0) { WsbAffirmHr( m_pDataMover->CloseStream() ); }
} WsbCatchAndDo(hr, if ((m_pClient != 0) && bSendNotify) { m_pClient->SendRecallInfo((IFsaFilterRecall *) this, FALSE, resultHr); bSendNotify = FALSE; } );
WsbTraceOut(OLESTR("CFsaFilterRecall::HasCompleted"), OLESTR("filter Id = %I64x, sent = <%ls>, hr = <%ls>"), m_driversRecallId, WsbBoolAsString(m_kernelCompletionSent), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::CheckRecallLimit( IN DWORD minRecallInterval, IN DWORD maxRecalls, IN BOOLEAN exemptAdmin )
/*++
Implements:
IFsaFilterRecall::CheckRecallLimit().
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CFsaFilterRecall::CheckRecallLimit"), OLESTR("filter Id = %I64x"), m_driversRecallId);
try {
// Check the limit if we are not file open no recall
if (!(m_mode & FILE_OPEN_NO_RECALL) && (m_pClient != NULL)) { WsbAffirmHr(m_pClient->CheckRecallLimit(minRecallInterval, maxRecalls, exemptAdmin)); }
} WsbCatch(hr);
//
// Commenting the following out: we are reverting back to
// denial of service when we hit the recall limit, not trunc-on-close
//
// If we hit the recall limit then we start to truncate on close.
//
// if (hr == FSA_E_HIT_RECALL_LIMIT) {
// m_recallFlags |= RP_RECALL_ACTION_TRUNCATE;
// }
WsbTraceOut(OLESTR("CFsaFilterRecall::CheckRecallLimit"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::Init( IN IFsaFilterClient* pClient, IN ULONGLONG DriversRecallId, IN IFsaResource* pResource, IN OLECHAR* path, IN LONGLONG fileId, IN LONGLONG offset, IN LONGLONG size, IN ULONG mode, IN FSA_PLACEHOLDER* pPlaceholder, IN IFsaFilterPriv *pFilterPriv )
/*++
Implements:
IFsaFilterRecallPriv::Init().
--*/ { HRESULT hr = S_OK; FILETIME now; CComPtr<IFsaResourcePriv> pResourcePriv;
WsbTraceIn(OLESTR("CFsaFilterRecall::Init"), OLESTR("filter ID = %I64x, offset = %I64u, size = %I64u"), DriversRecallId, offset, size);
try { m_pClient = pClient; m_driversRecallId = DriversRecallId; m_pResource = pResource; m_placeholder = *pPlaceholder; m_pFilterPriv = pFilterPriv; m_path = path; m_mode = mode; m_fileId = fileId; GetSystemTimeAsFileTime(&m_startTime);
m_offset = offset; m_size = size; m_isDirty = TRUE;
WsbAssert(m_path != 0, E_UNEXPECTED); //
// Get the recall started with the engine
// Start a session and ask it to advise us of state changes.
// Tell the resource object that we got an open.
//
hr = S_OK; } WsbCatchAndDo(hr, //
// Something failed - send the kernel completion if it has not been sent already.
//
GetSystemTimeAsFileTime(&now); if (m_pClient != 0) { m_pClient->SetLastRecallTime(now); } if (m_kernelCompletionSent == FALSE) { m_pFilterPriv->SendComplete((IFsaFilterRecallPriv *) this, hr); m_kernelCompletionSent = TRUE; } else { WsbLogEvent(FSA_MESSAGE_RECALL_FAILED, 0, NULL, (OLECHAR*) WsbAbbreviatePath(path, 120), WsbHrAsString(hr), NULL); }
if (m_pClient != 0) { m_pClient->SendRecallInfo((IFsaFilterRecall *) this, FALSE, E_FAIL); // Not fatal if this fails
}
);
WsbTraceOut(OLESTR("CFsaFilterRecall::Init"), OLESTR("%ls"), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::Load( IN IStream* pStream )
/*++
Implements:
IPersistStream::Load().
--*/ { HRESULT hr = S_OK;
WsbTraceIn(OLESTR("CFsaFilterRecall::Load"), OLESTR(""));
try { WsbAssert(0 != pStream, E_POINTER); // No persistence.
hr = E_NOTIMPL;
} WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::Load"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::LogComplete( IN HRESULT result )
/*++
Implements:
IFsaFilterRecallPriv:LogComplete(HRESULT result)
--*/ { HRESULT hr = S_OK; FILETIME completeTime; LONGLONG recallTime;
WsbTraceIn(OLESTR("CFsaFilterRecall::LogComplete"), OLESTR("filter Id = %I64x"), m_driversRecallId);
try { // Calculate the time it took for this recall to complete
GetSystemTimeAsFileTime(&completeTime); recallTime = WsbFTtoLL(WsbFtSubFt(completeTime, m_startTime)); // If over 10 minutes then show time in minutes otherwise show in seconds
if (recallTime >= (WSB_FT_TICKS_PER_MINUTE * (LONGLONG) 10)) { recallTime = recallTime / WSB_FT_TICKS_PER_MINUTE; WsbTrace(OLESTR("CFsaFilterRecall::LogComplete Recall of %ws completed in %I64u minutes. (%ws)\n"), WsbAbbreviatePath(m_path, 120), recallTime, WsbHrAsString(result)); WsbLogEvent(FSA_MESSAGE_RECALL_TIMING_MINUTES, 0, NULL, WsbAbbreviatePath(m_path, 120), WsbLonglongAsString(recallTime), WsbHrAsString(result), NULL); } else { recallTime = recallTime / WSB_FT_TICKS_PER_SECOND; WsbTrace(OLESTR("CFsaFilterRecall::LogComplete Recall of %ws completed in %I64u seconds. (%ws)\n"), WsbAbbreviatePath(m_path, 120), recallTime, WsbHrAsString(result)); WsbLogEvent(FSA_MESSAGE_RECALL_TIMING_SECONDS, 0, NULL, WsbAbbreviatePath(m_path, 120), WsbLonglongAsString(recallTime), WsbHrAsString(result), NULL); }
} WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::LogComplete"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::Save( IN IStream* pStream, IN BOOL clearDirty )
/*++
Implements:
IPersistStream::Save().
--*/ { HRESULT hr = S_OK; CComPtr<IPersistStream> pPersistStream;
WsbTraceIn(OLESTR("CFsaFilterRecall::Save"), OLESTR("clearDirty = <%ls>"), WsbBoolAsString(clearDirty)); try { WsbAssert(0 != pStream, E_POINTER); // No persistence.
hr = E_NOTIMPL;
// If we got it saved and we were asked to clear the dirty bit, then
// do so now.
if (clearDirty) { m_isDirty = FALSE; }
} WsbCatch(hr);
WsbTraceOut(OLESTR("CFsaFilterRecall::Save"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::SetDriversRecallId( IN ULONGLONG pId )
/*++
Implements:
IFsaFilterRecallPriv::SetDriversRecallId().
--*/ { HRESULT hr = S_OK;
try {
m_driversRecallId = pId;
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::SetThreadId( IN DWORD id )
/*++
Implements:
IFsaFilterRecallPriv::SetThreadId().
--*/ { HRESULT hr = S_OK;
try {
m_threadId = id;
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::SetIdentifier( IN GUID id )
/*++
Implements:
IFsaFilterRecallPriv::SetIdentifier().
--*/ { HRESULT hr = S_OK;
m_id = id; m_isDirty = TRUE;
return(hr); }
HRESULT CFsaFilterRecall::StartRecall( IN ULONGLONG offset, IN ULONGLONG size )
/*++
Implements:
IFsaFilterRecallPriv::StartRecall().
--*/ { HRESULT hr = S_OK; FILETIME now; CComPtr<IFsaResourcePriv> pResourcePriv; CWsbStringPtr sessionName; ULONG tryLoop; BOOL bSentNotify = FALSE;
WsbTraceIn(OLESTR("CFsaFilterRecall::StartRecall"), OLESTR("filter Id = %I64x"), m_driversRecallId);
try { m_offset = offset; m_size = size; if (m_mode & FILE_OPEN_NO_RECALL) { if (m_offset >= m_placeholder.dataStreamSize) { //
// Read beyond the end of file
//
hr = STATUS_END_OF_FILE; WsbAffirmHr(hr); } else if ( (m_offset + m_size) > (m_placeholder.dataStreamStart + m_placeholder.dataStreamSize) ) { //
// They are asking for more than we have - adjust the read size
//
m_size -= (m_offset + m_size) - (m_placeholder.dataStreamStart + m_placeholder.dataStreamSize); } }
m_isDirty = TRUE;
WsbAssert(m_path != 0, E_UNEXPECTED); //
// Get the recall started with the engine
// Start a session and ask it to advise us of state changes.
// Tell the resource object that we got an open.
//
WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: BeginSession\n"));
// Get the string that we are using to describe the session.
WsbAffirmHr(sessionName.LoadFromRsc(_Module.m_hInst, IDS_FSA_RECALL_NAME));
WsbAffirmHr(m_pResource->BeginSession(sessionName, HSM_JOB_LOG_ITEMMOSTFAIL | HSM_JOB_LOG_HR, 1, 1, &m_pSession));
WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: Session is setup.\n")); WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: Notify the client that the recall started.\n"));
if (m_pClient != 0) { hr = m_pClient->SendRecallInfo((IFsaFilterRecall *) this, TRUE, S_OK); // Not fatal if this fails
if (! SUCCEEDED(hr)) { WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: SendNotify failed with %ls.\n"), WsbHrAsString(hr)); } else { if (hr != S_OK) { WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: SendNotify returned %ls.\n"), WsbHrAsString(hr)); }
bSentNotify = TRUE; } } hr = S_OK; //
// Tell the resource to send the job to the engine.
//
WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: Calling FilterSawOpen.\n"));
WsbAffirmHr(m_pResource->QueryInterface(IID_IFsaResourcePriv, (void**) &pResourcePriv));
if (m_mode & FILE_OPEN_NO_RECALL) { WsbAffirmHr(pResourcePriv->FilterSawOpen(m_pSession, (IFsaFilterRecall*) this, m_path, m_fileId, offset, size, &m_placeholder, m_mode, FSA_RESULT_ACTION_NORECALL, m_threadId)); } else { WsbAffirmHr(pResourcePriv->FilterSawOpen(m_pSession, (IFsaFilterRecall*) this, m_path, m_fileId, offset, size, &m_placeholder, m_mode, FSA_RESULT_ACTION_OPEN, m_threadId)); }
//
// The work is now complete - terminate the session.
//
WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: End Session.\n")); WsbAffirmHr(m_pResource->EndSession(m_pSession));
//
// Try the notification again if we have not sent it yet.
// On the first recall from a remote client the identification usually does not
// happen in time for the first attempt so we try again here.
// We will try 5 times with a .1 second delay between.
//
WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: m_pClient = %x sent = %u.\n"), m_pClient, bSentNotify);
if ((m_pClient != 0) && (!bSentNotify)) { tryLoop = 5; while ((tryLoop != 0) &&( !bSentNotify)) {
// Reporting here is done after the recall is started.
// Therefore, it must be synchronized with the recall end notification
switch (WaitForSingleObject(m_notifyEvent, INFINITE)) { case WAIT_OBJECT_0: // Check if need to report (if recall did not end yet)
if (m_kernelCompletionSent == FALSE) { // Recall end was not sent yet
hr = m_pClient->SendRecallInfo((IFsaFilterRecall *) this, TRUE, S_OK); // Not fatal if this fails
} SetEvent(m_notifyEvent); break;
case WAIT_FAILED: default: WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: WaitForSingleObject returned error %lu\n"), GetLastError());
// Just get out without notifying
hr = S_OK; break; }
if (! SUCCEEDED(hr)) { WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: Retried notify failed with %ls.\n"), WsbHrAsString(hr)); if (tryLoop != 1) { Sleep(100); // Sleep .1 sec and try again
} } else { if (hr != S_OK) WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: Retried notify returned %ls.\n"), WsbHrAsString(hr));
bSentNotify = TRUE; }
tryLoop--; }
hr = S_OK; }
} WsbCatchAndDo(hr, //
// Something failed - send the kernel completion if it has not been sent already.
//
GetSystemTimeAsFileTime(&now); if (m_pClient != 0) { m_pClient->SetLastRecallTime(now); } if (m_kernelCompletionSent == FALSE) { m_pFilterPriv->SendComplete((IFsaFilterRecallPriv *) this, hr); m_kernelCompletionSent = TRUE; } else { //
// STATUS_END_OF_FILE is not really an error - it just means they tried to read past the end - some apps do this and expect
// this status to tell them when to stop reading.
//
if (hr != STATUS_END_OF_FILE) { WsbLogEvent(FSA_MESSAGE_RECALL_FAILED, 0, NULL, (OLECHAR*) WsbAbbreviatePath(m_path, 120), WsbHrAsString(hr), NULL); } }
if (m_pClient != 0) { m_pClient->SendRecallInfo((IFsaFilterRecall *) this, FALSE, E_FAIL); // Not fatal if this fails
}
);
WsbTraceOut(OLESTR("CFsaFilterRecall::StartRecall"), OLESTR("%ls"), WsbHrAsString(hr));
return(hr); }
HRESULT CFsaFilterRecall::Test( USHORT* passed, USHORT* failed )
/*++
Implements:
IWsbTestable::Test().
--*/ { HRESULT hr = S_OK;
try {
WsbAssert(0 != passed, E_POINTER); WsbAssert(0 != failed, E_POINTER);
*passed = 0; *failed = 0;
} WsbCatch(hr);
return(hr); }
HRESULT CFsaFilterRecall::WasCancelled( void )
/*++
Implements:
IFsaFilterRecall::WasCancelled().
--*/ { HRESULT hr = S_OK;
if (!m_wasCancelled) { hr = S_FALSE; }
return(hr); }
HRESULT CFsaFilterRecall::AddClient( IFsaFilterClient *pWaitingClient ) /*++
Implements:
IFsaFilterRecall::AddClient
--*/ { HRESULT hr = E_FAIL; switch (WaitForSingleObject(m_waitingClientEvent, INFINITE)) { case WAIT_OBJECT_0: if ((!m_waitingClientsNotified) && (m_pWaitingClients != 0)) { hr = m_pWaitingClients->Add(pWaitingClient); if (hr == S_OK) { // Notify client only if it was added successfully to the collection
hr = pWaitingClient->SendRecallInfo((IFsaFilterRecall *) this, TRUE, S_OK); // Not fatal if this fails
if (hr != S_OK) { // Note that S_FALSE is an "expected failure" but we still want to trace this
WsbTrace(OLESTR("CFsaFilterRecall::AddClient: SendNotify for start returned %ls.\n"), WsbHrAsString(hr)); } } }
SetEvent(m_waitingClientEvent); break;
case WAIT_FAILED: default: DWORD dwErr = GetLastError(); WsbTrace(OLESTR("CFsaFilterRecall::AddClient: WaitForSingleObject returned error %lu\n"), dwErr);
// Don't add waiting client
hr = HRESULT_FROM_WIN32(dwErr); break; }
return(hr); }
|