WindowsXP-SP1/base/fs/hsm/fsa/fsaftrcl.cpp
2020-09-30 16:53:49 +02:00

1847 lines
42 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
© 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->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;
WsbAffirmHr(CoCreateGuid(&m_id));
numRefs = 0;
m_waitingClientsNotified = FALSE;
// 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->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->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->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->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 (hr != S_OK) {
WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: SendNotify returned %ls.\n"),
WsbHrAsString(hr));
} else {
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 (hr != S_OK) {
WsbTrace(OLESTR("CFsaFilterRecall::StartRecall: Retried notify - %ls.\n"),
WsbHrAsString(hr));
if (tryLoop != 1) {
Sleep(100); // Sleep .1 sec and try again
}
} else {
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) {
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);
}