// 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( 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( reinterpret_cast(_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