//+-------------------------------------------------------------------------
//
//  File:       crecover.cxx
//
//  Contents:   Implementation for the CRecover support class.
//
//  History:    09-Mar-93       SudK            Created
//
//--------------------------------------------------------------------------

#include "headers.hxx"
#pragma hdrstop

#include "crecover.hxx"

//+------------------------------------------------------------------------
//
// Method:      CRecover::CRecover
//
// Synopsis:    The Constructor for this Class. This constructor sets the
//              Operation Stage and Operation in its private section to 0.
//              No persistent storage operations are done here.
//
// Arguments:   [iprop] --      The IProperty instance. Without this it does not
//                              make sense to instantiate this class.
//
// Returns:     Nothing.
//
// History:     09-Mar-1993     SudK    Created.
//
//-------------------------------------------------------------------------
CRecover::CRecover(void)
{
    IDfsVolInlineDebOut((
        DEB_TRACE, "CRecover::+CRecover(0x%x)\n",
        this));

    _Operation = 0;
    _OperStage = 0;
    _RecoveryState = 0;
    _RecoveryBuffer = _ulongBuffer;
    _pPSStg = NULL;

}


//+------------------------------------------------------------------------
//
// Method:      CRecover::~CRecover
//
// Synopsis:    The Destructor.
//
// Arguments:   None
//
// Returns:     It does nothing actually except to deallocate any memory.
//
// History:     09-Mar-1993     SudK    Created.
//
//-------------------------------------------------------------------------
CRecover::~CRecover(void)
{
    IDfsVolInlineDebOut((
        DEB_TRACE, "CRecover::~CRecover(0x%x)\n",
        this));

    if (_RecoveryBuffer != _ulongBuffer)
        delete [] _RecoveryBuffer;

    if (_pPSStg != NULL)
        _pPSStg->Release();
}

//+------------------------------------------------------------------------
//
// Method:      CRecover::Initialise
//
// Synopsis:    Set the IProperty interface. This should not be called twice!!
//
// Arguments:   [pPSStg] -- The IPropertySetStg from here we get to Props
//
// Returns:     Nothing.
//
// History:     09-Mar-1993     SudK    Created.
//
//-------------------------------------------------------------------------
VOID
CRecover::Initialize(
    CStorage *pPSStg)
{
    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::Initialize()\n"));

    ASSERT(_pPSStg == NULL);

    if (_pPSStg != NULL)
        _pPSStg->Release();

    _pPSStg = pPSStg;
    _pPSStg->AddRef();

    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::Initialize() exit\n"));
}


//+------------------------------------------------------------------------
//
// Method:      CRecover::SetOperationStart
//
// Synopsis:    Used when one is about to start an operation. Takes Operation
//              Code and any recovery arg if necessary.
//
// Arguments:   [Operation] --  The operation code for which this class is
//                              being instantiated.
//              [RecoverySvc]-- The Recovery Svc if any associated with this
//                              Operation.
//
// Returns:     Nothing. If it cant set properties it will throw an exception.
//
// Notes:       Caller should take care of freeing the Service passed in.
//
// History:     09-Mar-1993     SudK    Created.
//
//-------------------------------------------------------------------------
DWORD
CRecover::SetOperationStart(ULONG fOperation, CDfsService *pRecoverySvc)
{
    ULONG       size;
    DWORD dwErr = ERROR_SUCCESS;
    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::SetOperationStart()\n"));

    //
    // There could be a recovery buffer from a previous different operation.
    // So we need to get rid of it and create an appropriate sized one again.
    //
    if (_RecoveryBuffer != _ulongBuffer)        {
        delete [] _RecoveryBuffer;
        _RecoveryBuffer = _ulongBuffer;
    }
    //
    // Set the private section variables first.
    //
    _Operation = fOperation;
    _OperStage = DFS_OPER_STAGE_START;

    //
    // Create the RecoverState and the RecoverySvc in private section.
    //
    _RecoveryState = DFS_COMPOSE_RECOVERY_STATE(_Operation, _OperStage);

    //
    // Let us figure out the marshalled buffer for the Service and create it.
    //
    if (pRecoverySvc != NULL)   {
        size = pRecoverySvc->GetMarshalSize();

        _RecoveryBuffer = new BYTE[size + sizeof(ULONG)]; 
        if (_RecoveryBuffer == NULL) {
            dwErr = ERROR_OUTOFMEMORY;
            return dwErr;
	}
 
        _PutULong(_RecoveryBuffer, size);

        pRecoverySvc->Serialize(_RecoveryBuffer + sizeof(ULONG), size);
    }
    else        {
        //
        // In this case also we add a BLOB but however, this is only an Empty
        // BLOB. So this is easy to handle.
        //
        _PutULong(_RecoveryBuffer, 0);
    }

    SetRecoveryProps(_RecoveryState, _RecoveryBuffer, FALSE);

    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::SetOperationStart() exit\n"));

    return dwErr;
}


