Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2192 lines
71 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 2002.
//
// 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 ];
wcsncpy( wcsPath, pwcPath, sizeof wcsPath / sizeof WCHAR );
wcsPath[ (sizeof wcsPath / sizeof WCHAR) - 1 ] = 0;
wcsncat(wcsPath, CAT_HASH_FILE, (sizeof wcsPath / sizeof WCHAR) - wcslen(wcsPath) );
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 )
{
Win4Assert( wcslen( PROP_BKP_FILE1 ) == wcslen( PROP_BKP_FILE2 ) );
unsigned cwc = wcslen( _xPath.GetPointer() ) + wcslen( PROP_BKP_FILE1 );
if ( cwc >= MAX_PATH )
THROW( CException( STATUS_INVALID_PARAMETER ) );
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)
{
Win4Assert( wcslen( PROP_BKP_FILE1 ) == wcslen( PROP_BKP_FILE2 ) );
unsigned cwc = wcslen( _xPath.GetPointer() ) + wcslen( PROP_BKP_FILE1 );
if ( cwc >= MAX_PATH )
THROW( CException( STATUS_INVALID_PARAMETER ) );
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 );
}
//+---------------------------------------------------------------------------
//
// 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];
if ( ( wcslen( _xPath.GetPointer() ) + wcslen( wcsFileName ) ) >= MAX_PATH )
THROW( CException( STATUS_INVALID_PARAMETER ) );
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;
}