/*++ Copyright (c) 1999 Microsoft Corporation Abstract: @doc @module Writer.h | Declaration of Writer @end Author: Adi Oltean [aoltean] 08/18/1999 TBD: Add comments. Revision History: Name Date Comments aoltean 08/18/1999 Created brianb 05/03/2000 Changed for new security model brianb 05/09/2000 fix problem with autolocks mikejohn 06/23/2000 Add connection for SetWriterFailure() --*/ #ifndef __CVSS_WRITER_IMPL_H_ #define __CVSS_WRITER_IMPL_H_ // forward declarations class CVssWriterImplStateMachine; class CVssCreateWriterMetadata; class CVssWriterComponents; class IVssWriterComponentsInt; //////////////////////////////////////////////////////////////////////// // Standard foo for file name aliasing. This code block must be after // all includes of VSS header files. // #ifdef VSS_FILE_ALIAS #undef VSS_FILE_ALIAS #endif #define VSS_FILE_ALIAS "INCWRMPH" // //////////////////////////////////////////////////////////////////////// // implementation class for writers class IVssWriterImpl : public IVssWriter { public: // initialize writer virtual void Initialize ( VSS_ID writerId, LPCWSTR wszWriterName, VSS_USAGE_TYPE ut, VSS_SOURCE_TYPE st, VSS_APPLICATION_LEVEL nLevel, DWORD dwTimeout ) = 0; // subscribe to events virtual void Subscribe ( ) = 0; // unsubscribe from events virtual void Unsubscribe ( ) = 0; // get array of volume names virtual LPCWSTR *GetCurrentVolumeArray() const = 0; // get # of volumes in volume array virtual UINT GetCurrentVolumeCount() const = 0; // get id of snapshot set virtual VSS_ID GetCurrentSnapshotSetId() const = 0; // determine which Freeze event writer responds to virtual VSS_APPLICATION_LEVEL GetCurrentLevel() const = 0; // determine if path is included in the snapshot virtual bool IsPathAffected(IN LPCWSTR wszPath) const = 0; // determine if bootable state is backed up virtual bool IsBootableSystemStateBackedUp() const = 0; // determine if the backup application is selecting components virtual bool AreComponentsSelected() const = 0; // determine the backup type for the backup virtual VSS_BACKUP_TYPE GetBackupType() const = 0; // let writer pass back indication of reason for failure virtual HRESULT SetWriterFailure(HRESULT hr) = 0; }; ///////////////////////////////////////////////////////////////////////////// // CVssWriterImpl class ATL_NO_VTABLE CVssWriterImpl : public CComObjectRootEx, public IVssWriterImpl { public: friend class CVssWriterImplLock; // Constructors & Destructors CVssWriterImpl(); ~CVssWriterImpl(); // Exposed operations public: // create a writer implementation for a specific writer static void CreateWriter ( CVssWriter *pWriter, IVssWriterImpl **ppImpl ); // set external writer object void SetWriter(CVssWriter *pWriter) { BS_ASSERT(pWriter); m_pWriter = pWriter; } // initialize class void Initialize ( IN VSS_ID WriterID, IN LPCWSTR wszWriterName, IN VSS_USAGE_TYPE ut, IN VSS_SOURCE_TYPE st, IN VSS_APPLICATION_LEVEL nLevel, IN DWORD dwTimeoutFreeze ); // subscribe to writer events void Subscribe ( ); // unsubscribe from writer events void Unsubscribe ( ); // get array of volume names LPCWSTR* GetCurrentVolumeArray() const { return (LPCWSTR *) m_ppwszVolumesArray; }; // get count of volumes in array UINT GetCurrentVolumeCount() const { return m_nVolumesCount; }; // get id of snapshot VSS_ID GetCurrentSnapshotSetId() const { return m_CurrentSnapshotSetId; }; // get level at which freeze takes place VSS_APPLICATION_LEVEL GetCurrentLevel() const { return m_nLevel; }; // determine if path is included in the snapshot bool IsPathAffected(IN LPCWSTR wszPath) const; // determine if the backup is including bootable system state bool IsBootableSystemStateBackedUp() const { return m_bBootableSystemStateBackup ? true : false; } // determine if the backup selects components bool AreComponentsSelected() const { return m_bComponentsSelected ? true : false; } // return the type of backup VSS_BACKUP_TYPE GetBackupType() const { return m_backupType; } // indicate why the writer failed HRESULT SetWriterFailure(HRESULT hr); // IVssWriter ovverides public: BEGIN_COM_MAP(CVssWriterImpl) COM_INTERFACE_ENTRY(IVssWriter) END_COM_MAP() // request WRITER_METADATA or writer state STDMETHOD(RequestWriterInfo)( IN BSTR bstrSnapshotSetId, IN BOOL bWriterMetadata, IN BOOL bWriterState, IN IDispatch* pWriterCallback ); // prepare for backup event STDMETHOD(PrepareForBackup)( IN BSTR bstrSnapshotSetId, IN IDispatch* pWriterCallback ); // prepare for snapshot event STDMETHOD(PrepareForSnapshot)( IN BSTR bstrSnapshotSetId, IN BSTR VolumeNamesList ); // freeze event STDMETHOD(Freeze)( IN BSTR bstrSnapshotSetId, IN INT nApplicationLevel ); // thaw event STDMETHOD(Thaw)( IN BSTR bstrSnapshotSetId ); // backup complete event STDMETHOD(BackupComplete)( IN BSTR bstrSnapshotSetId, IN IDispatch* pWriterCallback ); // backup shutdown event STDMETHOD(BackupShutdown)( IN BSTR bstrSnapshotSetId ); // abort event STDMETHOD(Abort)( IN BSTR bstrSnapshotSetId ); STDMETHOD(PostRestore)( IN IDispatch* pWriterCallback ); STDMETHOD(PreRestore)( IN IDispatch* pWriterCallback ); STDMETHOD(PostSnapshot)( IN BSTR bstrSnapshotSestId, IN IDispatch* pWriterCallback, IN BSTR SnapshotDevicesList ); // Implementation - methods private: enum VSS_EVENT_MASK { VSS_EVENT_PREPAREBACKUP = 0x00000001, VSS_EVENT_PREPARESNAPSHOT = 0x00000002, VSS_EVENT_FREEZE = 0x00000004, VSS_EVENT_THAW = 0x00000008, VSS_EVENT_ABORT = 0x00000010, VSS_EVENT_BACKUPCOMPLETE = 0x00000020, VSS_EVENT_REQUESTINFO = 0x00000040, VSS_EVENT_RESTORE = 0x00000080, VSS_EVENT_ALL = 0xff, }; // get WRITER callback from IDispatch void GetCallback ( IN IDispatch *pWriterCallback, OUT IVssWriterCallback **ppCallback ); // reset state machine void ResetSequence ( IN bool bCalledFromTimerThread ); // abort the current snapshot sequence void DoAbort ( IN bool bCalledFromTimerThread ); // obtain components for this writer void InternalGetWriterComponents ( IN IVssWriterCallback *pCallback, OUT IVssWriterComponentsInt **ppWriter, bool bWriteable ); // create WRITER_METADATA XML document CVssCreateWriterMetadata *CreateBasicWriterMetadata ( ); // startup routine for timer thread static DWORD StartTimerThread(void *pv); // function to run in timer thread void TimerFunc(VSS_ID id); // enter a state bool EnterState ( IN const CVssWriterImplStateMachine &vwsm, IN BSTR bstrSnapshotSetId ) throw(HRESULT); // leave a state void LeaveState ( IN const CVssWriterImplStateMachine &vwsm, IN bool fSuccessful ); // create a Handle to an event void SetupEvent ( IN HANDLE *phevt ) throw(HRESULT); // begin a sequence to create a snapshot void BeginSequence ( IN CVssID &SnapshotSetId ) throw(HRESULT); INT SearchForPreviousSequence( IN VSS_ID& idSnapshotSet ); // terminate timer thread void TerminateTimerThread(); // lock critical section inline void Lock() { m_cs.Lock(); m_bLocked = true; } // unlock critical section inline void Unlock() { m_bLocked = false; m_cs.Unlock(); } // assert that critical section is locked inline void AssertLocked() { BS_ASSERT(m_bLocked); } // Implementation - members private: enum VSS_TIMER_COMMAND { VSS_TC_UNDEFINED, VSS_TC_ABORT_CURRENT_SEQUENCE, VSS_TC_TERMINATE_THREAD, VSS_TIMEOUT_FREEZE = 60*1000, // 30 seconds VSS_STACK_SIZE = 256 * 1024 // 256K }; enum { x_MAX_SUBSCRIPTIONS = 32 }; // data related to writer // writer class id VSS_ID m_WriterID; // writer instance id VSS_ID m_InstanceID; // usage type for writer VSS_USAGE_TYPE m_usage; // data source type for writer VSS_SOURCE_TYPE m_source; // writer name LPWSTR m_wszWriterName; // Data related to the current sequence // snapshot set id VSS_ID m_CurrentSnapshotSetId; // volume array list passed in as a string LPWSTR m_pwszLocalVolumeNameList; // # of volumes in volume array INT m_nVolumesCount; // volume array LPWSTR* m_ppwszVolumesArray; // pointer to writer callback CComPtr m_pWriterCallback; // are we currently in a sequence bool m_bSequenceInProgress; // current state of the writer VSS_WRITER_STATE m_state; // Subscription-related data CComBSTR m_bstrSubscriptionName; // actual subscription ids CComBSTR m_rgbstrSubscriptionId[x_MAX_SUBSCRIPTIONS]; // number of allocated subscription ids UINT m_cbstrSubscriptionId; // Data related with the Writer object // which freeze event is handled VSS_APPLICATION_LEVEL m_nLevel; // what events are subscribed to DWORD m_dwEventMask; // count of subscriptions INT m_nSubscriptionsCount; // Critical section or avoiding race between tasks CVssSafeCriticalSection m_cs; // was critical section initialized bool m_bLockCreated; // flag indicating if critical section is locked bool m_bLocked; // timeout and queuing mechanisms HANDLE m_hevtTimerThread; // event used to signal timer thread if timer is aborted HANDLE m_hmtxTimerThread; // mutex used to guarantee only one timer thread exists at a time HANDLE m_hThreadTimerThread; // handle to timer thread VSS_TIMER_COMMAND m_command; // timer command when it exits the wait DWORD m_dwTimeoutFreeze; // timeout for freeze // actual writer implementation CVssWriter *m_pWriter; // state of backup components BOOL m_bBootableSystemStateBackup; BOOL m_bComponentsSelected; VSS_BACKUP_TYPE m_backupType; // indication why the writer failed HRESULT m_hrWriterFailure; // structures to keep track of writer status from previous snapshots enum { MAX_PREVIOUS_SNAPSHOTS = 8, INVALID_SEQUENCE_INDEX = -1 }; // snapshot ids of previous snapshots VSS_ID m_rgidPreviousSnapshots[MAX_PREVIOUS_SNAPSHOTS]; // status from previous snapshots VSS_WRITER_STATE m_rgstatePreviousSnapshots[MAX_PREVIOUS_SNAPSHOTS]; // failure reasons from previous snapshots HRESULT m_rghrWriterFailurePreviousSnapshots[MAX_PREVIOUS_SNAPSHOTS]; // current slot for dumping a previous snapshots result UINT m_iPreviousSnapshots; // TRUE if an OnPrepareForBackup/Freeze/Thaw // was sent and without a corresponding OnAbort bool m_bOnAbortPermitted; // FALSE if an previous OnIdentify failed // TRUE if OnIdentify succeeded or was not called at all bool m_bFailedAtIdentify; }; // auto class for locks class CVssWriterImplLock { public: CVssWriterImplLock(CVssWriterImpl *pImpl) : m_pImpl(pImpl) { m_pImpl->Lock(); } ~CVssWriterImplLock() { m_pImpl->Unlock(); } private: CVssWriterImpl *m_pImpl; }; #endif //__CVSS_WRITER_IMPL_H_