//+------------------------------------------------------------------------
//
// Method:      CRecover::SetDefaultProps
//
// Synopsis:    This method sets null recovery props to start.
//
// Arguments:   None
//
// Returns:     Nothing.
//
// Notes:       This may throw an exception. Failure of this is truly an
//              appropriate time to throw an exception.
//
// History:     12-21-1993      SudK    Created.
//
//-------------------------------------------------------------------------
VOID
CRecover::SetDefaultProps(void)
{
    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::SetDefaultProps()\n"));

    _RecoveryState = DFS_RECOVERY_STATE_NONE;
    _Operation = 0;
    _OperStage = 0;

    _PutULong(_RecoveryBuffer, 0);
    SetRecoveryProps(_RecoveryState, _RecoveryBuffer, TRUE);

    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::SetDefaultProps() exit\n"));
}

//+------------------------------------------------------------------------
//
// Method:      CRecover::SetOperationDone
//
// Synopsis:    This method deletes all recovery properties to signify end of
//              the Operation that was in progress.
//
// Arguments:   [Operation] -- The Operation Code.
//
// Returns:     Nothing.
//
// Notes:       This may throw an exception. Failure of this is truly an
//              appropriate time to throw an exception.
//
// History:     09-Mar-1993     SudK    Created.
//
//-------------------------------------------------------------------------
VOID
CRecover::SetOperationDone(void)
{
    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::SetOperationDone()\n"));

    _RecoveryState = DFS_RECOVERY_STATE_NONE;
    _Operation = 0;
    _OperStage = 0;

    _PutULong(_RecoveryBuffer, 0);
    SetRecoveryProps(_RecoveryState, _RecoveryBuffer, FALSE);

    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::SetOperationDone() exit\n"));
}

//+------------------------------------------------------------------------
//
// Method:      CRecover::SetOperStage
//
// Synopsis:    This methods sets the operation stage in its private section
//              and at the same time updates the VolumeObject.
//
// Arguments:   [OperStage] -- Operation Stage.
//
// Returns:     Nothing. It throws an exception if it has any problems.
//
// History:     09-Mar-1993     SudK    Created.
//
//-------------------------------------------------------------------------
VOID
CRecover::SetOperStage(ULONG OperStage)
{
    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::SetOperStage()\n"));

    _OperStage = OperStage;
    _RecoveryState = DFS_COMPOSE_RECOVERY_STATE(_Operation, _OperStage);

    SetRecoveryProps(_RecoveryState, _RecoveryBuffer, FALSE);

    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::SetOperStage() exit\n"));
}


