305 lines
8 KiB
C++
305 lines
8 KiB
C++
|
|
||
|
// Copyright (c) 1996-1999 Microsoft Corporation
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// File: LogSect.cxx
|
||
|
//
|
||
|
// Classes: CLogFileSector
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
#include "pch.cxx"
|
||
|
#pragma hdrstop
|
||
|
#include "trkwks.hxx"
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: Initialize
|
||
|
//
|
||
|
// Synopsis: Initialize CLogFileSector. This is called once for the object,
|
||
|
// not for every sector it touches.
|
||
|
//
|
||
|
// Inputs: [cSkipSectors] (in)
|
||
|
// The number of sectors at the front of the file we're not
|
||
|
// allowed to touch.
|
||
|
// [cbSector] (in)
|
||
|
// The size of a disk sector.
|
||
|
//
|
||
|
// Outputs: None
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
|
||
|
void
|
||
|
CLogFileSector::Initialize( ULONG cSkipSectors, ULONG cbSector )
|
||
|
{
|
||
|
// Is the sector large enough?
|
||
|
|
||
|
if( sizeof(LogEntry) + sizeof(LogEntryHeader) > cbSector )
|
||
|
{
|
||
|
TrkLog(( TRKDBG_ERROR, TEXT("Sector size isn't large enough for log sectors") ));
|
||
|
TrkRaiseWin32Error( ERROR_BAD_CONFIGURATION );
|
||
|
}
|
||
|
|
||
|
// Allocate enough memory to hold a single sector. This is the
|
||
|
// only alloc in the class.
|
||
|
|
||
|
if( NULL != _pvSector && _cbSector != cbSector )
|
||
|
{
|
||
|
delete [] _pvSector;
|
||
|
_pvSector = NULL;
|
||
|
}
|
||
|
|
||
|
if( NULL == _pvSector )
|
||
|
{
|
||
|
_pvSector = static_cast<void*>( new BYTE[ cbSector ] );
|
||
|
if( NULL == _pvSector )
|
||
|
{
|
||
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't alloc a sector in CLogFileSector")));
|
||
|
TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// The entry header is at the end of every sector, always in the same place.
|
||
|
|
||
|
_pEntryHeader = reinterpret_cast<LogEntryHeader*>( reinterpret_cast<BYTE*>(_pvSector)
|
||
|
+
|
||
|
cbSector
|
||
|
-
|
||
|
sizeof(*_pEntryHeader) );
|
||
|
|
||
|
// Initialize the flags
|
||
|
|
||
|
_fValid = FALSE;
|
||
|
_fDirty = FALSE;
|
||
|
|
||
|
// Save the inputs
|
||
|
|
||
|
_cSkipSectors = cSkipSectors;
|
||
|
_cbSector = cbSector;
|
||
|
|
||
|
// Calculate how many entries can fit in a sector.
|
||
|
|
||
|
_cEntriesPerSector = ( _cbSector - sizeof(*_pEntryHeader) ) / sizeof(LogEntry);
|
||
|
|
||
|
} // CLogFileSector::Initialize
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: UnInitialize
|
||
|
//
|
||
|
// Synopsis: Free resources and re-initialize data members.
|
||
|
//
|
||
|
// Inputs: None
|
||
|
//
|
||
|
// Output: None
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
|
||
|
void
|
||
|
CLogFileSector::UnInitialize()
|
||
|
{
|
||
|
if( NULL != _pvSector )
|
||
|
{
|
||
|
if( IsOpen() )
|
||
|
OnClose();
|
||
|
|
||
|
void *pvSector = _pvSector;
|
||
|
_pvSector = NULL;
|
||
|
delete [] pvSector;
|
||
|
}
|
||
|
|
||
|
_fValid = FALSE;
|
||
|
|
||
|
} // CLogFileSector::UnInitialize
|
||
|
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: LoadSector
|
||
|
//
|
||
|
// Synopsis: Load a data sector from the log file.
|
||
|
//
|
||
|
// Inputs: [ilogEntry] (in)
|
||
|
// The index of the entry to load. This is a 0-relative
|
||
|
// index, relative to the first data sector in the file.
|
||
|
//
|
||
|
// Output: None
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
|
||
|
void
|
||
|
CLogFileSector::LoadSector( LogIndex ilogEntry )
|
||
|
{
|
||
|
ULONG iSector = 0;
|
||
|
LARGE_INTEGER liOffset;
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
|
||
|
TrkAssert( _pvSector );
|
||
|
TrkAssert( NULL != _hFile );
|
||
|
|
||
|
// We can skip everything if the correct sector is already loaded
|
||
|
|
||
|
if( !_fValid
|
||
|
||
|
||
|
ilogEntry < _ilogCurrentFirst
|
||
|
||
|
||
|
ilogEntry >= _ilogCurrentFirst + _cEntriesPerSector
|
||
|
)
|
||
|
{
|
||
|
// No, the sector isn't currently loaded.
|
||
|
|
||
|
ULONG cbRead = 0;
|
||
|
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
|
||
|
// If the current sector is dirty, flush it now, because we're
|
||
|
// about to lose it.
|
||
|
|
||
|
Flush();
|
||
|
|
||
|
// Which sector contains this log entry?
|
||
|
|
||
|
iSector = ilogEntry / _cEntriesPerSector + _cSkipSectors;
|
||
|
|
||
|
// What is the byte index of this sector?
|
||
|
|
||
|
liOffset.QuadPart = iSector * _cbSector;
|
||
|
|
||
|
// Read the sector
|
||
|
|
||
|
status = NtReadFile( _hFile, NULL, NULL, NULL,
|
||
|
&IoStatusBlock, _pvSector, _cbSector,
|
||
|
&liOffset, NULL );
|
||
|
|
||
|
|
||
|
if ( STATUS_PENDING == status )
|
||
|
{
|
||
|
// Wait for the operation to complete. The resulting status
|
||
|
// will be put in the IOSB
|
||
|
|
||
|
status = NtWaitForSingleObject( _hFile, FALSE, NULL );
|
||
|
|
||
|
if( NT_SUCCESS(status) )
|
||
|
status = IoStatusBlock.Status;
|
||
|
}
|
||
|
|
||
|
// Validate the results of the read
|
||
|
|
||
|
if ( !NT_SUCCESS(status) )
|
||
|
{
|
||
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't read data sector from log file")));
|
||
|
if(STATUS_VOLUME_DISMOUNTED == status)
|
||
|
{
|
||
|
TrkRaiseNtStatus(status);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TrkRaiseException( TRK_E_CORRUPT_LOG );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( NULL != g_ptrkwks ) // NULL when called by dltadmin.exe
|
||
|
g_ptrkwks->_entropy.Put();
|
||
|
|
||
|
if( _cbSector != IoStatusBlock.Information )
|
||
|
{
|
||
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't read enough data bytes from log (%d)"),
|
||
|
IoStatusBlock.Information ));
|
||
|
TrkRaiseException( TRK_E_CORRUPT_LOG );
|
||
|
}
|
||
|
|
||
|
// Remember what sector we've got (we keep the index of the first
|
||
|
// entry in this sector).
|
||
|
|
||
|
_ilogCurrentFirst = ( iSector - _cSkipSectors ) * _cEntriesPerSector;
|
||
|
_fValid = TRUE;
|
||
|
|
||
|
} // if( !_fValid ...
|
||
|
} // CLogFileSector::LoadSector
|
||
|
|
||
|
|
||
|
|
||
|
//+----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: Flush
|
||
|
//
|
||
|
// Synopsis: Flush the current sector (if there is one) to the underlying
|
||
|
// log file.
|
||
|
//
|
||
|
// Inputs: None
|
||
|
//
|
||
|
// Output: None
|
||
|
//
|
||
|
//+----------------------------------------------------------------------------
|
||
|
|
||
|
void
|
||
|
CLogFileSector::Flush( )
|
||
|
{
|
||
|
NTSTATUS status = STATUS_SUCCESS;
|
||
|
RaiseIfNotOpen();
|
||
|
|
||
|
// Is the sector loaded & dirty?
|
||
|
|
||
|
if( _fValid && _fDirty )
|
||
|
{
|
||
|
// Yes, we need to flush it
|
||
|
|
||
|
ULONG iSector = 0;
|
||
|
LARGE_INTEGER liOffset;
|
||
|
IO_STATUS_BLOCK IoStatusBlock;
|
||
|
|
||
|
TrkAssert( NULL != _hFile );
|
||
|
|
||
|
// Which sector contains the currently-loaded log entry?
|
||
|
|
||
|
iSector = _ilogCurrentFirst / _cEntriesPerSector + _cSkipSectors;
|
||
|
|
||
|
// Write the sector to the file
|
||
|
|
||
|
liOffset.QuadPart = iSector * _cbSector;
|
||
|
|
||
|
|
||
|
status = NtWriteFile( _hFile, NULL, NULL, NULL,
|
||
|
&IoStatusBlock, _pvSector, _cbSector,
|
||
|
&liOffset, NULL );
|
||
|
|
||
|
if ( STATUS_PENDING == status )
|
||
|
{
|
||
|
// Wait for the operation to complete. The resulting status
|
||
|
// will be put in the IOSB
|
||
|
|
||
|
status = NtWaitForSingleObject( _hFile, FALSE, NULL );
|
||
|
|
||
|
if( NT_SUCCESS(status) )
|
||
|
status = IoStatusBlock.Status;
|
||
|
}
|
||
|
|
||
|
// Validate the results of the write
|
||
|
|
||
|
if ( !NT_SUCCESS(status) )
|
||
|
{
|
||
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't write data to the log file")));
|
||
|
TrkRaiseNtStatus( status );
|
||
|
}
|
||
|
|
||
|
if( _cbSector != IoStatusBlock.Information )
|
||
|
{
|
||
|
TrkLog((TRKDBG_ERROR, TEXT("Couldn't write enough data bytes to the log (%d)"),
|
||
|
IoStatusBlock.Information ));
|
||
|
TrkRaiseException( TRK_E_CORRUPT_LOG );
|
||
|
}
|
||
|
|
||
|
if( NULL != g_ptrkwks ) // NULL when called by dltadmin.exe
|
||
|
g_ptrkwks->_entropy.Put();
|
||
|
|
||
|
SetDirty( FALSE );
|
||
|
|
||
|
} // if( _fValid && _fDirty )
|
||
|
|
||
|
} // CLogFileSector::Flush
|
||
|
|