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.

304 lines
8.0 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+----------------------------------------------------------------------------
  3. //
  4. // File: LogSect.cxx
  5. //
  6. // Classes: CLogFileSector
  7. //
  8. //+----------------------------------------------------------------------------
  9. #include "pch.cxx"
  10. #pragma hdrstop
  11. #include "trkwks.hxx"
  12. //+----------------------------------------------------------------------------
  13. //
  14. // Method: Initialize
  15. //
  16. // Synopsis: Initialize CLogFileSector. This is called once for the object,
  17. // not for every sector it touches.
  18. //
  19. // Inputs: [cSkipSectors] (in)
  20. // The number of sectors at the front of the file we're not
  21. // allowed to touch.
  22. // [cbSector] (in)
  23. // The size of a disk sector.
  24. //
  25. // Outputs: None
  26. //
  27. //+----------------------------------------------------------------------------
  28. void
  29. CLogFileSector::Initialize( ULONG cSkipSectors, ULONG cbSector )
  30. {
  31. // Is the sector large enough?
  32. if( sizeof(LogEntry) + sizeof(LogEntryHeader) > cbSector )
  33. {
  34. TrkLog(( TRKDBG_ERROR, TEXT("Sector size isn't large enough for log sectors") ));
  35. TrkRaiseWin32Error( ERROR_BAD_CONFIGURATION );
  36. }
  37. // Allocate enough memory to hold a single sector. This is the
  38. // only alloc in the class.
  39. if( NULL != _pvSector && _cbSector != cbSector )
  40. {
  41. delete [] _pvSector;
  42. _pvSector = NULL;
  43. }
  44. if( NULL == _pvSector )
  45. {
  46. _pvSector = static_cast<void*>( new BYTE[ cbSector ] );
  47. if( NULL == _pvSector )
  48. {
  49. TrkLog((TRKDBG_ERROR, TEXT("Couldn't alloc a sector in CLogFileSector")));
  50. TrkRaiseWin32Error( ERROR_NOT_ENOUGH_MEMORY );
  51. }
  52. }
  53. // The entry header is at the end of every sector, always in the same place.
  54. _pEntryHeader = reinterpret_cast<LogEntryHeader*>( reinterpret_cast<BYTE*>(_pvSector)
  55. +
  56. cbSector
  57. -
  58. sizeof(*_pEntryHeader) );
  59. // Initialize the flags
  60. _fValid = FALSE;
  61. _fDirty = FALSE;
  62. // Save the inputs
  63. _cSkipSectors = cSkipSectors;
  64. _cbSector = cbSector;
  65. // Calculate how many entries can fit in a sector.
  66. _cEntriesPerSector = ( _cbSector - sizeof(*_pEntryHeader) ) / sizeof(LogEntry);
  67. } // CLogFileSector::Initialize
  68. //+----------------------------------------------------------------------------
  69. //
  70. // Method: UnInitialize
  71. //
  72. // Synopsis: Free resources and re-initialize data members.
  73. //
  74. // Inputs: None
  75. //
  76. // Output: None
  77. //
  78. //+----------------------------------------------------------------------------
  79. void
  80. CLogFileSector::UnInitialize()
  81. {
  82. if( NULL != _pvSector )
  83. {
  84. if( IsOpen() )
  85. OnClose();
  86. void *pvSector = _pvSector;
  87. _pvSector = NULL;
  88. delete [] pvSector;
  89. }
  90. _fValid = FALSE;
  91. } // CLogFileSector::UnInitialize
  92. //+----------------------------------------------------------------------------
  93. //
  94. // Method: LoadSector
  95. //
  96. // Synopsis: Load a data sector from the log file.
  97. //
  98. // Inputs: [ilogEntry] (in)
  99. // The index of the entry to load. This is a 0-relative
  100. // index, relative to the first data sector in the file.
  101. //
  102. // Output: None
  103. //
  104. //+----------------------------------------------------------------------------
  105. void
  106. CLogFileSector::LoadSector( LogIndex ilogEntry )
  107. {
  108. ULONG iSector = 0;
  109. LARGE_INTEGER liOffset;
  110. NTSTATUS status = STATUS_SUCCESS;
  111. TrkAssert( _pvSector );
  112. TrkAssert( NULL != _hFile );
  113. // We can skip everything if the correct sector is already loaded
  114. if( !_fValid
  115. ||
  116. ilogEntry < _ilogCurrentFirst
  117. ||
  118. ilogEntry >= _ilogCurrentFirst + _cEntriesPerSector
  119. )
  120. {
  121. // No, the sector isn't currently loaded.
  122. ULONG cbRead = 0;
  123. IO_STATUS_BLOCK IoStatusBlock;
  124. // If the current sector is dirty, flush it now, because we're
  125. // about to lose it.
  126. Flush();
  127. // Which sector contains this log entry?
  128. iSector = ilogEntry / _cEntriesPerSector + _cSkipSectors;
  129. // What is the byte index of this sector?
  130. liOffset.QuadPart = iSector * _cbSector;
  131. // Read the sector
  132. status = NtReadFile( _hFile, NULL, NULL, NULL,
  133. &IoStatusBlock, _pvSector, _cbSector,
  134. &liOffset, NULL );
  135. if ( STATUS_PENDING == status )
  136. {
  137. // Wait for the operation to complete. The resulting status
  138. // will be put in the IOSB
  139. status = NtWaitForSingleObject( _hFile, FALSE, NULL );
  140. if( NT_SUCCESS(status) )
  141. status = IoStatusBlock.Status;
  142. }
  143. // Validate the results of the read
  144. if ( !NT_SUCCESS(status) )
  145. {
  146. TrkLog((TRKDBG_ERROR, TEXT("Couldn't read data sector from log file")));
  147. if(STATUS_VOLUME_DISMOUNTED == status)
  148. {
  149. TrkRaiseNtStatus(status);
  150. }
  151. else
  152. {
  153. TrkRaiseException( TRK_E_CORRUPT_LOG );
  154. }
  155. }
  156. if( NULL != g_ptrkwks ) // NULL when called by dltadmin.exe
  157. g_ptrkwks->_entropy.Put();
  158. if( _cbSector != IoStatusBlock.Information )
  159. {
  160. TrkLog((TRKDBG_ERROR, TEXT("Couldn't read enough data bytes from log (%d)"),
  161. IoStatusBlock.Information ));
  162. TrkRaiseException( TRK_E_CORRUPT_LOG );
  163. }
  164. // Remember what sector we've got (we keep the index of the first
  165. // entry in this sector).
  166. _ilogCurrentFirst = ( iSector - _cSkipSectors ) * _cEntriesPerSector;
  167. _fValid = TRUE;
  168. } // if( !_fValid ...
  169. } // CLogFileSector::LoadSector
  170. //+----------------------------------------------------------------------------
  171. //
  172. // Method: Flush
  173. //
  174. // Synopsis: Flush the current sector (if there is one) to the underlying
  175. // log file.
  176. //
  177. // Inputs: None
  178. //
  179. // Output: None
  180. //
  181. //+----------------------------------------------------------------------------
  182. void
  183. CLogFileSector::Flush( )
  184. {
  185. NTSTATUS status = STATUS_SUCCESS;
  186. RaiseIfNotOpen();
  187. // Is the sector loaded & dirty?
  188. if( _fValid && _fDirty )
  189. {
  190. // Yes, we need to flush it
  191. ULONG iSector = 0;
  192. LARGE_INTEGER liOffset;
  193. IO_STATUS_BLOCK IoStatusBlock;
  194. TrkAssert( NULL != _hFile );
  195. // Which sector contains the currently-loaded log entry?
  196. iSector = _ilogCurrentFirst / _cEntriesPerSector + _cSkipSectors;
  197. // Write the sector to the file
  198. liOffset.QuadPart = iSector * _cbSector;
  199. status = NtWriteFile( _hFile, NULL, NULL, NULL,
  200. &IoStatusBlock, _pvSector, _cbSector,
  201. &liOffset, NULL );
  202. if ( STATUS_PENDING == status )
  203. {
  204. // Wait for the operation to complete. The resulting status
  205. // will be put in the IOSB
  206. status = NtWaitForSingleObject( _hFile, FALSE, NULL );
  207. if( NT_SUCCESS(status) )
  208. status = IoStatusBlock.Status;
  209. }
  210. // Validate the results of the write
  211. if ( !NT_SUCCESS(status) )
  212. {
  213. TrkLog((TRKDBG_ERROR, TEXT("Couldn't write data to the log file")));
  214. TrkRaiseNtStatus( status );
  215. }
  216. if( _cbSector != IoStatusBlock.Information )
  217. {
  218. TrkLog((TRKDBG_ERROR, TEXT("Couldn't write enough data bytes to the log (%d)"),
  219. IoStatusBlock.Information ));
  220. TrkRaiseException( TRK_E_CORRUPT_LOG );
  221. }
  222. if( NULL != g_ptrkwks ) // NULL when called by dltadmin.exe
  223. g_ptrkwks->_entropy.Put();
  224. SetDirty( FALSE );
  225. } // if( _fValid && _fDirty )
  226. } // CLogFileSector::Flush