//+---------------------------------------------------------------------------- // // Copyright (C) 1998,1999 Microsoft Corporation // // File: ntfs.h // // Contents: Header file for NTFS-base message class // //----------------------------------------------------------------------------- #ifndef __NTFS_H_ #define __NTFS_H_ #include "resource.h" // main symbols #include "listmacr.h" #include "evntwrap.h" #include "perf.h" // // Class IDs // EXTERN_C const CLSID CLSID_NtfsStoreDriver; EXTERN_C const CLSID CLSID_NtfsEnumMessages; EXTERN_C const CLSID CLSID_NtfsPropertyStream; ///////////////////////////////////////////////////////////////////////////// // CDriverUtils class CDriverUtils { public: CDriverUtils(); ~CDriverUtils(); static HRESULT LoadStoreDirectory( DWORD dwInstanceId, LPTSTR szStoreDirectory, DWORD *pdwLength ); static HRESULT GetStoreFileName( LPTSTR szStoreDirectory, LPTSTR szStoreFilename, DWORD *pdwLength ); static HRESULT GetStoreFileFromPath( LPTSTR szStoreFilename, IMailMsgPropertyStream **ppStream, PFIO_CONTEXT *phContentFile, BOOL fCreate, BOOL fIsFAT, IMailMsgProperties *pMsg, GUID guidInstance = GUID_NULL ); static HRESULT SetMessageContext( IMailMsgProperties *pMsg, LPBYTE pbContext, DWORD dwLength ); static HRESULT GetMessageContext( IMailMsgProperties *pMsg, LPBYTE pbContext, DWORD *pdwLength ); static HRESULT IsStoreDirectoryFat( LPTSTR szStoreDirectory, BOOL *pfIsFAT ); #if 0 static HANDLE CreateFileCallback( LPSTR szFilename, LPVOID lpvData, DWORD *pdwSize, DWORD *pdwSizeHigh ); #endif private: static DWORD s_dwCounter; }; typedef struct { DWORD dwSignature; DWORD dwVersion; GUID guidInstance; } NTFS_STREAM_HEADER; #define STREAM_OFFSET sizeof(NTFS_STREAM_HEADER) #define STREAM_SIGNATURE 'rvDN' #define STREAM_SIGNATURE_INVALID 'rvD!' #define STREAM_SIGNATURE_PRECOMMIT 'rvDp' #define STREAM_SIGNATURE_NOOFFSET 'MMCv' // // These are internal status codes used by CNtfsStoreDriver::SetHandle // to report on the status of the current stream // // They aren't errors because SetHandle does actually load the stream. // they are hints to the caller telling them that mailmsg won't be // able to parse the stream. // #define FACILITY_NTFSDRV 0x6b1 #define NTFSDRV_S_HRESULT(_x_) \ MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NTFSDRV, (_x_)) #define S_NO_FIRST_COMMIT NTFSDRV_S_HRESULT(1) #define S_INVALIDSTREAM NTFSDRV_S_HRESULT(2) ///////////////////////////////////////////////////////////////////////////// // CNtfsStoreDriver class ATL_NO_VTABLE CNtfsStoreDriver : public IMailMsgStoreDriver, public ISMTPStoreDriver, public IEventIsCacheable, public CComObjectRootEx, public CComCoClass, public IMailMsgStoreDriverValidateContext { public: CNtfsStoreDriver(); ~CNtfsStoreDriver(); LONG AddUsage() { return(InterlockedIncrement(&m_lRefCount)); } LONG ReleaseUsage() { return(InterlockedDecrement(&m_lRefCount)); } DWORD GetInstance() { return(m_dwInstance); } BOOL IsShuttingDown() { return(m_fIsShuttingDown); } /***************************************************************************/ // // Implementation of IUnknown // HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, void **ppvObject ); ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); /***************************************************************************/ // // IMailMsgStoreDriver // HRESULT STDMETHODCALLTYPE AllocMessage( IMailMsgProperties *pMsg, DWORD dwFlags, IMailMsgPropertyStream **ppStream, PFIO_CONTEXT *phContentFile, IMailMsgNotify *pNotify ); HRESULT STDMETHODCALLTYPE EnumMessages( IMailMsgEnumMessages **ppEnum ); HRESULT STDMETHODCALLTYPE ReOpen( IMailMsgProperties *pMsg, IMailMsgPropertyStream **ppStream, PFIO_CONTEXT *phContentFile, IMailMsgNotify *pNotify ); HRESULT STDMETHODCALLTYPE Delete( IMailMsgProperties *pMsg, IMailMsgNotify *pNotify ); HRESULT STDMETHODCALLTYPE CloseContentFile( IMailMsgProperties *pMsg, PFIO_CONTEXT hContentFile ); HRESULT STDMETHODCALLTYPE ReAllocMessage( IMailMsgProperties *pOriginalMsg, IMailMsgProperties *pNewMsg, IMailMsgPropertyStream **ppStream, PFIO_CONTEXT *phContentFile, IMailMsgNotify *pNotify ); HRESULT STDMETHODCALLTYPE SupportWriteContent() { return S_OK; } /***************************************************************************/ // // ISMTPStoreDriver // HRESULT STDMETHODCALLTYPE Init( DWORD dwInstance, IUnknown *pBinding, IUnknown *pServer, DWORD dwReason, IUnknown **ppStoreDriver ); HRESULT STDMETHODCALLTYPE PrepareForShutdown( DWORD dwReason ); HRESULT STDMETHODCALLTYPE Shutdown( DWORD dwReason ); HRESULT STDMETHODCALLTYPE LocalDelivery( IMailMsgProperties *pMsg, DWORD dwRecipCount, DWORD *pdwRecipIndexes, IMailMsgNotify *pNotify ); HRESULT STDMETHODCALLTYPE EnumerateAndSubmitMessages( IMailMsgNotify *pNotify ); // // IEventIsCahceable // HRESULT STDMETHODCALLTYPE IsCacheable(); // // IMailMsgStoreDriverValidateContext // HRESULT STDMETHODCALLTYPE ValidateMessageContext( BYTE *pbContext, DWORD cbContext); DECLARE_REGISTRY_RESOURCEID(IDR_NTFSDRV) BEGIN_COM_MAP(CNtfsStoreDriver) COM_INTERFACE_ENTRY(IMailMsgStoreDriver) COM_INTERFACE_ENTRY(ISMTPStoreDriver) COM_INTERFACE_ENTRY(IEventIsCacheable) COM_INTERFACE_ENTRY(IMailMsgStoreDriverValidateContext) END_COM_MAP() GUID GetInstanceGuid() { return m_guidInstance; } BOOL IsFAT() { return m_fIsFAT; } private: LONG m_lRefCount; DWORD m_dwInstance; TCHAR m_szQueueDirectory[MAX_PATH * 2]; BOOL m_fInitialized; BOOL m_fIsShuttingDown; ISMTPServer *m_pSMTPServer; // Reference count LONG m_ulRefCount; BOOL m_fIsFAT; // our instance guid GUID m_guidInstance; public: //Use list entry to maintain the list to keep track of current //instances of sink of this type LIST_ENTRY m_InstLEntry; public: //Global array of instances static DWORD sm_cCurrentInstances; static CRITICAL_SECTION sm_csLockInstList; static LIST_ENTRY sm_ListHead; //for controlling the retry queue static void LockList () {EnterCriticalSection (&CNtfsStoreDriver::sm_csLockInstList);} static void UnLockList() {LeaveCriticalSection (&CNtfsStoreDriver::sm_csLockInstList);} //Lookup and insert into array static IUnknown * LookupSinkInstance(DWORD dwVirtualServerId, REFIID iidBinding) { PLIST_ENTRY pCurrentListEntry; CNtfsStoreDriver * pStoreInstance = NULL; //Initialize pCurrentListEntry = &sm_ListHead; //Look at the next entry to see if we are not at the end of the queue while(pCurrentListEntry->Flink != &sm_ListHead) { //Get the object pointed by the next entry pStoreInstance = CONTAINING_RECORD( pCurrentListEntry->Flink, CNtfsStoreDriver, m_InstLEntry); //If the entry has same virtual server id we are done //NK** : check binding too in MM3 timeframe if(dwVirtualServerId == pStoreInstance->m_dwInstance) { return (IUnknown *)(ISMTPStoreDriver *)pStoreInstance; } pCurrentListEntry = pCurrentListEntry->Flink; } return NULL; } static HRESULT InsertSinkInstance(PLIST_ENTRY pListEntry) { CNtfsStoreDriver::sm_cCurrentInstances++; //insert at the start of the list InsertHeadList(&sm_ListHead, pListEntry); return S_OK; } static HRESULT RemoveSinkInstance(IUnknown * pISinkInstance) { PLIST_ENTRY pCurrentListEntry; CNtfsStoreDriver * pStoreInstance = NULL; //Initialize pCurrentListEntry = &sm_ListHead; //Look at the next entry to see if we are not at the end of the queue while(pCurrentListEntry->Flink != &sm_ListHead) { //Get the object pointed by the next entry pStoreInstance = CONTAINING_RECORD( pCurrentListEntry->Flink, CNtfsStoreDriver, m_InstLEntry); //If the entry has same instance pointer we are done //check binding too in MM3 timeframe if(pISinkInstance == (IUnknown *)(ISMTPStoreDriver *)pStoreInstance) { RemoveEntryList(pCurrentListEntry->Flink); CNtfsStoreDriver::sm_cCurrentInstances--; pStoreInstance->m_InstLEntry.Flink = NULL; pStoreInstance->m_InstLEntry.Blink = NULL; return S_OK; } pCurrentListEntry = pCurrentListEntry->Flink; } return(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); } public: PerfObjectInstance *m_ppoi; static CEventLogWrapper *g_pEventLog; }; ///////////////////////////////////////////////////////////////////////////// // CNtfsStoreDriver class ATL_NO_VTABLE CNtfsEnumMessages : public IMailMsgEnumMessages, public CComObjectRootEx, public CComCoClass { public: CNtfsEnumMessages(); ~CNtfsEnumMessages(); HRESULT SetStoreDirectory( LPTSTR szStoreDirectory, BOOL fIsFAT ); HRESULT SetInfo( CNtfsStoreDriver *pDriver ) { _ASSERT(pDriver); m_pDriver = pDriver; pDriver->AddUsage(); return(S_OK); } /***************************************************************************/ // // Implementation of IUnknown // HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, void **ppvObject ); ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); // // IMailMsgEnumMessages // HRESULT STDMETHODCALLTYPE Next( IMailMsgProperties *pMsg, IMailMsgPropertyStream **ppStream, PFIO_CONTEXT *phContentFile, IMailMsgNotify *pNotify ); DECLARE_REGISTRY_RESOURCEID(IDR_NTFSENUM) BEGIN_COM_MAP(CNtfsEnumMessages) COM_INTERFACE_ENTRY(IMailMsgEnumMessages) END_COM_MAP() private: CNtfsStoreDriver *m_pDriver; BOOL m_fIsFAT; TCHAR m_szEnumPath[MAX_PATH * 2]; TCHAR m_szStorePath[MAX_PATH * 2]; HANDLE m_hEnum; WIN32_FIND_DATA m_Data; // Reference count LONG m_ulRefCount; }; ///////////////////////////////////////////////////////////////////////////// // CNtfsPropertyStream class ATL_NO_VTABLE CNtfsPropertyStream : public IMailMsgPropertyStream, public CComObjectRootEx, public CComCoClass { public: CNtfsPropertyStream(); ~CNtfsPropertyStream(); // // guidInstance should be GUID_NULL when we are loading an existing // stream from disk, or an instance guid for the driver when we are // creating a new stream; // HRESULT SetHandle( HANDLE hStream, GUID guidInstance, BOOL fLiveStream, IMailMsgProperties *pMsg); HRESULT SetInfo( CNtfsStoreDriver *pDriver ) { _ASSERT(pDriver); m_pDriver = pDriver; pDriver->AddUsage(); IncCtr((pDriver->m_ppoi), NTFSDRV_MSG_STREAMS_OPEN); return(S_OK); } /***************************************************************************/ // // Implementation of IUnknown // HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, void **ppvObject ); ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); // // IMailMsgPropertyStream // HRESULT STDMETHODCALLTYPE GetSize( IMailMsgProperties *pMsg, DWORD *pdwSize, IMailMsgNotify *pNotify ); HRESULT STDMETHODCALLTYPE ReadBlocks( IMailMsgProperties *pMsg, DWORD dwCount, DWORD *pdwOffset, DWORD *pdwLength, BYTE **ppbBlock, IMailMsgNotify *pNotify ); HRESULT STDMETHODCALLTYPE StartWriteBlocks( IMailMsgProperties *pMsg, DWORD cBlocks, DWORD cBytes); HRESULT STDMETHODCALLTYPE EndWriteBlocks( IMailMsgProperties *pMsg); HRESULT STDMETHODCALLTYPE CancelWriteBlocks( IMailMsgProperties *pMsg); HRESULT STDMETHODCALLTYPE WriteBlocks( IMailMsgProperties *pMsg, DWORD dwCount, DWORD *pdwOffset, DWORD *pdwLength, BYTE **ppbBlock, IMailMsgNotify *pNotify ); DECLARE_REGISTRY_RESOURCEID(IDR_NTFSSTM) BEGIN_COM_MAP(CNtfsPropertyStream) COM_INTERFACE_ENTRY(IMailMsgPropertyStream) END_COM_MAP() GUID GetInstanceGuid() { return m_guidInstance; } private: HANDLE m_hStream; CNtfsStoreDriver *m_pDriver; // how many times have we seen EndWriteBlocks? (and thus a full commit) BOOL m_cCommits; // Reference count LONG m_ulRefCount; // do we have header information? BOOL m_fStreamHasHeader; // is the stream being used for validation? BOOL m_fValidation; // the instance GUID under which this was created GUID m_guidInstance; // the hresult that we returned from StartWriteBlocks. if we failed // then we also fail writeblocks HRESULT m_hrStartWriteBlocks; }; #define DECLARE_STD_IUNKNOWN_METHODS(ClassRoot, Interface) \ HRESULT STDMETHODCALLTYPE C##ClassRoot::QueryInterface( \ REFIID iid, \ void **ppvObject \ ) \ { \ if (iid == IID_IUnknown) \ *ppvObject = (IUnknown *)(##Interface *)this; \ else if (iid == IID_##Interface) \ *ppvObject = (##Interface *)this; \ else \ return(E_NOINTERFACE); \ AddRef(); \ return(S_OK); \ } \ ULONG STDMETHODCALLTYPE C##ClassRoot::AddRef() \ { \ return(InterlockedIncrement(&m_ulRefCount)); \ } \ ULONG STDMETHODCALLTYPE C##ClassRoot::Release() \ { \ LONG lRefCount = InterlockedDecrement(&m_ulRefCount);\ if (lRefCount == 0) \ delete this; \ return(lRefCount); \ } #endif //__NTFS_H_