//+------------------------------------------------------------------------
//
// Method:      CRecover::SetRecoveryProps
//
// Synopsis:    This method interacts with the actual property interface
//              to set the recovery properties.
//
// Arguments:   [RecoveryState] --      Recovery State.
//              [RecoveryBuffer] --     Recovery Argument if any.
//              [bCreate] --            Whether to create Propset or not.
//
// Returns:     Nothing. Will throw exception if anything goes wrong.
//
// Notes:       Caller must free the buffer that he passed in.
//
// History:     09-Mar-1993     SudK    Created.
//
//-------------------------------------------------------------------------
VOID
CRecover::SetRecoveryProps(
    ULONG RecoveryState,
    PBYTE RecoveryBuffer,
    BOOLEAN bCreate
)
{
    DWORD       dwErr;
    DWORD       cbSize;

    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::SetRecoveryProps()\n"));

    _GetULong(RecoveryBuffer, cbSize);
    _PutULong(RecoveryBuffer, RecoveryState);

    dwErr = _pPSStg->SetRecoveryProps(RecoveryBuffer, cbSize+sizeof(ULONG));

    _PutULong(RecoveryBuffer, cbSize);

    if (dwErr != ERROR_SUCCESS)     {
        IDfsVolInlineDebOut((
            DEB_ERROR, "Unable to Set RecoveryProperties %08lx\n",dwErr));

        RaiseException ( dwErr, 0, 0, 0 );        
    }

    IDfsVolInlineDebOut((DEB_TRACE, "CRecover::SetRecoveryProps() exit\n"));
}



//+-------------------------------------------------------------------------
//
//  Method:   CRecover::GetRecoveryProps, private
//
//  Synopsis: Get the recovery related properties off the volume object.
//
//  Arguments:[RecoveryState] -- The RecoveryState is returned here.
//            [ppRecoverySvc] -- If there is a recovery Svc it is returned here.
//
//  Returns:
//
//  History:  09-Feb-1993       SudK    Created.
//
//--------------------------------------------------------------------------
DWORD
CRecover :: GetRecoveryProps(
    ULONG  *RecoveryState,
    CDfsService **ppRecoverySvc
)
{
    DWORD               dwErr = ERROR_SUCCESS;
    PBYTE               buffer, svcBuffer;
    ULONG               size;

    IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetRecoveryProps()\n"));

    //
    // Initialize all the arguments to NULL
    //

    *RecoveryState = 0;
    *ppRecoverySvc = NULL;

    dwErr = _pPSStg->GetRecoveryProps( &buffer, &size );

    if (dwErr != ERROR_SUCCESS)     {
        IDfsVolInlineDebOut((
            DEB_ERROR, "Unable to read recovery Props %08lx\n", dwErr));
        SetOperationDone();
        return(dwErr);
    }

    //
    // First let us extract the RecoveryState property.
    //
    _GetULong(buffer, (*RecoveryState));

    //
    // Next let us extract the RecoveryArg property.
    //

    svcBuffer = buffer + sizeof(ULONG);
    size -= sizeof(ULONG);

    //
    // Now that we have a buffer we have to create a service out of this.
    // If the buffer is of size Zero we will just return back a NULL ptr.
    //
    if (size != 0)      {
        dwErr = CDfsService::DeSerialize(svcBuffer, size, ppRecoverySvc);
        if (dwErr != ERROR_SUCCESS) {
            IDfsVolInlineDebOut((
                DEB_ERROR, "Failed %d to unmarshall RecoverySvc\n", dwErr));
            *ppRecoverySvc = NULL;
        }
    }

    delete [] buffer;

    IDfsVolInlineDebOut((DEB_TRACE, "CDfsVolume::GetRecoveryProps() exit\n"));

    return dwErr;
}



#if (DBG == 1) || (_CT_TEST_HOOK == 1)
INIT_RECOVERY_BREAK_INFO()
//+-------------------------------------------------------------------------
//
//  Function: DfsSetRecoveryBreakPoint
//
//  Synopsis: Sets the globals that determine when a recovery break point
//            is activated
//
//  Arguments:[pBuffer]         --  Marshalled buffer
//            [cbSize]          --  Size of the marhalled buffer
//
//  Returns:  STATUS_SUCCESS    --  Success
//
//--------------------------------------------------------------------------
NTSTATUS DfsSetRecoveryBreakPoint(PBYTE pBuffer,
                                  ULONG cbSize)
{
    NTSTATUS            Status;
    MARSHAL_BUFFER      marshalBuffer;

    MarshalBufferFree(gRecoveryBkptInfo.pwszApiBreak);

    MarshalBufferInitialize(&marshalBuffer, cbSize, pBuffer);

    Status = DfsRtlGet(&marshalBuffer, &MiRecoveryBkpt, &gRecoveryBkptInfo);

    return(Status);
}
#endif