Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

490 lines
14 KiB

//+---------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation, 1991 - 1998
//
// File: dellog.cxx
//
// Contents: Deletion log for usns
//
// History: 28-Jul-97 SitaramR Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <mmstrm.hxx>
#include "cicat.hxx"
#include "dellog.hxx"
const LONGLONG eSigDelLog = 0x64656c746e6c6f67i64; // Signature
//+---------------------------------------------------------------------------
//
// Member: CFakeVolIdMap::CFakeVolIdMap
//
// Synopsis: Constructor
//
// History: 28-Jul-97 SitaramR Created
//
//----------------------------------------------------------------------------
CFakeVolIdMap::CFakeVolIdMap()
{
for ( ULONG i=0; i<COUNT_SPECIAL_CHARS; i++)
_aVolIdSpecial[i] = 0;
}
//+---------------------------------------------------------------------------
//
// Member: CFakeVolIdMap::VolIdToFakeVolId
//
// Synopsis: Converts a volume id to a fake volume id in the range
// 0..RTL_MAX_DRIVE_LETTERS-1
//
// History: 28-Jul-97 SitaramR Created
//
// Notes: Drive letters in the range 'a' to 'z' are mapped by subtracting
// 'a', which is the base volume id, i.e. they are in the range
// 0..25 The volume id's for the remaining drive letters are
// maintained in _aVolIdSpecial, and the fake volume ids for these
// special drives are in the range 26..RTL_MAX_DRIVE_LETTERS-1.
//
//----------------------------------------------------------------------------
ULONG CFakeVolIdMap::VolIdToFakeVolId( VOLUMEID volumeId )
{
//
// Volume ids are obtained by the ascii value of the drive letter
//
Win4Assert( volumeId < 0xff );
if ( volumeId >= VolumeIdBase
&& volumeId-VolumeIdBase < COUNT_ALPHABETS )
{
return volumeId-VolumeIdBase;
}
//
// Lookup in _aVolIdSpecial
//
for ( ULONG i=0; i<COUNT_SPECIAL_CHARS; i++ )
{
if ( _aVolIdSpecial[i] == volumeId )
return COUNT_ALPHABETS + i;
}
for ( i=0; i<COUNT_SPECIAL_CHARS; i++ )
{
if ( _aVolIdSpecial[i] == 0 )
{
_aVolIdSpecial[i] = volumeId;
return COUNT_ALPHABETS + i;
}
}
Win4Assert( !"Volume id map overflow" );
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CFakeVolIdMap::FakeVolIdToVolId
//
// Synopsis: Converts a fake volume id in the range 0..RTL_MAX_DRIVE_LETTERS-1
// to a real volume id
//
// History: 28-Jul-97 SitaramR Created
//
// Notes: See VolIdToFakeVolId for mapping info.
//
//----------------------------------------------------------------------------
VOLUMEID CFakeVolIdMap::FakeVolIdToVolId( ULONG fakeVolId )
{
Win4Assert( fakeVolId < RTL_MAX_DRIVE_LETTERS );
if ( fakeVolId < COUNT_ALPHABETS )
return VolumeIdBase + fakeVolId;
else
return _aVolIdSpecial[fakeVolId-COUNT_ALPHABETS];
}
//+---------------------------------------------------------------------------
//
// Member: CDeletionLog::CDeletionLog
//
// Synopsis: Constructor
//
// Arguments: [fileIdMap] -- File id map
// [cicat] -- Ci catalog
//
// History: 28-Jul-97 SitaramR Created
//
//----------------------------------------------------------------------------
CDeletionLog::CDeletionLog( CFileIdMap & fileIdMap, CiCat& cicat )
: _fileIdMap(fileIdMap),
_cicat(cicat)
{
}
//+---------------------------------------------------------------------------
//
// Member: CDeletionLog::FastInit
//
// Synopsis: Initialization
//
// Arguments: [pStorage] -- Ci storage
// [pwcsCatDir] -- Catalog dir
// [version] -- Version #
//
// History: 28-Jul-97 SitaramR Created
// 02-Mar-98 KitmanH Used QueryDeletionlog to obtain a new
// CMmStream
//
// Notes: The persistent format is <vol id><cEntries><entry 1>..<entry cEntries>
// for each volume id, and each entry has <fileid><wid><usn>.
//
//----------------------------------------------------------------------------
void CDeletionLog::FastInit( CiStorage * pStorage,
ULONG version )
{
XPtr<PMmStream> sStrm( pStorage->QueryDeletionLog() );
_xPersStream.Set( new CDynStream( sStrm.GetPointer() ) );
sStrm.Acquire();
_xPersStream->CheckVersion( *pStorage, version );
ULONG cVolumes = _xPersStream->Count();
_xPersStream->InitializeForRead();
for ( ULONG i=0; i<cVolumes; i++ )
{
ULONG cbRead;
LONGLONG llSig;
cbRead = _xPersStream->Read( &llSig, sizeof(llSig) );
if ( cbRead != sizeof(llSig) )
FatalCorruption( cbRead, sizeof(llSig) );
if ( eSigDelLog != llSig )
{
ciDebugOut(( DEB_ERROR,
"CDeletionLog: Signature mismatch 0x%x:0x%x\n",
lltoHighPart(llSig),
lltoLowPart(llSig) ));
FatalCorruption( 0, 0 );
}
VOLUMEID volumeId;
cbRead = _xPersStream->Read( &volumeId, sizeof(VOLUMEID) );
if ( cbRead != sizeof(VOLUMEID) )
FatalCorruption( cbRead, sizeof(VOLUMEID) );
ULONG cEntries;
cbRead = _xPersStream->Read( &cEntries, sizeof(ULONG) );
if ( cbRead != sizeof(ULONG) )
FatalCorruption( cbRead, sizeof(ULONG) );
for ( ULONG j=0; j<cEntries;j++ )
{
FILEID fileId;
cbRead = _xPersStream->Read( &fileId, sizeof(FILEID) );
if ( cbRead != sizeof(FILEID) )
FatalCorruption( cbRead, sizeof(FILEID) );
WORKID wid;
cbRead = _xPersStream->Read( &wid, sizeof(WORKID) );
if ( cbRead != sizeof(WORKID) )
FatalCorruption( cbRead, sizeof(WORKID) );
USN usn;
cbRead = _xPersStream->Read( &usn, sizeof(USN) );
if ( cbRead != sizeof(USN) )
FatalCorruption( cbRead, sizeof(USN) );
MarkForDeletion( volumeId,
fileId,
wid,
usn );
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CDeletionLog::ReInit
//
// Synopsis: Empties the deletion log
//
// History: 28-Jul-97 SitaramR Created
//
//----------------------------------------------------------------------------
void CDeletionLog::ReInit( ULONG version )
{
CLock lock(_mutex);
_xPersStream->SetVersion( version );
for ( ULONG i=0; i<RTL_MAX_DRIVE_LETTERS; i++ )
_aDelLogEntryList[i].Clear();
Flush();
}
//+---------------------------------------------------------------------------
//
// Member: CDeletionLog::Flush
//
// Synopsis: Serializes the deletion log to disk
//
// History: 28-Jul-97 SitaramR Created
//
//----------------------------------------------------------------------------
void CDeletionLog::Flush()
{
Win4Assert( !_xPersStream.IsNull() );
CLock lock(_mutex);
_xPersStream->InitializeForWrite( GetSize() );
LONGLONG llSig = eSigDelLog;
ULONG cVolumes = 0;
for ( ULONG i=0; i<RTL_MAX_DRIVE_LETTERS; i++ )
{
if ( _aDelLogEntryList[i].Count() > 0 )
{
cVolumes++;
_xPersStream->Write( &llSig, sizeof(llSig) );
VOLUMEID volumeId = _fakeVolIdMap.FakeVolIdToVolId( i );
_xPersStream->Write( &volumeId, sizeof(VOLUMEID) );
ULONG cEntries = _aDelLogEntryList[i].Count();
_xPersStream->Write( &cEntries, sizeof(ULONG) );
#if CIDBG==1
ULONG cEntriesInList = 0;
USN usnPrev = 0;
#endif
for ( CDelLogEntryListIter entryListIter( _aDelLogEntryList[i] );
!_aDelLogEntryList[i].AtEnd(entryListIter);
_aDelLogEntryList[i].Advance( entryListIter) )
{
FILEID fileId = entryListIter->FileId();
_xPersStream->Write( &fileId, sizeof(FILEID) );
WORKID wid = entryListIter->WorkId();
_xPersStream->Write( &wid, sizeof(WORKID) );
USN usn = entryListIter->Usn();
_xPersStream->Write( &usn, sizeof(USN) );
#if CIDBG==1
//
// Check usn's are monotonically increasing
//
cEntriesInList++;
Win4Assert( entryListIter->Usn() >= usnPrev );
usnPrev = entryListIter->Usn();
#endif
}
#if CIDBG==1
Win4Assert( cEntriesInList == _aDelLogEntryList[i].Count() );
#endif
}
}
_xPersStream->SetCount( cVolumes );
_xPersStream->Flush();
}
//+---------------------------------------------------------------------------
//
// Member: CDeletionLog::MarkForDeletion
//
// Synopsis: Adds a deletion entry
//
// History: 28-Jul-97 SitaramR Created
//
//----------------------------------------------------------------------------
void CDeletionLog::MarkForDeletion( VOLUMEID volumeId,
FILEID fileId,
WORKID wid,
USN usn )
{
CLock lock(_mutex);
XPtr<CDelLogEntry> xEntry( new CDelLogEntry( fileId, wid, usn ) );
ULONG fakeVolId = _fakeVolIdMap.VolIdToFakeVolId( volumeId );
Win4Assert( fakeVolId < RTL_MAX_DRIVE_LETTERS );
if ( _aDelLogEntryList[fakeVolId].Count() == 0 )
{
//
// Empty list case
//
_aDelLogEntryList[fakeVolId].Queue( xEntry.Acquire() );
}
else
{
CDelLogEntry *pEntryLast = _aDelLogEntryList[fakeVolId].GetLast();
if ( xEntry->Usn() > pEntryLast->Usn() )
{
//
// If the usn is less than the last entry's usn, then it means that it
// is a usn that is being replayed, and there is no need to add it
// to the deletion log again.
//
_aDelLogEntryList[fakeVolId].Queue( xEntry.Acquire() );
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CDeletionLog::ProcessChangesFlush
//
// Synopsis: Process the list of changes that has been flushed by
// framework/changelog and do the actual deletes from
// the file id map.
//
// Arguments: [usnFlushInfoList] -- List of changes flushed
//
// History: 28-Jul-97 SitaramR Created
//
//----------------------------------------------------------------------------
void CDeletionLog::ProcessChangesFlush( CUsnFlushInfoList & usnFlushInfoList )
{
CLock lock( _mutex );
for ( ULONG i=0; i<usnFlushInfoList.Count(); i++ )
{
CUsnFlushInfo *pFlushInfo = usnFlushInfoList.Get(i);
ULONG fakeVolId = _fakeVolIdMap.VolIdToFakeVolId( pFlushInfo->VolumeId() );
Win4Assert( fakeVolId < RTL_MAX_DRIVE_LETTERS );
CDelLogEntryList& entryList = _aDelLogEntryList[fakeVolId];
#if CIDBG==1
USN usnPrev = 0;
#endif
CDelLogEntryListIter entryListIter( entryList );
while ( !entryList.AtEnd( entryListIter ) )
{
CDelLogEntry *pEntry = entryListIter.GetEntry();
entryList.Advance( entryListIter );
#if CIDBG==1
//
// Check that usn's are monotonically increasing
//
Win4Assert( pEntry->Usn() >= usnPrev );
usnPrev = pEntry->Usn();
#endif
if ( pEntry->Usn() <= pFlushInfo->UsnHighest() )
{
entryList.RemoveFromList( pEntry );
_fileIdMap.Delete( pEntry->FileId(), pEntry->WorkId() );
delete pEntry;
}
else
{
//
// Since the list is in increasing usn order, we are done
// with this volume id.
//
break;
}
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CDeletionLog::GetSize
//
// Synopsis: Returns the size of the serialized stream in bytes
//
// History: 28-Jul-97 SitaramR Created
//
//----------------------------------------------------------------------------
ULONG CDeletionLog::GetSize()
{
//
// Start with a slop factor
//
ULONG ulSize = 1024;
for ( ULONG i=0; i<RTL_MAX_DRIVE_LETTERS; i++ )
{
ulSize += sizeof(VOLUMEID) // volume id field
+ sizeof(ULONG) // cEntries field
+ _aDelLogEntryList[i].Count() * sizeof(CDelLogEntry);
}
return ulSize;
}
//+---------------------------------------------------------------------------
//
// Member: CDeletionLog::FatalCorruption
//
// Synopsis: Handles deletion log corruption
//
// Arguments: [cbRead] -- Count of bytes read
// [cbToRead] -- Count of bytes to read
//
// History: 28-Jul-97 SitaramR Created
//
//----------------------------------------------------------------------------
void CDeletionLog::FatalCorruption( ULONG cbRead, ULONG cbToRead )
{
Win4Assert( !"Corrupt deletion log" );
ciDebugOut(( DEB_ERROR,
"CDeletionLog: read %d bytes instead of %d\n",
cbRead,
cbToRead ));
PStorage & storage = _cicat.GetStorage();
storage.ReportCorruptComponent( L"Deletion log" );
THROW( CException( CI_CORRUPT_CATALOG ) );
}