|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1998.
//
// File: cistore.cxx
//
// Contents: CI physical storage
//
// Classes: CiStorage
//
// History: 07-Jul-93 BartoszM Separated from physidx.cxx
// 20-Nov-98 KLam Moved IsVolumeWriteProtected to CDriveInfo
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <mmstrm.hxx>
#include <cidir.hxx>
#include <cistore.hxx>
#include <idxtab.hxx>
#include <circstob.hxx>
#include <fullpath.hxx>
#include <enumstr.hxx>
#include <pathpars.hxx>
#include <propbkp.hxx>
#include <ntopen.hxx>
#define CAT_TESTLOG_HDR L"\\CiTstLog.000"
#define CAT_TESTLOG_CP1 L"\\CiTstLog.001"
#define CAT_TESTLOG_CP2 L"\\CiTstLog.002"
#define CAT_IDXTABLE_HDR L"\\INDEX.000"
#define CAT_IDXTABLE_CP1 L"\\INDEX.001"
#define CAT_IDXTABLE_CP2 L"\\INDEX.002"
#define MMLOG_PREFIX L"\\CiML"
#define PROPSTORE_PREFIX L"\\CiPS"
#define PROPSTORE1_PREFIX L"\\CiP1"
#define PROPSTORE2_PREFIX L"\\CiP2"
#define PRI_CHANGELOG_PREFIX L"\\CiCL"
#define SEC_CHANGELOG_PREFIX L"\\CiSL"
#define FRESHLOG_PREFIX L"\\CiFL"
#define PIDTABLE_PREFIX L"\\CiPT"
#define SCOPELIST_PREFIX L"\\CiSP"
#define SECSTORE_PREFIX L"\\CiST"
#define VSCOPELIST_PREFIX L"\\CiVP"
// constant definitions moved here from cicat.cxx
const WCHAR CAT_FILEID_MAP_FILE[] = L"\\cicat.fid"; // File id map table
const WCHAR CAT_HASH_FILE[] = L"\\cicat.hsh"; // Strings table
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
SStorage::SStorage(PStorage * pObj ) : _pObj(pObj) { }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
SStorage::~SStorage() { delete _pObj; }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
PStorageObject::PStorageObject() { }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
inline CiStorageObject& CI_OBJ ( PStorageObject& obj ) { return( (CiStorageObject&)obj ); }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
CiStorageObject::CiStorageObject(WORKID objectId) : _objectId(objectId) { }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
CiStorageObject::~CiStorageObject() { }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
SStorageObject::SStorageObject ( PStorageObject* pObj ) : _pObj(pObj) { }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
SStorageObject::~SStorageObject() { delete _pObj; }
//+-------------------------------------------------------------------------
//
// Function: DoesVolumeSupportShrinkFromFront
//
// Synopsis: Checks if the volume supports SFF, like NTFS5
//
// Arguments: [pwcPath] -- Path to physical storage.
//
// Returns: TRUE if the file system supports sparse files
// FALSE otherwise
//
// History: 5-Nov-97 dlee Created
//
//--------------------------------------------------------------------------
BOOL DoesVolumeSupportShrinkFromFront( WCHAR const * pwcPath ) { SHandle xDir( CiNtOpen( pwcPath, FILE_READ_DATA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT ) );
BYTE aInfo[ sizeof FILE_FS_ATTRIBUTE_INFORMATION + MAX_PATH * sizeof WCHAR ];
FILE_FS_ATTRIBUTE_INFORMATION *pAttributeInfo = (FILE_FS_ATTRIBUTE_INFORMATION *) aInfo; IO_STATUS_BLOCK IoStatus;
NTSTATUS Status = NtQueryVolumeInformationFile( xDir.Get(), &IoStatus, pAttributeInfo, sizeof aInfo, FileFsAttributeInformation );
if ( FAILED( Status ) ) { ciDebugOut(( DEB_WARN, "can't get volume info %#x on '%ws'\n", Status, pwcPath )); THROW( CException( Status ) ); }
return 0 != ( FILE_SUPPORTS_SPARSE_FILES & pAttributeInfo->FileSystemAttributes ); } //DoesVolumeSupportShrinkFromFront
//+-------------------------------------------------------------------------
//
// Member: IsDirectoryWritable
//
// Synopsis: Checks if the directory is writable by trying to open
// file "cicat.hsh" for write
//
// Arguments: [pwcPath] -- Path to physical storage.
//
// Returns: TRUE if the directory is writable
// FALSE otherwise
//
// History: 17-Mar-98 KitmanH Created
// 10-Jun-98 KitmanH Changed to only retrive file
// attributes
//
// Note: Assume writable, if the file does not exist, caller needs
// to check if the volume is writable
//
//--------------------------------------------------------------------------
BOOL IsDirectoryWritable( WCHAR const * pwcPath ) { WCHAR wcsPath [ MAX_PATH ]; wcscpy(wcsPath, pwcPath ); wcscat(wcsPath, CAT_HASH_FILE );
ciDebugOut(( DEB_ITRACE, "wcsPath == %ws\n", wcsPath ));
DWORD dwFileAttribute = GetFileAttributes( wcsPath ); if ( 0xFFFFFFFF != dwFileAttribute) { Win4Assert( !(FILE_ATTRIBUTE_DIRECTORY & dwFileAttribute) ); ciDebugOut(( DEB_ITRACE, "dwFileAttribute is %#x\n", dwFileAttribute )); if ( dwFileAttribute & FILE_ATTRIBUTE_READONLY ) return FALSE; else return TRUE; } else return TRUE;
} //IsDirectoryWritable
//+-------------------------------------------------------------------------
//
// Member: CiStorage::CiStorage, public
//
// Effects: Saves path to physical storage.
//
// Arguments: [wcsPath] -- Path to physical storage.
// [adviseStatus] -- advise status object
// [cMegToLeaveOnDisk] -- number of megabytes to leave on disk
// [ulVer] -- version [default: CURRENT_VERSION_STAMP]
// [fReadOnly] -- is storage read-only [default: FALSE]
//
// History: 07-Mar-92 KyleP Created
// 16-Feb-98 KitmanH Added fReadOnly argument
// 20-Mar-98 KitmanH _fReadOnly is determined by both
// IsDirectoryWritable() and
// IsVolumeWriteProtected()
// 27-Oct-98 KLam Added disk space to leave
// 20-Nov-98 KLam Initialize _driveInfo
//
// Note: _fIsReadOnly value is set according whether the registry
// value "IsReadOnly" is set OR the volume is WriteProtected
// OR the directory is not writable
//--------------------------------------------------------------------------
CiStorage::CiStorage( WCHAR const * wcsPath, ICiCAdviseStatus & adviseStatus, ULONG cMegToLeaveOnDisk, ULONG ulVer, BOOL fReadOnly ) :_widFreshLog( widInvalid ), _adviseStatus( adviseStatus ), _fCorruptionReported(FALSE), _ulVer( ulVer ), _fSupportsShrinkFromFront( FALSE ), _fIsReadOnly( fReadOnly ), _fFavorReadAhead( FALSE ), // optimize for queries, not merges
_cMegToLeaveOnDisk ( cMegToLeaveOnDisk ), _driveInfo ( wcsPath, cMegToLeaveOnDisk ) { // The constructor is extended to take a version parameter
// to set the FSCI versioning apart from framework CI versioning.
// When the content framework version changes, all framework clients should reindex.
// However, if only the FSCI version changes, only FSCI should reindex.
// The default value for the property store is the content index version.
//
// ulVer defaults to the framework's version stamp, so when FSCI alone changes,
// others don't have to change (unless they are using a feature of FSCI.)
CIndexId iid( itFreshLog, partidFresh2 ); _widFreshLog = iid;
//
// Squirrel away the path.
//
_xPath.Set( new WCHAR [ wcslen( wcsPath ) + 1 ] ); wcscpy( _xPath.GetPointer(), wcsPath ); ciDebugOut(( DEB_ITRACE, "Content index physical storage: %ws\n", wcsPath ));
// Is the volume writable?
BOOL fAbsolutelyUnWritable = ( _driveInfo.IsWriteProtected() ) || !( IsDirectoryWritable( wcsPath ) ); ciDebugOut(( DEB_ITRACE, "CiStorage::CiStorage.. fAbsolutelyUnWritable == %d\n", fAbsolutelyUnWritable ));
_fIsReadOnly = fReadOnly || fAbsolutelyUnWritable;
//
// Determine whether this volume supports shrink from front (ntfs5)
//
_fSupportsShrinkFromFront = DoesVolumeSupportShrinkFromFront( wcsPath ); ciDebugOut(( DEB_ITRACE, "supports SFF: %d\n", _fSupportsShrinkFromFront )); } //CiStorage
//+-------------------------------------------------------------------------
//
// Member: CiStorage::~CiStorage, public
//
// Synopsis: Destroys physical storage.
//
// Effects: Has *no* effect on open indexes.
//
// History: 07-Mar-92 KyleP Created
//
//--------------------------------------------------------------------------
CiStorage::~CiStorage() { }
const WCHAR CiStorage::_aHexDigit[] = L"0123456789ABCDEF";
//+-------------------------------------------------------------------------
//
// Member: CiStorage::MakePath, private
//
// Synopsis: Creates an index, dir, hash or prop path.
//
// Arguments: [type] -- Index, dir, etc.
// [iid] -- Index ID.
// [wcsIndex] -- Output path
//
// History: 07-Mar-92 KyleP Created
// 28-Dec-95 KyleP Collapsed four routines into one
//
//--------------------------------------------------------------------------
void CiStorage::MakePath( CiStorage::EPathType type, WORKID iid, WCHAR * wcsIndex ) { //
// Construct a path for the new index.
//
wcscpy( wcsIndex, _xPath.GetPointer() ); int len = wcslen( wcsIndex ); wcsIndex[len++] = L'\\';
for ( int i = 7; i >= 0; i-- ) { wcsIndex[len++] = _aHexDigit[ (iid >> (4 * i)) & 0xF ]; }
wcsIndex[len] = 0;
Win4Assert( len < MAX_PATH );
switch ( type ) { case CiStorage::eIndexPath: wcscat( wcsIndex, L".ci" ); break;
case CiStorage::eHashPath: wcscat( wcsIndex, L".hsh" ); break;
case CiStorage::ePrimaryPropPath: wcscat( wcsIndex, L".ps1" ); break;
case CiStorage::eSecondaryPropPath: wcscat( wcsIndex, L".ps2" ); break;
case CiStorage::eDirPath: wcscat( wcsIndex, L".dir" ); break; }
ciDebugOut(( DEB_ITRACE, "Physical index name: %ws\n", wcsIndex )); }
PStorageObject* CiStorage::QueryObject( WORKID objectId ) { return new CiStorageObject(objectId); }
//+---------------------------------------------------------------------------
//
// Function: QueryIdxTableObject
//
// Synopsis: Returns an "Index Table" as a "Recoverable Storage Object"
//
// Returns: Pointer to a recoverable storage object allocated from the
// heap. It is the responsibiity of the caller to destroy the
// object.
//
// History: 2-25-94 srikants Created
// 27-Oct-98 KLam Pass cMegToLeaveOnDisk to CiRcovStorageObj
//
//----------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QueryIdxTableObject() { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
MakeLogPath( CAT_IDXTABLE_HDR, wcsHdr ); MakeLogPath( CAT_IDXTABLE_CP1, wcsCopy1 ); MakeLogPath( CAT_IDXTABLE_CP2, wcsCopy2 );
return new CiRcovStorageObj( *this, wcsHdr, wcsCopy1, wcsCopy2, _cMegToLeaveOnDisk, _fIsReadOnly); }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
PIndexTable* CiStorage::QueryIndexTable ( CTransaction& xact ) { return new CIndexTable ( *this, xact ); }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryNewIndexStream( PStorageObject& obj, BOOL isSparse ) { WCHAR wcsIndex [ MAX_PATH ]; MakePath( eIndexPath, CI_OBJ(obj).ObjectId(), wcsIndex ); XPtr<PMmStream> xStream;
//
// If it's a master index and the storage supports sparse streams, make
// the stream sparse.
//
BOOL fSparse = ( isSparse && _fSupportsShrinkFromFront );
ciDebugOut(( DEB_ITRACE, "opening new %s stream '%ws'\n", isSparse ? "master" : "shadow", wcsIndex ));
if ( fSparse ) { CLockingMmStream * pLockingMmStream = new CLockingMmStream( _cMegToLeaveOnDisk ); xStream.Set( pLockingMmStream );
pLockingMmStream->Open( wcsIndex, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, // File cannot already exist.
FILE_ATTRIBUTE_NORMAL, TRUE ); // sparse file
} else { CMmStream * pMmStream = new CMmStream( _cMegToLeaveOnDisk, _fIsReadOnly ); xStream.Set( pMmStream ); pMmStream->Open( wcsIndex, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, CREATE_NEW, // File cannot already exist.
FILE_ATTRIBUTE_NORMAL, FALSE ); // non-sparse file
}
return xStream.Acquire(); }
//+---------------------------------------------------------------------------
//
// Function: QueryExistingIndexStream
//
// Synopsis: Returns an "existing" index stream as a memory mapped
// stream.
//
// Arguments: [obj] -- The storage object associated with the main
// object containing the stream.
// [mode] -- The open mode: read/write
//
// History: 4-20-94 srikants Added fWrite parameter.
// 2-18-98 kitmanh Ignore fWrite for readOnly catalogs
//
// Notes: The fWrite parameter was used for supporting a restartable
// master merge for which an existing index stream must be
// opened for write access. Otherwise, all existing streams are
// normally opened for read access only.
//
//----------------------------------------------------------------------------
PMmStream* CiStorage::QueryExistingIndexStream ( PStorageObject& obj, PStorage::EOpenMode mode ) { WCHAR wcsIndex [ MAX_PATH ]; MakePath( eIndexPath, CI_OBJ(obj).ObjectId(), wcsIndex );
BOOL fWrite = _fIsReadOnly ? FALSE : (PStorage::eOpenForWrite == mode); DWORD dwAccess = fWrite ? (GENERIC_READ | GENERIC_WRITE) : (GENERIC_READ); ciDebugOut(( DEB_ITRACE, "opening existing %s stream '%ws'\n", fWrite ? "write" : "read", wcsIndex ));
XPtr<PMmStream> xStream;
if ( fWrite ) {
CLockingMmStream * pLockingMmStream = new CLockingMmStream( _cMegToLeaveOnDisk ); xStream.Set( pLockingMmStream );
pLockingMmStream->Open( wcsIndex, dwAccess, // Access flags
FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, // File must already exist.
FILE_ATTRIBUTE_NORMAL, fWrite && _fSupportsShrinkFromFront ); // sparse
} else { dwAccess = _fIsReadOnly ? GENERIC_READ : dwAccess;
CMmStream * pMmStream = new CMmStream( _cMegToLeaveOnDisk, _fIsReadOnly ); xStream.Set( pMmStream );
pMmStream->Open( wcsIndex, dwAccess, // Access flags
FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING, // File must already exist.
FILE_ATTRIBUTE_NORMAL, FALSE ); // sparse
}
return xStream.Acquire(); }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
PMmStream * CiStorage::DupExistingIndexStream( PStorageObject& obj, PMmStream & mmStream, EOpenMode mode ) { return new CDupStream( (CLockingMmStream &) mmStream ); }
//+-------------------------------------------------------------------------
//
// Method: CiStorage::QueryNewHashStream
//
// Synopsis: Creates hash stream
//
// Arguments: [obj] -- Object holding stream
//
// Returns: Stream
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryNewHashStream ( PStorageObject& obj ) { WCHAR wcsIndex [ MAX_PATH ]; MakePath( eHashPath, CI_OBJ(obj).ObjectId(), wcsIndex ); XPtr<CMmStream> xStream( new CMmStream( _cMegToLeaveOnDisk, _fIsReadOnly ) );
xStream->Open( wcsIndex, GENERIC_READ | GENERIC_WRITE, // Access flags
0, // Sharing flags
CREATE_NEW, // File cannot already exist.
FILE_ATTRIBUTE_NORMAL ); return xStream.Acquire(); }
//+-------------------------------------------------------------------------
//
// Method: CiStorage::QueryExistingHashStream
//
// Synopsis: Opens existing hash stream
//
// Arguments: [obj] -- Object holding stream
// [fWrite] -- Flag indicating if the stream must be opened
// for write access; set to TRUE during a restarted
// master merge.
//
// Returns: Stream
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryExistingHashStream ( PStorageObject& obj, PStorage::EOpenMode mode ) {
WCHAR wcsIndex [ MAX_PATH ]; MakePath( eHashPath, CI_OBJ(obj).ObjectId(), wcsIndex ); XPtr<CMmStream> xStream( new CMmStream( _cMegToLeaveOnDisk, _fIsReadOnly ) );
BOOL fWrite = PStorage::eOpenForWrite == mode; DWORD dwAccess = fWrite ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ;
xStream->Open( wcsIndex, dwAccess, // Access flags
FILE_SHARE_READ | FILE_SHARE_WRITE, // Sharing flags
OPEN_EXISTING ); // File must already exist.
return xStream.Acquire(); }
//+-------------------------------------------------------------------------
//
// Method: CiStorage::QueryNewPropStream
//
// Synopsis: Creates prop stream
//
// Arguments: [obj] -- Object holding stream
//
// Returns: Stream
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryNewPropStream ( PStorageObject& obj, DWORD dwStoreLevel ) { WCHAR wcsIndex [ MAX_PATH ];
Win4Assert(PRIMARY_STORE == dwStoreLevel || SECONDARY_STORE == dwStoreLevel); MakePath( (PRIMARY_STORE == dwStoreLevel) ? ePrimaryPropPath : eSecondaryPropPath, CI_OBJ(obj).ObjectId(), wcsIndex );
XPtr<CMmStream> xStream( new CMmStream( _cMegToLeaveOnDisk, _fIsReadOnly ) );
xStream->Open ( wcsIndex, GENERIC_READ | GENERIC_WRITE, // Access flags
FILE_SHARE_READ | FILE_SHARE_WRITE, // Sharing flags
CREATE_NEW, // File cannot already exist.
FILE_ATTRIBUTE_NORMAL ); return xStream.Acquire(); }
//+-------------------------------------------------------------------------
//
// Method: CiStorage::QueryExistingPropStream
//
// Synopsis: Opens existing prop stream
//
// Arguments: [obj] -- Object holding stream
// [fWrite] -- Flag indicating if the stream must be opened
// for write access; set to TRUE during a restarted
// master merge.
//
// Returns: Stream
//
// History: 17-Feb-1994 KyleP Created
//
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryExistingPropStream ( PStorageObject& obj, PStorage::EOpenMode mode, DWORD dwStoreLevel ) { WCHAR wcsIndex [ MAX_PATH ];
Win4Assert(PRIMARY_STORE == dwStoreLevel || SECONDARY_STORE == dwStoreLevel); MakePath( (PRIMARY_STORE == dwStoreLevel) ? ePrimaryPropPath : eSecondaryPropPath, CI_OBJ(obj).ObjectId(), wcsIndex ); XPtr<CMmStream> xStream( new CMmStream( _cMegToLeaveOnDisk, _fIsReadOnly ) );
BOOL fWrite = PStorage::eOpenForWrite == mode; DWORD dwAccess = fWrite ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ;
xStream->Open ( wcsIndex, dwAccess, // Access flags
FILE_SHARE_READ | FILE_SHARE_WRITE, // Sharing flags
OPEN_EXISTING); // File must already exist.
return xStream.Acquire(); }
//+-------------------------------------------------------------------------
//
// Method: CiStorage::QueryNewPSBkpStream, public
//
// Synopsis: Creates property store backup stream.
//
// Arguments: [obj] -- Object holding stream
// [ulMaxPages] -- Max pages to backup
//
// Returns: Property store backup stream
//
// History: 30-May-97 KrishnaN Created
// 29-Oct-98 KLam Pass _cMegToLeaveOnDisk to
// CPropStoreBackupStream
//
// Notes: This method can be called either to create a backup file when a
// catalog is being created for the first time or when a catalog is
// being opened at CI startup. In the latter case it will be called
// after the existing backup file is already used, if necessary. Once
// the backup file is used, it can be run over.
//
//--------------------------------------------------------------------------
CPropStoreBackupStream* CiStorage::QueryNewPSBkpStream( PStorageObject& obj, ULONG ulMaxPages, DWORD dwStoreLevel ) { WCHAR wcsIndex [ MAX_PATH ]; wcscpy(wcsIndex, _xPath.GetPointer() ); Win4Assert(PRIMARY_STORE == dwStoreLevel || SECONDARY_STORE == dwStoreLevel); wcscat(wcsIndex, (PRIMARY_STORE == dwStoreLevel) ? PROP_BKP_FILE1 : PROP_BKP_FILE2); XPtr<CPropStoreBackupStream> xStream( new CPropStoreBackupStream( _cMegToLeaveOnDisk ) );
xStream->OpenForBackup ( wcsIndex, FILE_SHARE_READ | FILE_SHARE_WRITE, // Sharing flags
CREATE_ALWAYS, // File may already exist, but we'll run over it.
ulMaxPages); Win4Assert(xStream.GetPointer()); return xStream.Acquire(); }
//+-------------------------------------------------------------------------
//
// Method: CiStorage::OpenExistingPSBkpStreamForRecovery, public
//
// Synopsis: Opens existing property store backup stream for recovery.
//
// Arguments: [obj] -- Object holding stream
//
// Returns: Property store backup stream
//
// History: 30-May-97 KrishnaN Created
// 29-Oct-98 KLam Pass _cMegToLeaveOnDisk to
// CPropStoreBackupStream
//
//--------------------------------------------------------------------------
CPropStoreBackupStream* CiStorage::OpenExistingPSBkpStreamForRecovery(PStorageObject& obj, DWORD dwStoreLevel) { WCHAR wcsIndex [ MAX_PATH ]; wcscpy( wcsIndex, _xPath.GetPointer() ); Win4Assert(PRIMARY_STORE == dwStoreLevel || SECONDARY_STORE == dwStoreLevel); wcscat(wcsIndex, (PRIMARY_STORE == dwStoreLevel) ? PROP_BKP_FILE1 : PROP_BKP_FILE2); XPtr<CPropStoreBackupStream> xStream( new CPropStoreBackupStream( _cMegToLeaveOnDisk ) );
xStream->OpenForRecovery( wcsIndex, FILE_SHARE_READ); // Sharing flags
Win4Assert(xStream.GetPointer()); return xStream.Acquire(); }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
PDirectory* CiStorage::QueryNewDirectory( PStorageObject& obj ) { return new CiDirectory( *this, CI_OBJ(obj).ObjectId(), PStorage::eCreate ); }
//+---------------------------------------------------------------------------
//
// Function: QueryExistingDirectory
//
// Synopsis: Returns an existing directory stream for an index.
//
// Arguments: [obj] -- Storage object.
// [fWrite] -- Flag indicating if the stream must be opened
// for write access or for read access.
//
// History: 4-20-94 srikants Added fWrite parameter
//
// Notes: fWrite parameter was added to support restartable master
// merge.
//
//----------------------------------------------------------------------------
PDirectory* CiStorage::QueryExistingDirectory( PStorageObject& obj, PStorage::EOpenMode mode ) { return new CiDirectory ( *this, CI_OBJ(obj).ObjectId(), mode ); }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryNewDirStream ( WORKID iid ) { WCHAR wcsDir [ MAX_PATH ]; MakePath( eDirPath, iid, wcsDir ); XPtr<CMmStream> xStream( new CMmStream( _cMegToLeaveOnDisk, _fIsReadOnly ) ); xStream->Open ( wcsDir, GENERIC_READ | GENERIC_WRITE, // Access flags
FILE_SHARE_READ, // Sharing flags
CREATE_NEW, // File cannot already exist.
FILE_ATTRIBUTE_NORMAL ); return xStream.Acquire(); }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryExistingDirStream ( WORKID iid, BOOL fWrite ) { WCHAR wcsDir [ MAX_PATH ]; MakePath( eDirPath, iid, wcsDir ); XPtr<CMmStream> xStream( new CMmStream( _cMegToLeaveOnDisk, _fIsReadOnly ) );
if ( _fIsReadOnly ) fWrite = FALSE;
DWORD dwAccess = fWrite ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ;
xStream->Open( wcsDir, dwAccess, // Access flags
FILE_SHARE_READ | FILE_SHARE_WRITE, // Sharing flags
OPEN_EXISTING ); // File must already exist.
return xStream.Acquire(); }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
BOOL CiStorage::RemoveObject( WORKID iid ) { WCHAR wcsIndex [ MAX_PATH ];
//
// Delete index
//
MakePath( eIndexPath, iid, wcsIndex ); BOOL fSuccess = DeleteFile( wcsIndex );
//
// and directory
//
MakePath( eDirPath, iid, wcsIndex ); fSuccess = fSuccess && DeleteFile( wcsIndex );
//
// and maybe hash
//
MakePath( eHashPath, iid, wcsIndex ); if ( !DeleteFile( wcsIndex ) ) fSuccess = fSuccess && (GetLastError() == ERROR_FILE_NOT_FOUND);
//
// and maybe prop
//
MakePath( ePrimaryPropPath, iid, wcsIndex ); if ( !DeleteFile( wcsIndex ) ) fSuccess = fSuccess && (GetLastError() == ERROR_FILE_NOT_FOUND);
MakePath( eSecondaryPropPath, iid, wcsIndex ); if ( !DeleteFile( wcsIndex ) ) fSuccess = fSuccess && (GetLastError() == ERROR_FILE_NOT_FOUND);
return fSuccess; }
//+-------------------------------------------------------------------------
//
// Member: CiStorage::MakeLogPath, private
//
// Synopsis: Create a fully qualified path for which to store the
// persistent log.
//
// Arguments: [wcsName] -- name of logfile to append to path
// [wcsPath] -- (out) resulting fully qualified name
//
// Notes: It is assumed that wcsPath is large enough to hold the
// name + path
//
// History: 18-Nov-93 DwightKr Created
//
//--------------------------------------------------------------------------
void CiStorage::MakeLogPath(WCHAR * wcsName, WCHAR * wcsPath) { wcscpy(wcsPath, _xPath.GetPointer()); wcscat(wcsPath, wcsName);
Win4Assert( wcslen(wcsPath) < MAX_PATH ); }
//+-------------------------------------------------------------------------
//
// Member: CiStorage::QueryFreshLog, public
//
// Synopsis: Builds a new persistent freshlog, using the specified name
//
// Arguments: [wcsName] -- name to use for new stream
//
// Returns: a new CPersStream * object
//
// History: 19-Nov-93 DwightKr Created
// 27-Oct-98 KLam Pass _cMegToLeaveOnDisk to CiRcovStorageObj
//
//--------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QueryFreshLog(WORKID wid) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
FormRcovObjNames( wid, FRESHLOG_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 );
return new CiRcovStorageObj( *this, wcsHdr, wcsCopy1, wcsCopy2, _cMegToLeaveOnDisk, _fIsReadOnly); }
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
BOOL CiStorage::RemoveFreshLog(WORKID wid) {
WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
FormRcovObjNames( wid, FRESHLOG_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 );
DeleteFile( wcsHdr ); DeleteFile( wcsCopy1 ); DeleteFile( wcsCopy2 );
return(TRUE); }
//+---------------------------------------------------------------------------
//
// Function: QueryChangeLog
//
// Synopsis: Creates a recoverable storage object for testing.
//
// History: 2-08-94 DwightKr Created
// 4-20-94 SrikantS Modified to use the common
// FormRcovObjNames method.
// 27-Oct-98 KLam Pass _cMegToLeaveOnDisk to CiRcovStorageObj
//
// Notes: For down level storage, the WID is really the partition ID.
//
//----------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QueryChangeLog( WORKID wid, EChangeLogType type ) {
WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
if ( ePrimChangeLog == type ) { FormRcovObjNames( wid, PRI_CHANGELOG_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 ); } else { FormRcovObjNames( wid, SEC_CHANGELOG_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 ); }
return new CiRcovStorageObj( *this, wcsHdr, wcsCopy1, wcsCopy2, _cMegToLeaveOnDisk, _fIsReadOnly ); }
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QueryRecoverableLog(WORKID wid) { Win4Assert(!"QueryRecoverableLog() not supported in class CiStorage");
PRcovStorageObj *a = 0;
return a; }
//+-------------------------------------------------------------------------
//
// Member: CiStorage::QueryPidLookupTable, public
//
// Synopsis: Builds a new persistent storage object for PID mapping.
//
// Arguments: [wid] -- WorkId of the object. For downlevel, only
// the upper 4 bytes are used as the "partition id" that the
// object belongs to. It is assumed that the upper 4 bytes of
// the wid contain the partition id.
//
// Returns: a new CPersStream * object
//
// History: 05 Jan 1996 Alanw Created
// 27 Oct 1998 KLam Pass _cMegToLeaveOnDisk to CiRcovStorageObj
//
//--------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QueryPidLookupTable(WORKID wid) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
FormRcovObjNames( wid, PIDTABLE_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 );
return new CiRcovStorageObj( *this, wcsHdr, wcsCopy1, wcsCopy2, _cMegToLeaveOnDisk, _fIsReadOnly ); }
//+-------------------------------------------------------------------------
//
// Member: CiStorage::QuerySdidLookupTable, public
//
// Synopsis: Builds a new persistent storage object for SDID mapping.
//
// Arguments: [wid] -- WorkId of the object. For downlevel, only
// the upper 4 bytes are used as the "partition id" that the
// object belongs to. It is assumed that the upper 4 bytes of
// the wid contain the partition id.
//
// Returns: a new CPersStream * object
//
// History: 29 Jan 1996 Alanw Created
// 27 Oct 1998 KLam Pass _cMegToLeaveOnDisk to CiRcovStorageObj
//
//--------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QuerySdidLookupTable(WORKID wid) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
FormRcovObjNames( wid, SECSTORE_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 );
return new CiRcovStorageObj( *this, wcsHdr, wcsCopy1, wcsCopy2, _cMegToLeaveOnDisk, _fIsReadOnly ); }
//+---------------------------------------------------------------------------
//
// Function: FormRcovObjNames
//
// Synopsis: Forms the down-level names for the three streams that make up
// a recoverable object. This method can be used for creating
// names for objects that exist on a "per partition" basis.
//
// Arguments: [wid] -- WorkId of the object. For downlevel, only
// the upper 4 bytes are used as the "partition id" that the
// object belongs to. It is assumed that the upper 4 bytes of
// the wid contain the partition id.
// [wcsPrefix] -- A 5 character prefix for the object name.
// Must begin with a "\\". (That will leave 4 chars for name.)
// [wcsHdr] -- On output will contain the file name for the
// atomic header.
// [wcsCopy1] -- On output will contain the name of the first
// copy.
// [wcsCopy2] -- On output, will contain the name of the
// second copy.
//
// History: 4-20-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CiStorage::FormRcovObjNames( WORKID wid, WCHAR * wcsPrefix, WCHAR * wcsHdr, WCHAR * wcsCopy1, WCHAR * wcsCopy2 ) { Win4Assert( wcslen(wcsPrefix) == 5 ); // extra char is for "\\"
WCHAR wcsTemp[_MAX_FNAME+1]; CIndexId iid(wid);
Win4Assert( iid.PartId() <= 0x0000FFFF );
swprintf(wcsTemp, L"%5s%4.4x.000", wcsPrefix, iid.PartId() ); MakeLogPath( wcsTemp, wcsHdr );
swprintf(wcsTemp, L"%5s%4.4x.001", wcsPrefix, iid.PartId() ); MakeLogPath( wcsTemp, wcsCopy1 );
swprintf(wcsTemp, L"%5s%4.4x.002", wcsPrefix, iid.PartId() ); MakeLogPath( wcsTemp, wcsCopy2 ); }
//+---------------------------------------------------------------------------
//
// Function: QueryMMergeLog
//
// Synopsis: Returns a Master Merge Log object created on the heap.
//
// Arguments: [wid] -- WorkId of the master merge log. Only the upper
// 4 bytes are used as the partition id.
//
// History: 4-20-94 srikants Created
// 27-Oct-98 KLam Pass _cMegToLeaveOnDisk to CiRcovStorageObj
//
// Notes:
//
//----------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QueryMMergeLog( WORKID wid ) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
FormRcovObjNames( wid, MMLOG_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 ); return new CiRcovStorageObj( *this, wcsHdr, wcsCopy1, wcsCopy2, _cMegToLeaveOnDisk, _fIsReadOnly ); }
//+---------------------------------------------------------------------------
//
// Function: QueryPropStore
//
// Synopsis: Returns a property store table
//
// Arguments: [wid] -- WorkId of the property store table. Only the upper
// 4 bytes are used as the partition id.
//
// History: 27-Dec-94 KyleP Created
// 27-Oct-98 KLam Pass _cMegToLeaveOnDisk to CiRcovStorageObj
//
//----------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QueryPropStore( WORKID wid, DWORD dwStoreLevel ) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
Win4Assert(PRIMARY_STORE == dwStoreLevel || SECONDARY_STORE == dwStoreLevel);
FormRcovObjNames( wid, (PRIMARY_STORE == dwStoreLevel) ? PROPSTORE1_PREFIX : PROPSTORE2_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 );
return new CiRcovStorageObj( *this, wcsHdr, wcsCopy1, wcsCopy2, _cMegToLeaveOnDisk, _fIsReadOnly ); }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::RemovePropStore
//
// Synopsis: Removes the PropStore header files.
//
// Arguments: [wid] -- WorkId of the property store table. Only the upper
// 4 bytes are used as the partition id.
//
// History: 3-26-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::RemovePropStore( WORKID wid, DWORD dwStoreLevel ) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
Win4Assert(PRIMARY_STORE == dwStoreLevel || SECONDARY_STORE == dwStoreLevel);
FormRcovObjNames( wid, (PRIMARY_STORE == dwStoreLevel) ? PROPSTORE1_PREFIX : PROPSTORE2_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 ); DeleteFile( wcsHdr ); DeleteFile( wcsCopy1); DeleteFile( wcsCopy2 ); }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::RemoveSecStore
//
// Synopsis: Removes the security store files.
//
// Arguments: [wid] -- Workid of the security store table.
//
// History: 7-14-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::RemoveSecStore( WORKID wid ) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
FormRcovObjNames( wid, SECSTORE_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 );
DeleteFile( wcsHdr ); DeleteFile( wcsCopy1); DeleteFile( wcsCopy2 ); }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::QueryScopeList
//
// Synopsis: Returns CI scopes list table
//
// Arguments: [wid] - Workid of the scopes list table.
//
// History: 1-19-96 srikants Created
// 27-Oct-98 KLam Pass _cMegToLeaveOnDisk to CiRcovStorageObj
//
// Notes:
//
//----------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QueryScopeList( WORKID wid ) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
FormRcovObjNames( wid, SCOPELIST_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 );
return new CiRcovStorageObj( *this, wcsHdr, wcsCopy1, wcsCopy2, _cMegToLeaveOnDisk, _fIsReadOnly ); }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::QueryVirtualScopeList
//
// Synopsis: Returns CI virtual scopes list table
//
// Arguments: [wid] - Workid of the virtual scopes list table.
//
// History: 2-05-96 KyleP Created
// 27-Oct-98 KLam Pass _cMegToLeaveOnDisk to CiRcovStorageObj
//
//----------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QueryVirtualScopeList( WORKID wid ) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
FormRcovObjNames( wid, VSCOPELIST_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 );
return new CiRcovStorageObj( *this, wcsHdr, wcsCopy1, wcsCopy2, _cMegToLeaveOnDisk, _fIsReadOnly ); }
//+---------------------------------------------------------------------------
//
// Function: RemoveMMLog
//
// Synopsis: Deletes the specified master log object.
//
// Arguments: [wid] -- WorkId of the master merge log. Only the upper
// 4 bytes are used as the partition id.
//
// History: 4-20-94 srikants Created
//
//----------------------------------------------------------------------------
BOOL CiStorage::RemoveMMLog( WORKID wid ) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
FormRcovObjNames( wid, MMLOG_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 );
DeleteFile( wcsHdr ); DeleteFile( wcsCopy1 ); DeleteFile( wcsCopy2 );
return(TRUE);
}
//+---------------------------------------------------------------------------
//
// Function: QueryTestLog
//
// Synopsis: Creates a recoverable storage object for testing.
//
// History: 2-08-94 srikants Created
// 27-Oct-98 KLam Pass _cMegToLeaveOnDisk to CiRcovStorageObj
//
//----------------------------------------------------------------------------
PRcovStorageObj * CiStorage::QueryTestLog() { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
MakeLogPath( CAT_TESTLOG_HDR, wcsHdr ); MakeLogPath( CAT_TESTLOG_CP1, wcsCopy1 ); MakeLogPath( CAT_TESTLOG_CP2, wcsCopy2 );
return new CiRcovStorageObj( *this, wcsHdr, wcsCopy1, wcsCopy2, _cMegToLeaveOnDisk, _fIsReadOnly ); }
//+---------------------------------------------------------------------------
//
// Function: GetDiskSpace
//
// Synopsis: Returns the disk size & space remaining, in bytes
// Takes into consideration the space to leave on disk
//
// History: 31-Jul-94 DwightKr Created
// 27-Oct-98 KLam Compensates for DiskSpaceToLeave
// Forwards call to drive info
//
//----------------------------------------------------------------------------
void CiStorage::GetDiskSpace( __int64 & diskTotal, __int64 & diskRemaining ) { _driveInfo.GetDiskSpace ( diskTotal, diskRemaining ); }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::ReportCorruptComponent, public
//
// Synopsis: Generates meaningful error message on storage corruption.
//
// Arguments: [pwszString] -- Error message
//
// History: 21-Jul-97 KyleP Move from header
//
//----------------------------------------------------------------------------
void CiStorage::ReportCorruptComponent( WCHAR const * pwszString ) { if ( !_fCorruptionReported ) { CFwCorruptionEvent event( GetVolumeName(), pwszString, _adviseStatus ); _fCorruptionReported = TRUE; } }
//+---------------------------------------------------------------------------
//
// Function: GetNewObjectIdForFreshLog
//
// Synopsis: Forms a new object id for the fresh log. It uses a pool of
// two ids and returns the one that is currently not in use.
//
// Returns: ObjectId for a new fresh log.
//
// History: 10-05-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
WORKID CiStorage::GetNewObjectIdForFreshLog() { CIndexId iidCurr( _widFreshLog ); PARTITIONID partIdNew = partidFresh1 == iidCurr.PartId() ? partidFresh2 : partidFresh1;
CIndexId iidNew( itFreshLog, partIdNew ); return( CreateObjectId( iidNew, PStorage::eRcovHdr ) ); }
//+---------------------------------------------------------------------------
//
// Function: SetSpecialItObjectId
//
// Synopsis: Sets the object id of the special index type.
//
// Arguments: [it] -- Index Type
// [wid] -- WorkId for this index type.
//
// History: 10-05-94 srikants Created
//
// Notes: As of now, only the itFreshLog is of interest to CiStorage.
//
//----------------------------------------------------------------------------
void CiStorage::SetSpecialItObjectId( IndexType it, WORKID wid ) { switch ( it ) { case itFreshLog: #if CIDBG==1
CIndexId iid( wid ); Win4Assert( it == iid.PersId() ); Win4Assert( partidFresh1 == iid.PartId() || partidFresh2 == iid.PartId() ); #endif // CIDBG
_widFreshLog = wid; break; }
return; }
//+---------------------------------------------------------------------------
//
// Function: GetSpecialItObjectId
//
// Synopsis: Returns the current object id of a special index type.
//
// Arguments: [it] -- Index Type
//
// History: 10-05-94 srikants Created
//
// Notes: As of now, only the itFreshLog is of interest.
//
//----------------------------------------------------------------------------
WORKID CiStorage::GetSpecialItObjectId( IndexType it ) const { switch ( it ) { case itFreshLog: return(_widFreshLog);
default: return(0); } }
//+---------------------------------------------------------------------------
//
// Function: DeleteObject, public
//
// Synopsis: Deletes the file specified
//
// Arguments: [objectId] -- Object to delete
//
// History: Nov-16-94 DwightKr Added this header
//
//----------------------------------------------------------------------------
void CiStorage::DeleteObject( WORKID objectId ) { RemoveObject( objectId ); }
//+---------------------------------------------------------------------------
//
// Function: EmptyIndexList, public
//
// Synopsis: Empties the index list
//
// History: Nov-16-94 DwightKr Created
//
//----------------------------------------------------------------------------
void CiStorage::EmptyIndexList() { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
MakeLogPath( CAT_IDXTABLE_HDR, wcsHdr ); MakeLogPath( CAT_IDXTABLE_CP1, wcsCopy1 ); MakeLogPath( CAT_IDXTABLE_CP2, wcsCopy2 );
HANDLE hFile = CreateFile( wcsHdr, GENERIC_WRITE, 0, NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( INVALID_HANDLE_VALUE != hFile ) CloseHandle( hFile );
hFile = CreateFile( wcsCopy1, GENERIC_WRITE, 0, NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( INVALID_HANDLE_VALUE != hFile ) CloseHandle( hFile );
hFile = CreateFile( wcsCopy2, GENERIC_WRITE, 0, NULL, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( INVALID_HANDLE_VALUE != hFile ) CloseHandle( hFile ); }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::ListPropStoreFileNames, public
//
// Synopsis: Lists property store related files in the ci directory.
//
// Arguments: [enumStr] - String enumerator to which to add filenames to.
// [wid] - WORKID of the property store.
//
// History: 11-Apr-97 KrishnaN Created
// 30-May-97 KrishnaN Enumerate the backup file
// 24-Oct-97 KyleP Backup file is ephemeral and thus not
// part of the list.
//
//----------------------------------------------------------------------------
void CiStorage::ListPropStoreFileNames( CEnumString & enumStr, WORKID wid, DWORD dwStoreLevel ) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
//
// Get the recoverable storage object files
//
Win4Assert(PRIMARY_STORE == dwStoreLevel || SECONDARY_STORE == dwStoreLevel);
FormRcovObjNames( wid, (PRIMARY_STORE == dwStoreLevel) ? PROPSTORE1_PREFIX:PROPSTORE2_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 ); enumStr.Append(wcsHdr); enumStr.Append(wcsCopy1); enumStr.Append(wcsCopy2);
//
// Get the property store and prop store backup file names
//
// Reuse wcsCopy1
PStorageObject *pObj = QueryObject(wid); XPtr<PStorageObject> xObj(pObj);
MakePath( (PRIMARY_STORE == dwStoreLevel) ? ePrimaryPropPath:eSecondaryPropPath, CI_OBJ(*pObj).ObjectId(), wcsCopy1); enumStr.Append(wcsCopy1); }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::ListSecStoreFileNames
//
// Synopsis: Lists the names of the files that constitute the recoverable
// stoage object for the security store.
//
// Arguments: [enumStr] -- Output object to append the names of the
// security store.
// [wid] -- Workid
//
// History: 7-14-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::ListSecStoreFileNames( CEnumString & enumStr, WORKID wid ) { WCHAR wcsHdr[MAX_PATH]; WCHAR wcsCopy1[MAX_PATH]; WCHAR wcsCopy2[MAX_PATH];
//
// Get the recoverable storage object files
//
FormRcovObjNames( wid, SECSTORE_PREFIX, wcsHdr, wcsCopy1, wcsCopy2 );
enumStr.Append(wcsHdr); enumStr.Append(wcsCopy1); enumStr.Append(wcsCopy2);
}
//+---------------------------------------------------------------------------
//
// Member: CiStorage::DeleteFilesInCiDir
//
// Synopsis: Deletes files in the ci directory which match the given
// pattern.
//
// Arguments: [pwszPattern] - Pattern of files to search.
//
// History: 1-31-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::DeleteFilesInCiDir( WCHAR const * pwszPattern ) { CFullPath fullPath( _xPath.GetPointer() );
WCHAR wszFullPattern[MAX_PATH];
swprintf( wszFullPattern, L"%s%s", fullPath.GetBuf(), pwszPattern );
WIN32_FIND_DATA fileData;
HANDLE hFile = FindFirstFile( wszFullPattern, &fileData );
if ( INVALID_HANDLE_VALUE == hFile ) { ciDebugOut(( DEB_ITRACE, "Did not find files for (%ws)\n", wszFullPattern )); return; }
do { if ( !(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { fullPath.MakePath( fileData.cFileName ); BOOL fSuccess = DeleteFile( fullPath.GetBuf() ); if ( !fSuccess ) { DWORD dwError = GetLastError(); ciDebugOut(( DEB_ITRACE, "Failed to delete file (%ws) due to error (%d)\n", fullPath.GetBuf(), dwError )); } else { ciDebugOut(( DEB_ITRACE, "Deleted file (%ws)\n", fullPath.GetBuf() )); } } else { ciDebugOut(( DEB_ITRACE, "Not deleting directory (%ws) \n", fullPath.GetBuf() ));
}
} while ( FindNextFile( hFile, &fileData ) );
FindClose( hFile ); }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::DeleteAllFiles
//
// Synopsis: Deletes all the files in the Ci directory.
//
// History: 3-21-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::DeleteAllFiles() { WCHAR wszPattern[32];
swprintf( wszPattern, L"*.*" ); DeleteFilesInCiDir( wszPattern );
}
//+---------------------------------------------------------------------------
//
// Member: CiStorage::DeleteAllCiFiles
//
// Synopsis: Deletes files that belong to the CI engine.
//
// History: 1-31-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::DeleteAllCiFiles() { //
// Delete the following types of files.
//
WCHAR wszPattern[32];
swprintf( wszPattern, L"*.ci" ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"*.dir" ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", MMLOG_PREFIX ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", PRI_CHANGELOG_PREFIX ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", SEC_CHANGELOG_PREFIX ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", FRESHLOG_PREFIX ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"INDEX.*" ); DeleteFilesInCiDir( wszPattern );
}
//+---------------------------------------------------------------------------
//
// Member: CiStorage::DeleteAllPersistentIndexes
//
// Synopsis: Deletes all the persistent indexes in the ci directory.
//
// History: 3-25-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::DeleteAllPersIndexes() { //
// Delete the following types of files.
//
WCHAR wszPattern[32];
swprintf( wszPattern, L"*.ci" ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"*.dir" ); DeleteFilesInCiDir( wszPattern ); }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::DeleteUnUsedPersIndexes
//
// Synopsis: Deletes any .ci and .dir files that are not referenced in
// the given iid list.
//
// Arguments: [iidStk] - List of in-use iids.
//
// History: 3-25-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::DeleteUnUsedPersIndexes( BOOL fIsCi, CIndexIdList const & iidsInUse ) { WCHAR wszPattern[32];
if ( fIsCi ) swprintf( wszPattern, L"*.ci" ); else swprintf( wszPattern, L"*.dir" );
CFullPath fullPath( _xPath.GetPointer() );
WCHAR wszFullPattern[MAX_PATH];
swprintf( wszFullPattern, L"%s%s", fullPath.GetBuf(), wszPattern );
WIN32_FIND_DATA fileData;
HANDLE hFile = FindFirstFile( wszFullPattern, &fileData );
if ( INVALID_HANDLE_VALUE == hFile ) { ciDebugOut(( DEB_ITRACE, "Did not find files for (%ws)\n", wszFullPattern )); return; }
do { if ( !(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { if ( !IsInUse( fileData.cFileName, iidsInUse ) ) { fullPath.MakePath( fileData.cFileName );
ciDebugOut(( DEB_ITRACE, "Deleting UnUsed Index (%ws) \n", fullPath.GetBuf() )); BOOL fSuccess = DeleteFile( fullPath.GetBuf() ); if ( !fSuccess ) { DWORD dwError = GetLastError(); ciDebugOut(( DEB_ITRACE, "Failed to delete file (%ws) due to error (%d)\n", fullPath.GetBuf(), dwError )); } else { ciDebugOut(( DEB_ITRACE, "Deleted file (%ws)\n", fullPath.GetBuf() )); } } } else { ciDebugOut(( DEB_ITRACE, "Not deleting directory (%ws) \n", fullPath.GetBuf() ));
}
} while ( FindNextFile( hFile, &fileData ) );
FindClose( hFile );
}
//+---------------------------------------------------------------------------
//
// Member: CiStorage::IsInUse
//
// Synopsis: Tests if the given file is in use.
//
// Arguments: [pwszFile] -
// [iidStk] -
//
// Returns: TRUE if it is in use. FALSE o/w
//
// History: 3-25-97 srikants Created
//
//----------------------------------------------------------------------------
BOOL CiStorage::IsInUse( WCHAR const * pwszFile, CIndexIdList const & iidsInUse ) const { //
// Determine the iid and see if it is in the list.
//
WCHAR * pwszEnd; INDEXID iid = (INDEXID) wcstol( pwszFile, &pwszEnd, 16 );
for ( ULONG i = 0; i < iidsInUse.Count(); i++ ) { if ( iid == iidsInUse.Get(i) ) return TRUE; }
return FALSE; }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::DeleteUnUsedPersIndexes
//
// Synopsis: Deletes the persistent .ci and .dir files that are not
// in the list of in-use iids.
//
// Arguments: [iidStk] - The list of in-use iids.
//
// History: 3-25-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::DeleteUnUsedPersIndexes( CIndexIdList const & iidsInUse ) {
DeleteUnUsedPersIndexes( TRUE, iidsInUse ); // delete the unused .ci files
DeleteUnUsedPersIndexes( FALSE, iidsInUse ); // delete the unused .dir files
}
//+---------------------------------------------------------------------------
//
// Member: CiStorage::DeleteAllFsCiFiles
//
// Synopsis: Deletes all the files belonging to the FileSystem CI client.
//
// History: 2-10-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::DeleteAllFsCiFiles() { //
// Delete the following types of files.
//
WCHAR wszPattern[32];
swprintf( wszPattern, L"cicat.hsh" ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"cicat.fid" ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"deletion.log" ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, PROP_BKP_FILE); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, PROP_BKP_FILE1); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, PROP_BKP_FILE2); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"*.prp" ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"*.ps1" ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"*.ps2" ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", PIDTABLE_PREFIX ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", SCOPELIST_PREFIX ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", SECSTORE_PREFIX ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", PROPSTORE_PREFIX ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", PROPSTORE1_PREFIX ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", PROPSTORE2_PREFIX ); DeleteFilesInCiDir( wszPattern );
swprintf( wszPattern, L"%s*", VSCOPELIST_PREFIX ); DeleteFilesInCiDir( wszPattern ); }
//+---------------------------------------------------------------------------
//
// Member: CiStorage::CopyGivenFile
//
// Synopsis: Copies or Moves the given file to the current catalog location.
//
// Arguments: [pwszFilePath] - Full path of the source file
// [fMoveOk] - Set to TRUE if a move is okay. A move is done
// if the file is on the same drive.
//
// History: 3-18-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::CopyGivenFile( WCHAR const * pwszFilePath, BOOL fMoveOk ) {
Win4Assert( 0 != pwszFilePath );
//
// Locate the file name component in the path.
//
WCHAR const * pwszFileName = 0;
int cwc = (int) wcslen( pwszFilePath ); for ( int i = cwc; i >=0; i-- ) { if ( pwszFilePath[i] == L'\\' ) { pwszFileName = pwszFilePath+i; break; } }
if ( 0 == pwszFileName ) { ciDebugOut(( DEB_ITRACE, "No file name in path (%ws)\n", pwszFilePath )); THROW( CException( E_INVALIDARG ) ); }
WCHAR wcsDestPath[MAX_PATH]; wcscpy( wcsDestPath, _xPath.GetPointer() ); wcscat( wcsDestPath, pwszFileName );
ciDebugOut(( DEB_ITRACE, "CopyFile to (%ws) \n", wcsDestPath ));
//
// First delete any file with the same name in the destination.
//
DeleteFilesInCiDir( pwszFileName+1 ); // Backslash is the first char
//
// If they are on the same drive and move is okay, then we should move
// the file rather than copying the file.
//
if ( (_xPath.GetPointer()[0] == pwszFilePath[0]) && fMoveOk ) { if ( !MoveFile( pwszFilePath, wcsDestPath ) ) { DWORD dwError = GetLastError(); ciDebugOut(( DEB_ITRACE, "MoveFile (%ws) -> (%ws) failed. Error %d\n", pwszFilePath, wcsDestPath, dwError )); THROW( CException( HRESULT_FROM_WIN32( dwError ) ) ); } } else { //
// We have to create a copy of the file.
//
if ( !CopyFile( pwszFilePath, wcsDestPath, FALSE // Don't fail if it exists
) ) { DWORD dwError = GetLastError(); ciDebugOut(( DEB_ITRACE, "CopyFile (%ws) -> (%ws) failed. Error %d\n", pwszFilePath, wcsDestPath, dwError )); THROW( CException( HRESULT_FROM_WIN32( dwError ) ) ); }
//
// If the fMove is set to TRUE, delete the source file
//
if ( fMoveOk ) DeleteFile( pwszFilePath ); } }
//+---------------------------------------------------------------------------
//
// Function: EnumerateFilesInDir
//
// Synopsis: Enumerates files in a directory. Does not include directories
// and there is no recursive traversal.
//
// Arguments: [pwszDir] - Directory to enumerate.
// [enumStr] - Place to add the enumerated files.
//
// History: 3-19-97 srikants Created
//
//----------------------------------------------------------------------------
void CiStorage::EnumerateFilesInDir( WCHAR const * pwszDir, CEnumString & enumStr ) { CFullPath fullPath( (WCHAR *) pwszDir );
fullPath.MakePath( L"*.*" );
WIN32_FIND_DATA fileData;
HANDLE hFile = FindFirstFile( fullPath.GetBuf(), &fileData );
if ( INVALID_HANDLE_VALUE == hFile ) { ciDebugOut(( DEB_ITRACE, "Did not find files for (%ws)\n", fullPath.GetBuf() )); return; }
do { if ( !(fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) { fullPath.MakePath( fileData.cFileName ); enumStr.Append( fullPath.GetBuf() );
ciDebugOut(( DEB_ITRACE, "EnumerateFiles - Adding File (%ws) \n", fullPath.GetBuf() ));
} else { ciDebugOut(( DEB_ITRACE, "EnumerateFiles - Skipping directory (%ws) \n", fileData.cFileName ));
} } while ( FindNextFile( hFile, &fileData ) );
FindClose( hFile ); }
//+---------------------------------------------------------------------------
//
// Function: IsValidFile
//
// Synopsis: Verifies that the given file is a valid file.
//
// Arguments: [pwszFile] - File name
//
// History: 3-21-97 srikants Created
//
//----------------------------------------------------------------------------
BOOL CiStorage::IsValidFile( WCHAR const * pwszFile ) { DWORD dwFileAttributes = GetFileAttributes( pwszFile );
if ( 0xFFFFFFFF == dwFileAttributes ) { DWORD dwError = GetLastError();
ciDebugOut(( DEB_ITRACE, "GetFileAttributes failed with error %d\n", dwError )); return FALSE; }
return 0 == (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ; }
//+---------------------------------------------------------------------------
//
// Function: CheckHasIndexTable
//
// Synopsis: Verifies that the given directory is a valid one. Also checks
// that files INDEX.000, INDEX.001, INDEX.002 are present in the
// directory.
//
// Arguments: [pwszPath] - Path of the directory.
//
// Returns: TRUE if valid; FALSE o/w
//
// History: 3-21-97 srikants Created
//
//----------------------------------------------------------------------------
BOOL CiStorage::CheckHasIndexTable( WCHAR const * pwszPath ) { CFullPath fullPath( pwszPath );
fullPath.MakePath( CAT_IDXTABLE_HDR ); if ( !IsValidFile( fullPath.GetBuf() ) ) return FALSE;
fullPath.MakePath( CAT_IDXTABLE_CP1 ); if ( !IsValidFile( fullPath.GetBuf() ) ) return FALSE;
fullPath.MakePath( CAT_IDXTABLE_CP2 ); if ( !IsValidFile( fullPath.GetBuf() ) ) return FALSE;
return TRUE; }
//+---------------------------------------------------------------------------
//
// Function: DetermineDriveType
//
// Synopsis: Determines the type of drive on which the given path is.
//
// Arguments: [pwszPath] - Path of the file.
//
// Returns: WIN32 drive type ( values returned by GetDriveType() )
//
// History: 3-24-97 srikants Created
//
//----------------------------------------------------------------------------
UINT CiStorage::DetermineDriveType( WCHAR const * pwszPath ) { CPathParser pathParser( pwszPath ); if ( pathParser.IsUNCName() ) return DRIVE_REMOTE;
WCHAR wDrive[MAX_PATH]; ULONG cc=sizeof(wDrive)/sizeof(WCHAR); pathParser.GetFileName( wDrive, cc );
UINT uType = GetDriveType( wDrive ); return uType; }
//+-------------------------------------------------------------------------
//
// Method: CiStorage::QueryStream, Private
//
// Synopsis: Opens a mmstream of name specified
//
// Arguments: [wcsFileName] - Name of the file.
//
// Returns: CMmStream
//
// History: 17-Mar-1998 KitmanH Created
//
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryStream (WCHAR const * wcsFileName) {
XPtr<CMmStream> xStrm( new CMmStream( _cMegToLeaveOnDisk, _fIsReadOnly ) );
DWORD dwAccess = _fIsReadOnly ? GENERIC_READ : ( GENERIC_READ | GENERIC_WRITE );
DWORD sharing = _fIsReadOnly ? ( FILE_SHARE_READ | FILE_SHARE_WRITE ) : FILE_SHARE_READ;
DWORD openMode = _fIsReadOnly ? OPEN_EXISTING : OPEN_ALWAYS;
WCHAR wcsFilePath[MAX_PATH];
wcscpy ( wcsFilePath, _xPath.GetPointer() ); wcscat ( wcsFilePath, wcsFileName );
xStrm->Open( wcsFilePath, dwAccess, // Access flags
sharing, openMode, FILE_ATTRIBUTE_NORMAL, FALSE );
return xStrm.Acquire(); }
//+-------------------------------------------------------------------------
//
// Method: CiStorage::QueryStringHash
//
// Synopsis: Opens a mmstream by calling private function QueryStream
// with the appropriate filename
//
// Arguments: [wcsFileName] - Name of the file.
//
// Returns: CMmStream
//
// History: 17-Mar-1998 KitmanH Created
//
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryStringHash() { return QueryStream( CAT_HASH_FILE ); }
//+-------------------------------------------------------------------------
//
// Method: CiStorage::QueryFileIdMap
//
// Synopsis: Opens a mmstream by calling private function QueryStream
// with the appropriate filename
//
// Arguments: [wcsFileName] - Name of the file.
//
// Returns: CMmStream
//
// History: 17-Mar-1998 KitmanH Created
//
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryFileIdMap() { return QueryStream( CAT_FILEID_MAP_FILE ); } //+-------------------------------------------------------------------------
//
// Method: CiStorage::QueryDeletionLog
//
// Synopsis: Opens a mmstream by calling private function QueryStream
// with the appropriate filename
//
// Arguments: [wcsFileName] - Name of the file.
//
// Returns: CMmStream
//
// History: 17-Mar-1998 KitmanH Created
//
//--------------------------------------------------------------------------
PMmStream* CiStorage::QueryDeletionLog() { Win4Assert( FALSE ); return 0; }
|