|
|
//+--------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: rpubdf.cxx
//
// Contents: CRootPubDocFile implementation
//
// History: 26-Aug-92 DrewB Created
//
//---------------------------------------------------------------
#include <dfhead.cxx>
#pragma hdrstop
#include <header.hxx>
#include <rpubdf.hxx>
#include <lock.hxx>
#include <filelkb.hxx>
// Priority mode lock permissions
#define PRIORITY_PERMS DF_READ
//+--------------------------------------------------------------
//
// Member: CRootPubDocFile::CRootPubDocFile, public
//
// Synopsis: Ctor - Initializes empty object
//
// History: 30-Mar-92 DrewB Created
// 05-Sep-5 MikeHill Init _timeModifyAtCommit.
//
//
//---------------------------------------------------------------
CRootPubDocFile::CRootPubDocFile(IMalloc * const pMalloc) : _pMalloc(pMalloc), CPubDocFile(NULL, NULL, 0, ROOT_LUID, NULL, NULL, 0, NULL) { olDebugOut((DEB_ITRACE, "In CRootPubDocFile::CRootPubDocFile()\n"));
_ulPriLock = 0; // Default to an invalid value.
_timeModifyAtCommit.dwLowDateTime = _timeModifyAtCommit.dwHighDateTime = (DWORD) -1L; _sig = CROOTPUBDOCFILE_SIG;
olDebugOut((DEB_ITRACE, "Out CRootPubDocFile::CRootPubDocFile\n")); }
//+--------------------------------------------------------------
//
// Member: CRootPubDocFile::InitInd, private
//
// Synopsis: Initializes independent root
//
// Arguments: [plstBase] - Base
// [snbExclude] - Limited instantiation exclusions
// [dwStartFlags] - Startup flags
// [df] - Transactioning flags
//
// Returns: Appropriate status code
//
// History: 11-Jun-92 DrewB Created
//
//---------------------------------------------------------------
SCODE CRootPubDocFile::InitInd(ILockBytes *plstBase, SNBW snbExclude, DWORD const dwStartFlags, DFLAGS const df) { CFileStream *pfstCopy; ILockBytes *plkbCopy; ULONG ulLock = 0; CDocFile *pdfFrom, *pdfTo; SCODE sc; CMStream *pms;
olDebugOut((DEB_ITRACE, "In CRootPubDocFile::InitInd()\n"));
if ((sc = DllGetCommitSig(plstBase, &_sigMSF)) == STG_E_INVALIDHEADER || sc == STG_E_UNKNOWN) { _sigMSF = DF_INVALIDSIGNATURE; } else if (FAILED(sc)) { olErr(EH_Err,sc); }
olMem(pfstCopy = new (_pMalloc) CFileStream(_pMalloc));
olChkTo(EH_pfstCopy, pfstCopy->InitGlobal( RSF_CREATE | RSF_DELETEONRELEASE | RSF_SNAPSHOT | (dwStartFlags & RSF_ENCRYPTED), DF_READWRITE)); olChkTo(EH_pfstCopy, pfstCopy->InitSnapShot());
if (!P_PRIORITY(df) && (_pdfb->GetOrigLockFlags() & LOCK_ONLYONCE)) olChkTo(EH_pfstCopyInit, WaitForAccess(plstBase, DF_READ, &ulLock)); if (snbExclude) { plkbCopy = pfstCopy; olChkTo(EH_GetAccess, DllMultiStreamFromStream(_pMalloc, &pms, &plstBase, dwStartFlags, df)); olMemTo(EH_pmsFrom, pdfFrom = new (_pMalloc) CDocFile(pms, SIDROOT, ROOT_LUID, BP_TO_P(CDFBasis *, _pdfb))); pdfFrom->AddRef(); olChkTo(EH_pdfFrom, DllMultiStreamFromStream(_pMalloc, &pms, &plkbCopy, RSF_CREATE, 0)); olMemTo(EH_pmsTo, pdfTo = new (_pMalloc) CDocFile(pms, SIDROOT, ROOT_LUID, BP_TO_P(CDFBasis *, _pdfb))); pdfTo->AddRef(); olChkTo(EH_pdfTo, pdfFrom->CopyTo(pdfTo, CDF_EXACT, snbExclude)); olChkTo(EH_pdfTo, pms->Flush(0));
pdfFrom->Release(); pdfTo->Release(); } else if ((dwStartFlags & RSF_TRUNCATE) == 0) { olChkTo(EH_GetAccess, CopyLStreamToLStream(plstBase, pfstCopy)); } if (!P_PRIORITY(df) && ulLock != 0) ReleaseAccess(plstBase, DF_READ, ulLock);
_pdfb->SetBase(pfstCopy); _pdfb->SetOriginal(plstBase); olDebugOut((DEB_ITRACE, "Out CRootPubDocFile::InitInd\n")); return S_OK;
EH_pdfTo: pdfTo->Release(); goto EH_pdfFrom; EH_pmsTo: DllReleaseMultiStream(pms); EH_pdfFrom: pdfFrom->Release(); goto EH_GetAccess; EH_pmsFrom: DllReleaseMultiStream(pms); EH_GetAccess: if (!P_PRIORITY(df) && ulLock != 0) ReleaseAccess(plstBase, DF_READ, ulLock); EH_pfstCopyInit: EH_pfstCopy: olVerSucc(pfstCopy->Release()); EH_Err: return sc; }
//+--------------------------------------------------------------
//
// Member: CRootPubDocFile::InitNotInd, private
//
// Synopsis: Dependent root initialization
//
// Arguments: [plstBase] - Base
// [snbExclude] - Limited instantiation exclusions
// [dwStartFlags] - Startup flags
//
// Returns: Appropriate status code
//
// History: 11-Jun-92 DrewB Created
//
//---------------------------------------------------------------
SCODE CRootPubDocFile::InitNotInd(ILockBytes *plstBase, SNBW snbExclude, DWORD const dwStartFlags, DFLAGS const df) { CDocFile *pdf; SCODE sc; CMStream *pms;
olDebugOut((DEB_ITRACE, "In CRootPubDocFile::InitNotInd()\n"));
if (snbExclude) { olChk(DllMultiStreamFromStream(_pMalloc, &pms, &plstBase, dwStartFlags, df)); olMemTo(EH_pms, pdf = new(_pMalloc) CDocFile(pms, SIDROOT, ROOT_LUID, BP_TO_P(CDFBasis *, _pdfb))); pdf->AddRef(); olChkTo(EH_pdf, PDocFile::ExcludeEntries(pdf, snbExclude)); olChkTo(EH_pdf, pms->Flush(0)); pdf->Release(); } _pdfb->SetBase(plstBase); plstBase->AddRef(); _pdfb->SetOriginal(plstBase); olDebugOut((DEB_ITRACE, "Out CRootPubDocFile::InitNotInd\n")); return S_OK;
EH_pdf: //pdf->Release() will also release the multistream.
pdf->Release(); return sc; EH_pms: DllReleaseMultiStream(pms); EH_Err: return sc; }
//+--------------------------------------------------------------
//
// Member: CRootPubDocFile::InitRoot, public
//
// Synopsis: Constructor
//
// Arguments: [plstBase] - Base LStream
// [dwStartFlags] - How to start things
// [df] - Transactioning flags
// [snbExclude] - Parital instantiation list
// [ppdfb] - Basis pointer return
// [pulOpenLock] - Open lock index return
//
// Returns: Appropriate status code
//
// Modifies: [ppdfb]
// [pulOpenLock]
//
// History: 09-Dec-91 DrewB Created
// 09-Jun-92 PhilipLa Added conversion support
// 05-Sep-95 MikeHill Initialize _timeModifyAtCommit.
// Removed duplicate call to pdfWrapped->CopyTimesFrom
//
//---------------------------------------------------------------
SCODE CRootPubDocFile::InitRoot(ILockBytes *plstBase, DWORD dwStartFlags, DFLAGS const df, SNBW snbExclude, CDFBasis **ppdfb, ULONG *pulOpenLock, CGlobalContext *pgc) { CWrappedDocFile *pdfWrapped; CDocFile *pdfBase; CFileStream *pfstScratch; CMStream *pmsScratch; SCODE sc, scConv = S_OK; STATSTG statstg;
olDebugOut((DEB_ITRACE, "In CRootPubDocFile::InitRoot(" "%p, %lX, %lX, %p, %p)\n", plstBase, dwStartFlags, df, snbExclude, ppdfb));
// Exclusion only works with a plain open
olAssert(snbExclude == NULL || (dwStartFlags & (RSF_CREATEFLAGS | RSF_CONVERT)) == 0);
// ILockBytes::Stat calls are very expensive; we avoid one here
// if possible
HRESULT hr; IFileLockBytes *pfl; if (SUCCEEDED(plstBase->QueryInterface(IID_IFileLockBytes, (void**) &pfl))) { // This is our private ILockBytes implementation.
hr = pfl->GetLocksSupported(&statstg.grfLocksSupported); if (pfl->IsEncryptedFile()) dwStartFlags |= RSF_ENCRYPTED; pfl->Release(); } else hr = plstBase->Stat(&statstg, STATFLAG_NONAME);
olHChk(hr);
*pulOpenLock = 0; if (statstg.grfLocksSupported & LOCK_ONLYONCE) olChk(GetOpen(plstBase, df, TRUE, pulOpenLock)); if (P_PRIORITY(df) && (statstg.grfLocksSupported & LOCK_ONLYONCE)) olChkTo(EH_GetOpen, GetAccess(plstBase, PRIORITY_PERMS, &_ulPriLock));
olMemTo(EH_GetPriority, *ppdfb = new (_pMalloc) CDFBasis(_pMalloc, df, statstg.grfLocksSupported, pgc)); _pdfb = P_TO_BP(CBasedDFBasisPtr, *ppdfb);
if (P_INDEPENDENT(df)) olChkTo(EH_GetPriority, InitInd(plstBase, snbExclude, dwStartFlags, df)); else olChkTo(EH_GetPriority, InitNotInd(plstBase, snbExclude, dwStartFlags, df));
olMemTo(EH_SubInit, pfstScratch = new (_pMalloc) CFileStream(_pMalloc)); olChkTo(EH_pfstScratchInit, pfstScratch->InitGlobal( RSF_CREATE | RSF_DELETEONRELEASE | RSF_SCRATCH | (dwStartFlags & RSF_ENCRYPTED), DF_READWRITE)); _pdfb->SetDirty(pfstScratch);
CMStream *pms; scConv = DllMultiStreamFromStream(_pMalloc, &pms, _pdfb->GetPBase(), dwStartFlags | ((!P_INDEPENDENT(df) && P_TRANSACTED(df)) ? RSF_DELAY : 0), df); _pmsBase = P_TO_BP(CBasedMStreamPtr, pms);
if (scConv == STG_E_INVALIDHEADER) scConv = STG_E_FILEALREADYEXISTS; olChkTo(EH_pfstScratchInit, scConv);
if (P_NOSNAPSHOT(df)) { if ((sc = DllGetCommitSig(plstBase, &_sigMSF)) == STG_E_INVALIDHEADER || sc == STG_E_UNKNOWN) { _sigMSF = DF_INVALIDSIGNATURE; } else if (FAILED(sc)) { olErr(EH_pmsBase,sc); } }
olMemTo(EH_pmsBase, pdfBase = new (_pMalloc) CDocFile(pms, SIDROOT, ROOT_LUID, BP_TO_P(CDFBasis *, _pdfb)));
pdfBase->AddRef();
if (P_TRANSACTED(df)) { _cTransactedDepth = 1; CDfName dfnNull; // auto-initialized to 0
WCHAR wcZero = 0; dfnNull.Set(2, (BYTE*)&wcZero);
// 3/11/93 - Demand scratch when opening/creating transacted
olChkTo(EH_pdfBaseInit, _pdfb->GetDirty()->InitScratch());
olMemTo(EH_pdfBaseInit, pdfWrapped = new(_pMalloc) CWrappedDocFile(&dfnNull, pdfBase->GetLuid(), df, BP_TO_P(CDFBasis *, _pdfb), this)); olChkTo(EH_pdfWrapped, pdfWrapped->Init(pdfBase)); AddXSMember(NULL, pdfWrapped, pdfWrapped->GetLuid()); _pdf = P_TO_BP(CBasedDocFilePtr, (PDocFile *)pdfWrapped);
} else _pdf = P_TO_BP(CBasedDocFilePtr, (PDocFile *)pdfBase);
// For no-scratch transacted files, also save the Docfile's current modify
// time. This will be used on the Release (in vdtor).
if( P_NOSCRATCH( df )) { if( FAILED( _pmsBase->GetTime( SIDROOT, WT_MODIFICATION, &_timeModifyAtCommit ))) { // Do not return an error, but record an error flag so that
// vdtor will not try to use it.
_timeModifyAtCommit.dwLowDateTime = _timeModifyAtCommit.dwHighDateTime = (DWORD) -1; } }
olChkTo(EH_pfstScratchInit, DllGetScratchMultiStream(&pmsScratch, (df & DF_NOSCRATCH), (ILockBytes **)_pdfb->GetPDirty(), pms));
_pdfb->SetScratch(pmsScratch);
if (df & DF_NOSCRATCH) { _pdfb->SetBaseMultiStream(pms); olChkTo(EH_pfstScratchInit, pmsScratch->InitScratch(pms, TRUE)); _pmsBase->SetScratchMS(pmsScratch); } else { _pdfb->SetBaseMultiStream(NULL); }
_df = df;
// _pdfb->mxs is constructed automatically
olDebugOut((DEB_ITRACE, "Out CRootPubDocFile::InitRoot\n")); return scConv;
EH_pdfWrapped: delete pdfWrapped; EH_pdfBaseInit: pdfBase->Release(); goto EH_pfstScratchInit;
EH_pmsBase: DllReleaseMultiStream(BP_TO_P(CMStream *, _pmsBase));
EH_pfstScratchInit: olVerSucc(pfstScratch->Release()); _pdfb->SetDirty(NULL); EH_SubInit: olVerSucc(_pdfb->GetBase()->Release()); _pdfb->SetBase(NULL); EH_GetPriority: if (_ulPriLock > 0) { olAssert(P_PRIORITY(df) && (statstg.grfLocksSupported & LOCK_ONLYONCE)); ReleaseAccess(plstBase, PRIORITY_PERMS, _ulPriLock); _ulPriLock = 0; } EH_GetOpen: if (*pulOpenLock != 0) { olAssert(statstg.grfLocksSupported & LOCK_ONLYONCE); ReleaseOpen(plstBase, df, *pulOpenLock); *pulOpenLock = 0; } EH_Err: return sc; }
//+--------------------------------------------------------------
//
// Member: CRootPubDocFile::~CRootPubDocFile, public
//
// Synopsis: dtor
//
// History: 09-Dec-91 DrewB Created
// 05-Sep-95 MikeHill Revert time using _timeModifyAtCommit.
//
//---------------------------------------------------------------
void CRootPubDocFile::vdtor(void) { olDebugOut((DEB_ITRACE, "In CRootPubDocFile::~CRootPubDocFile\n"));
olAssert(_cReferences == 0);
// If this is a no-scratch transacted file, revert the Modify timestamp
// on the Docfile to that of the last commit.
if( P_NOSCRATCH( _df ) && ( _timeModifyAtCommit.dwLowDateTime != -1L ) // Don't use an invalid timestamp.
) { // We call SetFileLockBytesTime, rather than SetTime, so that
// the underlying Docfile's timestamp is changed, but the Storage's
// timestamp in the Directory is unchanged. If we changed the
// Directory, we would have to flush the Multi-Stream.
// An error here is ignored.
_pmsBase->SetFileLockBytesTime( WT_MODIFICATION, _timeModifyAtCommit ); }
// We can't rely on CPubDocFile::~CPubDocFile to do this since
// we're using a virtual destructor
_sig = CROOTPUBDOCFILE_SIGDEL;
if (SUCCEEDED(CheckReverted())) { ChangeXs(DF_NOLUID, XSO_RELEASE); _cilChildren.DeleteByName(NULL); if (_ulPriLock > 0) { // Priority instantiation can't be independent
olAssert(!P_INDEPENDENT(_df)); ReleaseAccess(_pdfb->GetBase(), PRIORITY_PERMS, _ulPriLock); }
if (_pdf) _pdf->Release(); if (_pdfb) _pdfb->vRelease();
} olDebugOut((DEB_ITRACE, "Out CRootPubDocFile::~CRootPubDocFile\n")); delete this; }
//+---------------------------------------------------------------------------
//
// Member: CRootPubDocFile::ReleaseLocks, public
//
// Synopsis: Release any locks using the given ILockBytes
//
// Arguments: [plkb] -- ILockBytes to use for release
//
// Returns: void
//
// History: 24-Jan-95 PhilipLa Created
//
// Notes: This is a cleanup function used to resolve the many
// conflicts we get trying to release locks using an
// ILockBytes in a basis that's already been released.
//
//----------------------------------------------------------------------------
void CRootPubDocFile::ReleaseLocks(ILockBytes *plkb) { olDebugOut((DEB_ITRACE, "In CRootPubDocFile::ReleaseLocks:%p()\n", this)); if (_ulPriLock > 0) { // Priority instantiation can't be independent
olAssert(!P_INDEPENDENT(_df)); ReleaseAccess(plkb, PRIORITY_PERMS, _ulPriLock); _ulPriLock = 0; }
olDebugOut((DEB_ITRACE, "Out CRootPubDocFile::ReleaseLocks\n")); }
//+--------------------------------------------------------------
//
// Member: CRootPubDocFile::Stat, public
//
// Synopsis: Fills in a stat buffer from the base LStream
//
// Arguments: [pstatstg] - Stat buffer
// [grfStatFlag] - Stat flags
//
// Returns: Appropriate status code
//
// Modifies: [pstatstg]
//
// History: 25-Mar-92 DrewB Created
//
//---------------------------------------------------------------
SCODE CRootPubDocFile::Stat(STATSTGW *pstatstg, DWORD grfStatFlag) { SCODE sc;
olDebugOut((DEB_ITRACE, "In CRootPubDocFile::Stat(%p, %lu)\n", pstatstg, grfStatFlag)); olChk(CheckReverted()); olHChk(_pdfb->GetOriginal()->Stat((STATSTG *)pstatstg, grfStatFlag)); pstatstg->grfMode = DFlagsToMode(_df); olChkTo(EH_pwcsName, _pdf->GetClass(&pstatstg->clsid)); olChkTo(EH_pwcsName, _pdf->GetStateBits(&pstatstg->grfStateBits)); olDebugOut((DEB_ITRACE, "Out CRootPubDocFile::Stat\n")); return S_OK;
EH_pwcsName: if (pstatstg->pwcsName) TaskMemFree(pstatstg->pwcsName); EH_Err: return sc; }
//+---------------------------------------------------------------------------
//
// Member: CRootPubDocFile::SwitchToFile, public
//
// Synopsis: Switches the underlying file in the base ILockBytes
//
// Arguments: [ptcsFile] - Filename
// [plkb] - The ILockBytes to operate on
// [pulOpenLock] - On entry, the current open lock
// On exit, the new open lock
//
// Returns: Appropriate status code
//
// Modifies: [pulOpenLock]
//
// History: 08-Jan-93 DrewB Created
//
//----------------------------------------------------------------------------
SCODE CRootPubDocFile::SwitchToFile(OLECHAR const *ptcsFile, ILockBytes *plkb, ULONG *pulOpenLock) { IFileLockBytes *pfl; SCODE sc; BYTE *pbBuffer; ULONG cbBuffer;
olDebugOut((DEB_ITRACE, "In CRootPubDocFile::SwitchToFile:%p(" "%s, %p, %p)\n", this, ptcsFile, plkb, pulOpenLock));
// If you're transacted, nothing can be dirty in the base
// If you're not dirty, there's no point in flushing
// This is also necessary to allow SwitchToFile with a read-only source
if (!P_TRANSACTED(_df) && IsDirty()) { // Make sure pending changes are flushed
olChk(_pmsBase->Flush(0));
// Make sure ILockBytes contents are on disk
olHChk(plkb->Flush()); }
#ifdef LARGE_DOCFILE
ULONGLONG ulCommitSize; #else
ULONG ulCommitSize; #endif
olChk(GetCommitSize(&ulCommitSize));
// Check for FileLockBytes
olHChkTo(EH_NotFile, plkb->QueryInterface(IID_IFileLockBytes, (void **)&pfl));
// Release old locks
if (*pulOpenLock) ReleaseOpen(plkb, _df, *pulOpenLock);
// Ask ILockBytes to switch
GetSafeBuffer(CB_SMALLBUFFER, CB_LARGEBUFFER, &pbBuffer, &cbBuffer); olAssert(pbBuffer != NULL); sc = DfGetScode(pfl->SwitchToFile( ptcsFile, ulCommitSize, cbBuffer, pbBuffer));
pfl->Release(); FreeBuffer(pbBuffer);
//Record the fact that we have enough space for overwrite commit.
_wFlags = _wFlags | PF_PREPARED;
// Attempt to get new locks
// If SwitchToFile failed, the ILockBytes is the same so this will
// restore our open locks released above
// If SwitchToFile succeeded, the ILockBytes is working on the new file
// so this will get locks for that
if (*pulOpenLock) { ULONG ulLock;
// Don't propagate failures here since there's nothing
// that can be done
if (SUCCEEDED(GetOpen(plkb, _df, FALSE, &ulLock))) *pulOpenLock = ulLock; }
olDebugOut((DEB_ITRACE, "Out CRootPubDocFile::SwitchToFile\n")); EH_Err: return sc;
EH_NotFile: return(STG_E_NOTFILEBASEDSTORAGE); }
//+--------------------------------------------------------------
//
// Member: CRootPubDocFile::Commit, public
//
// Synopsis: Commits transacted changes
//
// Arguments: [dwFlags] - DFC_*
//
// Returns: Appropriate status code
//
// History: 29-Aug-95 MikeHill Created
// 26-Apr-99 RogerCh Changed to use GetSystemTimeAsFileTime
//
//---------------------------------------------------------------
void CRootPubDocFile::CommitTimestamps(DWORD const dwFlags) { // For no-scratch transacted files, also save the Docfile's modify
// time. This will be used to restore the file's current time on a Release.
if( P_NOSCRATCH( _df ) && P_TRANSACTED( _df )) { GetSystemTimeAsFileTime(&_timeModifyAtCommit); } }
|