#pragma once //+============================================================================ // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1994 - 1998. // // File: hntfsstg.hxx // // This file provides the NFF (NTFS Flat File) IStream implementation. // // History: // //+============================================================================ #include "reserved.hxx" #include "nffmstm.hxx" // // NTFS Stream and NTFS Storage are debugged together under the same // infolevel and debug sub-system. The Stream header is included first // DECLARE_DEBUG(nff); #ifdef DEB_INFO #undef DEB_INFO #endif #define DEB_INFO DEB_USER1 #define DEB_REFCOUNT DEB_USER2 #define DEB_READ DEB_USER3 #define DEB_WRITE DEB_USER4 #define DEB_OPENS DEB_USER5 #define DEB_STATCTRL DEB_USER6 #define DEB_OPLOCK DEB_USER7 #if DBG == 1 #define nffAssert(e) Win4Assert(e) #define nffVerify(e) Win4Assert(e) #define nffDebug(x) nffInlineDebugOut x #define nffXTrace(x) nffCDbgTrace dbg_( DEB_TRACE, x ) #define nffITrace(x) nffCDbgTrace dbg_( DEB_ITRACE, x ) // nffDebugOut is called from the Chk/Err macros #define nffDebugOut(x) nffInlineDebugOut x #else #define nffAssert(e) #define nffVerify(e) (void)(e) #define nffDebug(x) #define nffXTrace(x) #define nffITrace(x) #endif #define nffErr(l, e) ErrJmp(nff, l, e, sc) #define nffChkTo(l, e) if (FAILED(sc = (e))) nffErr(l, sc) else 1 #define nffChk(e) nffChkTo(EH_Err, e) #define nffHChkTo(l, e) if (FAILED(sc = DfGetScode(e))) nffErr(l, sc) else 1 #define nffHChk(e) nffHChkTo(EH_Err, e) #define nffMemTo(l, e) \ if ((e) == NULL) nffErr(l, STG_E_INSUFFICIENTMEMORY) else 1 #define nffMem(e) nffMemTo(EH_Err, e) #define nffBoolTo(l, e) if (!(e)) nffErr(l, LAST_STG_SCODE) else 1 #define nffBool(e) nffBoolTo(EH_Err, e) #define NFF_VALIDATE(x) EXP_VALIDATE(nff, x) #define NTFSSTREAM_SIG LONGSIG('N','T','S','T') #define NTFSSTREAM_SIGDEL LONGSIG('N','T','S','t') //////////////////////////////////////////////////////////////// // IStream for an NTFS file stream. Hungarian Prefix "nffstm" // class CNtfsStream : public IStream, public ILockBytes // For use in e.g. StgCreateStorageOnILockBytes #if DBG , public IStorageTest #endif { friend class CNtfsStorage; friend class CNFFMappedStream; // ------------ // Construction // ------------ public: CNtfsStream( CNtfsStorage *pnffstg, IBlockingLock *pBlockingLock ); virtual ~CNtfsStream(); virtual HRESULT Init( HANDLE hFile, DWORD grfMode, const OLECHAR *pwcsName, CNtfsStream *pnffstm ); // -------- // IUnknown // -------- public: STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // ------- // IStream // ------- public: HRESULT STDMETHODCALLTYPE Read( /* [length_is][size_is][out] */ void __RPC_FAR *pv, /* [in] */ ULONG cb, /* [out] */ ULONG __RPC_FAR *pcbRead); HRESULT STDMETHODCALLTYPE Write( /* [size_is][in] */ const void __RPC_FAR *pv, /* [in] */ ULONG cb, /* [out] */ ULONG __RPC_FAR *pcbWritten); HRESULT STDMETHODCALLTYPE Seek( /* [in] */ LARGE_INTEGER dlibMove, /* [in] */ DWORD dwOrigin, /* [out] */ ULARGE_INTEGER __RPC_FAR *plibNewPosition); HRESULT STDMETHODCALLTYPE SetSize( /* [in] */ ULARGE_INTEGER libNewSize); HRESULT STDMETHODCALLTYPE CopyTo( /* [unique][in] */ IStream __RPC_FAR *pstm, /* [in] */ ULARGE_INTEGER cb, /* [out] */ ULARGE_INTEGER __RPC_FAR *pcbRead, /* [out] */ ULARGE_INTEGER __RPC_FAR *pcbWritten); HRESULT STDMETHODCALLTYPE Commit( /* [in] */ DWORD grfCommitFlags); HRESULT STDMETHODCALLTYPE Revert(void); HRESULT STDMETHODCALLTYPE LockRegion( /* [in] */ ULARGE_INTEGER libOffset, /* [in] */ ULARGE_INTEGER cb, /* [in] */ DWORD dwLockType); HRESULT STDMETHODCALLTYPE UnlockRegion( /* [in] */ ULARGE_INTEGER libOffset, /* [in] */ ULARGE_INTEGER cb, /* [in] */ DWORD dwLockType); HRESULT STDMETHODCALLTYPE Stat( /* [out] */ STATSTG __RPC_FAR *pstatstg, /* [in] */ DWORD grfStatFlag); HRESULT STDMETHODCALLTYPE Clone( /* [out] */ IStream __RPC_FAR *__RPC_FAR *ppstm); // ---------- // ILockBytes // ---------- public: HRESULT STDMETHODCALLTYPE ReadAt( /* [in] */ ULARGE_INTEGER ulOffset, /* [length_is][size_is][out] */ void __RPC_FAR *pv, /* [in] */ ULONG cb, /* [out] */ ULONG __RPC_FAR *pcbRead); HRESULT STDMETHODCALLTYPE WriteAt( /* [in] */ ULARGE_INTEGER ulOffset, /* [size_is][in] */ const void __RPC_FAR *pv, /* [in] */ ULONG cb, /* [out] */ ULONG __RPC_FAR *pcbWritten); HRESULT STDMETHODCALLTYPE Flush(void); public: inline BOOL IsWriteable(); HRESULT CheckReverted(); // ------------ // IStorageTest // ------------ public: #if DBG STDMETHOD(UseNTFS4Streams)( BOOL fUseNTFS4Streams ); STDMETHOD(GetFormatVersion)(WORD *pw); STDMETHOD(SimulateLowMemory)( BOOL fSimulate ); STDMETHOD(GetLockCount)(); STDMETHOD(IsDirty)(); #endif // ---------------- // Internal Methods // ---------------- protected: virtual HRESULT ShutDown(); void InsertSelfIntoList(CNtfsStream * pnffstmList); void RemoveSelfFromList(); HRESULT Delete(); private: HRESULT SetFileSize( const CULargeInteger &uliNewSize ); HRESULT Rename( const WCHAR *pwcsName, BOOL fOverWrite ); inline HRESULT Lock( DWORD dwTimeout ); inline HRESULT Unlock(); static HRESULT DeleteStream( HANDLE *phStream ); HRESULT SyncReadAtFile( ULARGE_INTEGER ulOffset, PVOID pv, ULONG cb, PULONG pcbRead ); HRESULT SyncWriteAtFile( ULARGE_INTEGER ulOffset, const void *pv, ULONG cb, PULONG pcbWritten ); HANDLE GetFileHandle(); // Used by friend CNtfsStorage. HRESULT MarkStreamAux( const MARK_HANDLE_INFO& mhi ); static HRESULT MarkFileHandleAux( HANDLE hFile, const MARK_HANDLE_INFO& mhi ); HRESULT SetStreamTime( const FILETIME*, const FILETIME*, const FILETIME* ); static HRESULT SetFileHandleTime( HANDLE hFile, const FILETIME*, const FILETIME*, const FILETIME* ); const WCHAR* GetName() const; // -------------- // Internal State // -------------- private: WCHAR * _pwcsName; CNFFMappedStream _nffMappedStream; DWORD _grfMode; // The mode used to open the IStream HANDLE _hFile; // File represented by this stream IBlockingLock * _pBlockingLock; // The lock to use for mutual exclusion // This is assumed to lock the whole storage // (the open stream list code requires this) ULONG _sig; // Class signature LONG _cRefs; // Reference count CNtfsStorage * _pnffstg; // Not ref-counted, NULL-ed in ShutDown // This class maintains its own copy of the seek pointer, different from // the underlying file's. This is necessary so that the IStream methods mantain // a consistent seek location, even when methods on e.g. IMappedStream are called. CLargeInteger _liCurrentSeekPosition; CNtfsStream * _pnffstmPrev; // links for the list of open streams. CNtfsStream * _pnffstmNext; OVERLAPPED _ovlp; // structure used for Async IO. }; // class CNtfsStream inline HANDLE CNtfsStream::GetFileHandle() { return _hFile; } inline HRESULT CNtfsStream::CheckReverted() { if(INVALID_HANDLE_VALUE == _hFile) return STG_E_REVERTED; return S_OK; } inline const WCHAR* CNtfsStream::GetName() const { return _pwcsName; } inline HRESULT CNtfsStream::Lock( DWORD dwTimeout ) { return( _pBlockingLock->Lock( dwTimeout )); } inline HRESULT CNtfsStream::Unlock() { return( _pBlockingLock->Unlock() ); } inline BOOL CNtfsStream::IsWriteable() { return( GrfModeIsWriteable( _grfMode )); } //+---------------------------------------------------------------------------- // // Class: CNtfsUpdateStreamForPropStg // // This class wraps the update stream handle, used by // CNFFMappedStream. See that class declaration for a description. // //+---------------------------------------------------------------------------- class CNtfsUpdateStreamForPropStg : public CNtfsStream { public: CNtfsUpdateStreamForPropStg( CNtfsStorage *pnffstg, IBlockingLock *_pBlockingLock ); ~CNtfsUpdateStreamForPropStg(); protected: virtual HRESULT ShutDown(); }; // class CNtfsStreamForPropStg inline CNtfsUpdateStreamForPropStg::CNtfsUpdateStreamForPropStg( CNtfsStorage *pnffstg, IBlockingLock *pBlockingLock ) : CNtfsStream( pnffstg, pBlockingLock ) { } inline CNtfsUpdateStreamForPropStg::~CNtfsUpdateStreamForPropStg() { // If the CNFFMappedStream was shutdown without flushing, and it couldn't // save and fix up the update stream, then there's nothing we can // do to recover and we should delete the stream. // In the normal path, CNFFMappedStream::~CNFFMappedStream calls // ReplaceOriginalWithUpdate(DONT_CREATE_NEW_UPDATE_STREAM), // and subsequently our handle is closed, and CheckReverted // returns STG_E_REVERTED. if( SUCCEEDED(CheckReverted()) ) Delete(); }