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.

692 lines
17 KiB

  1. /************************************************************************
  2. Copyright (c) 2000 - 2000 Microsoft Corporation
  3. Module Name :
  4. metadata.cpp
  5. Abstract :
  6. Main code for reading and writting to the metadata.
  7. Author :
  8. Revision History :
  9. NOTES:
  10. For robustness, the code preallocates disk space at the begining of a
  11. change which might have a large impact on the metadata file size. This
  12. preallocation eliminates most of the errors which can occure during the serialize
  13. operation. After serializing, metedata files are shrunk to the size used. The
  14. metadata files are not expanded for operations such as Resume which won't have
  15. a large effect on the file sizes. Instead a 4K pad is maintained at the end for
  16. these operations to use.
  17. Several of the check in the code can be clasified as paranoia checks.
  18. ***********************************************************************/
  19. #include "stdafx.h"
  20. #include <malloc.h>
  21. #include <sddl.h>
  22. #include <limits>
  23. #if !defined(BITS_V12_ON_NT4)
  24. #include "metadata.tmh"
  25. #endif
  26. void BITSSetEndOfFile( HANDLE File )
  27. {
  28. if ( !SetEndOfFile( File ) )
  29. {
  30. HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
  31. LogError( "SetEndOfFile failed, error %!winerr!", Hr );
  32. throw ComError( Hr );
  33. }
  34. }
  35. INT64 BITSSetFilePointer(
  36. HANDLE File,
  37. INT64 Offset,
  38. DWORD MoveMethod
  39. )
  40. {
  41. LARGE_INTEGER LargeIntegerOffset;
  42. LargeIntegerOffset.QuadPart = Offset;
  43. LARGE_INTEGER LargeIntegerNewPointer;
  44. if ( !SetFilePointerEx( File, LargeIntegerOffset, &LargeIntegerNewPointer, MoveMethod ) )
  45. {
  46. HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
  47. LogError( "SetFilePointerEx failed, error %!winerr!", Hr );
  48. throw ComError( Hr );
  49. }
  50. return LargeIntegerNewPointer.QuadPart;
  51. }
  52. INT64 BITSGetFileSize( HANDLE File )
  53. {
  54. LARGE_INTEGER LargeIntegerSize;
  55. if ( !GetFileSizeEx( File, &LargeIntegerSize ) )
  56. {
  57. HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
  58. LogError( "GetFileSize failed, error %!winerr!", Hr );
  59. throw ComError( Hr );
  60. }
  61. return LargeIntegerSize.QuadPart;
  62. }
  63. void BITSFlushFileBuffers( HANDLE File )
  64. {
  65. if ( !FlushFileBuffers( File ) )
  66. {
  67. HRESULT Hr = HRESULT_FROM_WIN32( GetLastError() );
  68. LogError( "FlushFileBuffers failed, error %!winerr!", Hr );
  69. throw ComError( Hr );
  70. }
  71. }
  72. bool
  73. printable( char c )
  74. {
  75. if ( c < 32 )
  76. {
  77. return false;
  78. }
  79. if ( c > 126 )
  80. {
  81. return false;
  82. }
  83. return true;
  84. }
  85. void
  86. DumpBuffer(
  87. void * Buffer,
  88. unsigned Length
  89. )
  90. {
  91. if( false == LogLevelEnabled( LogFlagSerialize ) )
  92. {
  93. return;
  94. }
  95. const BYTES_PER_LINE = 16;
  96. unsigned char FAR *p = (unsigned char FAR *) Buffer;
  97. //
  98. // 3 chars per byte for hex display, plus an extra space every 4 bytes,
  99. // plus a byte for the printable representation, plus the \0.
  100. //
  101. char Outbuf[BYTES_PER_LINE*3+BYTES_PER_LINE/4+BYTES_PER_LINE+1];
  102. Outbuf[0] = 0;
  103. Outbuf[sizeof(Outbuf)-1] = 0;
  104. char * HexDigits = "0123456789abcdef";
  105. unsigned Index;
  106. for ( unsigned Offset=0; Offset < Length; Offset++ )
  107. {
  108. Index = Offset % BYTES_PER_LINE;
  109. if ( Index == 0 )
  110. {
  111. LogSerial( " %s", Outbuf);
  112. memset(Outbuf, ' ', sizeof(Outbuf)-1);
  113. }
  114. Outbuf[Index*3+Index/4 ] = HexDigits[p[Offset] / 16];
  115. Outbuf[Index*3+Index/4+1] = HexDigits[p[Offset] % 16];
  116. Outbuf[BYTES_PER_LINE*3+BYTES_PER_LINE/4+Index] = printable(p[Offset]) ? p[Offset] : '.';
  117. }
  118. LogSerial( " %s", Outbuf);
  119. }
  120. // All of these methods and functions throw a ComError
  121. void SafeWriteFile( HANDLE hFile, void *pBuffer, DWORD dwSize )
  122. {
  123. DWORD dwBytesWritten;
  124. LogSerial("safe-write: writing file data, %d bytes:", dwSize );
  125. DumpBuffer( pBuffer, dwSize );
  126. BOOL bResult =
  127. WriteFile( hFile, pBuffer, dwSize, &dwBytesWritten, NULL );
  128. if ( !bResult ) throw ComError( HRESULT_FROM_WIN32(GetLastError()) );
  129. if ( dwBytesWritten != dwSize )
  130. throw ComError( HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) );
  131. }
  132. void SafeReadFile( HANDLE hFile, void *pBuffer, DWORD dwSize )
  133. {
  134. DWORD dwBytesRead;
  135. LogSerial("safe-read: reading %d bytes", dwSize );
  136. BOOL bResult =
  137. ReadFile( hFile, pBuffer, dwSize, &dwBytesRead, NULL );
  138. HRESULT Hr = ( bResult ) ? S_OK : HRESULT_FROM_WIN32( GetLastError() );
  139. DumpBuffer( pBuffer, dwBytesRead );
  140. if ( !bResult )
  141. {
  142. LogSerial("safe-read: only %d bytes read: %!winerr!", dwBytesRead, Hr );
  143. throw ComError( Hr );
  144. }
  145. if ( dwBytesRead != dwSize )
  146. throw ComError( HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) );
  147. }
  148. void SafeWriteStringHandle( HANDLE hFile, StringHandle & str )
  149. {
  150. DWORD dwStringSize = str.Size() + 1;
  151. SafeWriteFile( hFile, dwStringSize );
  152. SafeWriteFile( hFile, (void*)(const WCHAR*) str, dwStringSize * sizeof(wchar_t) );
  153. }
  154. StringHandle SafeReadStringHandle( HANDLE hFile )
  155. {
  156. DWORD dwStringSize;
  157. bool bResult;
  158. SafeReadFile( hFile, &dwStringSize, sizeof(dwStringSize) );
  159. auto_ptr<wchar_t> buf( new wchar_t[ dwStringSize ] );
  160. SafeReadFile( hFile, buf.get(), dwStringSize * sizeof(wchar_t) );
  161. if ( buf.get()[ dwStringSize-1 ] != L'\0' )
  162. throw ComError( HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) );
  163. return StringHandle( buf.get() );
  164. }
  165. void SafeWriteFile( HANDLE hFile, WCHAR * str )
  166. {
  167. bool bString = (NULL != str );
  168. SafeWriteFile( hFile, bString );
  169. if ( bString )
  170. {
  171. DWORD dwStringSize = (DWORD)wcslen(str) + 1;
  172. SafeWriteFile( hFile, dwStringSize );
  173. SafeWriteFile( hFile, (void*)str, dwStringSize * sizeof(WCHAR) );
  174. }
  175. }
  176. void SafeReadFile( HANDLE hFile, WCHAR ** pStr )
  177. {
  178. bool bString;
  179. SafeReadFile( hFile, &bString );
  180. if ( !bString )
  181. {
  182. *pStr = NULL;
  183. return;
  184. }
  185. DWORD dwStringSize;
  186. SafeReadFile( hFile, &dwStringSize );
  187. *pStr = new WCHAR[ dwStringSize ];
  188. if ( !*pStr )
  189. throw ComError( E_OUTOFMEMORY );
  190. try
  191. {
  192. SafeReadFile( hFile, (void*)*pStr, dwStringSize * sizeof(WCHAR));
  193. if ( (*pStr)[ dwStringSize - 1] != L'\0' )
  194. throw ComError( HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) );
  195. }
  196. catch ( ComError Error )
  197. {
  198. delete[] *pStr;
  199. *pStr = NULL;
  200. throw;
  201. }
  202. }
  203. void SafeWriteSid( HANDLE hFile, SidHandle & sid )
  204. {
  205. DWORD length;
  206. LPWSTR str = NULL;
  207. try
  208. {
  209. if ( !ConvertSidToStringSid( sid.get(), &str) )
  210. {
  211. throw ComError( HRESULT_FROM_WIN32( GetLastError()));
  212. }
  213. length = 1+wcslen( str );
  214. SafeWriteFile( hFile, length );
  215. SafeWriteFile( hFile, str, length * sizeof(wchar_t));
  216. LocalFree( str );
  217. }
  218. catch ( ComError Error )
  219. {
  220. if ( str )
  221. {
  222. LocalFree( str );
  223. }
  224. throw;
  225. }
  226. }
  227. void SafeReadSid( HANDLE hFile, SidHandle & sid )
  228. {
  229. DWORD dwStringSize;
  230. bool bResult;
  231. SafeReadFile( hFile, &dwStringSize, sizeof(dwStringSize) );
  232. auto_ptr<wchar_t> buf( new wchar_t[ dwStringSize ] );
  233. SafeReadFile( hFile, buf.get(), dwStringSize * sizeof(wchar_t) );
  234. if ( buf.get()[ dwStringSize-1 ] != L'\0' )
  235. throw ComError( HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) );
  236. PSID TempSid;
  237. if (!ConvertStringSidToSid( buf.get(), &TempSid ))
  238. {
  239. if (GetLastError() == ERROR_INVALID_SID)
  240. {
  241. THROW_HRESULT( HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) );
  242. }
  243. THROW_HRESULT( HRESULT_FROM_WIN32( GetLastError() ));
  244. }
  245. try
  246. {
  247. sid = DuplicateSid( TempSid );
  248. LocalFree( TempSid );
  249. }
  250. catch( ComError err )
  251. {
  252. LocalFree( TempSid );
  253. throw;
  254. }
  255. }
  256. int SafeReadGuidChoice( HANDLE hFile, const GUID * guids[] )
  257. {
  258. GUID guid;
  259. SafeReadFile( hFile, &guid );
  260. int i = 0;
  261. for ( i=0; guids[i] != NULL; ++i )
  262. {
  263. if ( guid == *guids[i] )
  264. {
  265. return i;
  266. }
  267. }
  268. throw ComError( HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) );
  269. }
  270. void SafeWriteBlockBegin( HANDLE hFile, GUID BlockGuid )
  271. {
  272. SafeWriteFile( hFile, BlockGuid );
  273. }
  274. void SafeWriteBlockEnd( HANDLE hFile, GUID BlockGuid )
  275. {
  276. SafeWriteFile( hFile, BlockGuid );
  277. }
  278. void SafeReadBlockBegin( HANDLE hFile, GUID BlockGuid )
  279. {
  280. GUID FileBlockGuid;
  281. SafeReadFile( hFile, &FileBlockGuid );
  282. if ( memcmp( &FileBlockGuid, &BlockGuid, sizeof(GUID)) != 0 )
  283. throw ComError( HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) );
  284. }
  285. void SafeReadBlockEnd( HANDLE hFile, GUID BlockGuid )
  286. {
  287. GUID FileBlockGuid;
  288. SafeReadFile( hFile, &FileBlockGuid );
  289. if ( memcmp( &FileBlockGuid, &BlockGuid, sizeof(GUID)) != 0 )
  290. throw ComError( HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) );
  291. }
  292. // {2B196AF5-007C-438f-8D12-1CFCA4CC9B76}
  293. static const GUID QmgrStateStorageGUID =
  294. { 0x2b196af5, 0x7c, 0x438f, { 0x8d, 0x12, 0x1c, 0xfc, 0xa4, 0xcc, 0x9b, 0x76 } };
  295. CQmgrStateFiles::CQmgrStateFiles()
  296. {
  297. for ( unsigned int i = 0; i < 2; i++ )
  298. {
  299. m_FileNames[i] = GetNameFromIndex(i);
  300. m_Files[i] = OpenMetadataFile( m_FileNames[i] );
  301. m_ExpandSize[i] = 0;
  302. m_OriginalFileSizes[i] = 0;
  303. }
  304. HRESULT hResult =
  305. GetRegDWordValue( C_QMGR_STATE_INDEX, &m_CurrentIndex);
  306. if ( !SUCCEEDED(hResult) )
  307. {
  308. m_CurrentIndex = 0;
  309. }
  310. }
  311. auto_ptr<WCHAR> CQmgrStateFiles::GetNameFromIndex( DWORD dwIndex )
  312. {
  313. using namespace std;
  314. TCHAR Template[] = _T("%sqmgr%u.dat");
  315. SIZE_T StringSize = _tcslen(g_GlobalInfo->m_QmgrDirectory)
  316. + RTL_NUMBER_OF( Template )
  317. + numeric_limits<unsigned long>::digits10;
  318. auto_ptr<TCHAR> ReturnString(new TCHAR[StringSize] );
  319. THROW_HRESULT( StringCchPrintf( ReturnString.get(), StringSize, Template, g_GlobalInfo->m_QmgrDirectory, dwIndex ));
  320. return ReturnString;
  321. }
  322. auto_FILE_HANDLE CQmgrStateFiles::OpenMetadataFile( auto_ptr<WCHAR> FileName )
  323. {
  324. SECURITY_ATTRIBUTES SecurityAttributes;
  325. SecurityAttributes.nLength = sizeof(SecurityAttributes);
  326. SecurityAttributes.lpSecurityDescriptor = (void*)g_GlobalInfo->m_MetadataSecurityDescriptor;
  327. SecurityAttributes.bInheritHandle = FALSE;
  328. HANDLE hFileHandle =
  329. CreateFile( FileName.get(),
  330. GENERIC_READ | GENERIC_WRITE,
  331. 0,
  332. &SecurityAttributes,
  333. OPEN_ALWAYS,
  334. FILE_ATTRIBUTE_NORMAL,
  335. NULL );
  336. if ( INVALID_HANDLE_VALUE == hFileHandle )
  337. throw ComError( HRESULT_FROM_WIN32(GetLastError()) );
  338. auto_FILE_HANDLE FileHandle( hFileHandle );
  339. // Ensure file size is at least METADATA_PADDING
  340. if ( BITSGetFileSize( hFileHandle ) < METADATA_PADDING )
  341. {
  342. BITSSetFilePointer( hFileHandle, METADATA_PADDING, FILE_BEGIN );
  343. BITSSetEndOfFile( hFileHandle );
  344. BITSSetFilePointer( hFileHandle, 0, FILE_BEGIN );
  345. }
  346. return FileHandle;
  347. }
  348. HANDLE CQmgrStateFiles::GetNextStateFile()
  349. {
  350. DWORD dwNextIndex = ( m_CurrentIndex + 1) % 2;
  351. HANDLE hFile = m_Files[ dwNextIndex ].get();
  352. BITSSetFilePointer( hFile, 0, FILE_BEGIN );
  353. return hFile;
  354. }
  355. void CQmgrStateFiles::UpdateStateFile()
  356. {
  357. DWORD OldCurrentIndex = m_CurrentIndex;
  358. DWORD NewCurrentIndex = ( m_CurrentIndex + 1) % 2;
  359. // Truncate the current file only if more then METADATA_PADDING remains
  360. HANDLE CurrentFileHandle = m_Files[ NewCurrentIndex ].get();
  361. INT64 CurrentPosition = BITSSetFilePointer( CurrentFileHandle, 0, FILE_CURRENT );
  362. INT64 CurrentFileSize = BITSGetFileSize( CurrentFileHandle );
  363. #if DBG
  364. // ASSERT( CurrentPosition <= ( m_OriginalFileSizes[ NewCurrentIndex ] + m_ExpandSize[ NewCurrentIndex ] ) );
  365. if (CurrentPosition > ( m_OriginalFileSizes[ NewCurrentIndex ] + m_ExpandSize[ NewCurrentIndex ] ) &&
  366. (m_OriginalFileSizes[ NewCurrentIndex ] > 0))
  367. {
  368. LogError("new idx %d, position %u, original size %u, expanded by %u",
  369. NewCurrentIndex,
  370. DWORD(CurrentPosition),
  371. DWORD(m_OriginalFileSizes[ NewCurrentIndex ]),
  372. DWORD(m_ExpandSize[ NewCurrentIndex ])
  373. );
  374. Log_Close();
  375. Sleep(30 * 1000);
  376. ASSERT( 0 && "BITS: encountered bug 483866");
  377. }
  378. #endif
  379. if ( ( CurrentFileSize - CurrentPosition ) > METADATA_PADDING )
  380. {
  381. BITSSetFilePointer( CurrentFileHandle, METADATA_PADDING, FILE_CURRENT );
  382. BITSSetEndOfFile( CurrentFileHandle );
  383. }
  384. BITSFlushFileBuffers( CurrentFileHandle );
  385. m_ExpandSize[ NewCurrentIndex ] = 0;
  386. m_OriginalFileSizes[ NewCurrentIndex ] = 0;
  387. HRESULT hResult = SetRegDWordValue( C_QMGR_STATE_INDEX, NewCurrentIndex);
  388. if ( !SUCCEEDED( hResult ) )
  389. throw ComError( hResult );
  390. m_CurrentIndex = NewCurrentIndex;
  391. //
  392. // Shrink the backup files if necessary
  393. //
  394. if ( m_ExpandSize[ OldCurrentIndex ] )
  395. {
  396. try
  397. {
  398. INT64 NewSize = BITSGetFileSize( m_Files[ NewCurrentIndex ].get() );
  399. if ( NewSize > m_OriginalFileSizes[ OldCurrentIndex ] )
  400. {
  401. BITSSetFilePointer( m_Files[ OldCurrentIndex ].get(), NewSize, FILE_BEGIN );
  402. BITSSetEndOfFile( m_Files[ OldCurrentIndex ].get() );
  403. }
  404. m_OriginalFileSizes[ OldCurrentIndex ] = 0;
  405. m_ExpandSize[ OldCurrentIndex ] = 0;
  406. }
  407. catch ( ComError Error )
  408. {
  409. LogError( "Unable to shrink file %u, error %!winerr!", OldCurrentIndex, Error.Error() );
  410. return;
  411. }
  412. }
  413. }
  414. HANDLE CQmgrStateFiles::GetCurrentStateFile()
  415. {
  416. HANDLE hFile = m_Files[ m_CurrentIndex ].get();
  417. BITSSetFilePointer( hFile, 0, FILE_BEGIN );
  418. return hFile;
  419. }
  420. void
  421. CQmgrStateFiles::ExtendMetadata( INT64 ExtendAmount )
  422. {
  423. //
  424. // Get the original file sizes
  425. //
  426. SIZE_T OriginalExpansion[2] =
  427. { m_ExpandSize[0], m_ExpandSize[1]};
  428. for ( unsigned int i=0; i < 2; i++ )
  429. {
  430. if ( !m_ExpandSize[i] )
  431. {
  432. m_OriginalFileSizes[i] = BITSGetFileSize( m_Files[i].get() );
  433. }
  434. }
  435. bool WasExpanded[2] = { false, false};
  436. try
  437. {
  438. for ( unsigned int i=0; i < 2; i++ )
  439. {
  440. BITSSetFilePointer( m_Files[i].get(), ExtendAmount, FILE_END );
  441. BITSSetEndOfFile( m_Files[i].get() );
  442. WasExpanded[i] = true;
  443. m_ExpandSize[i] += ExtendAmount;
  444. }
  445. }
  446. catch ( ComError Error )
  447. {
  448. LogError( "Unable to extend the size of the metadata files, error %!winerr!", Error.Error() );
  449. for ( unsigned int i=0; i < 2; i++ )
  450. {
  451. try
  452. {
  453. if ( WasExpanded[i] )
  454. {
  455. BITSSetFilePointer( m_Files[i].get(), -ExtendAmount, FILE_END );
  456. BITSSetEndOfFile( m_Files[i].get() );
  457. m_ExpandSize[i] = OriginalExpansion[i];
  458. }
  459. }
  460. catch ( ComError Error )
  461. {
  462. LogError( "Unable to reshrink file %u, error %!winerr!", i, Error.Error() );
  463. continue;
  464. }
  465. }
  466. throw;
  467. }
  468. }
  469. void
  470. CQmgrStateFiles::ShrinkMetadata()
  471. {
  472. for ( unsigned int i = 0; i < 2; i++ )
  473. {
  474. try
  475. {
  476. if ( m_ExpandSize[i] )
  477. {
  478. BITSSetFilePointer( m_Files[i].get(), m_OriginalFileSizes[i], FILE_BEGIN );
  479. BITSSetEndOfFile( m_Files[i].get() );
  480. m_ExpandSize[i] = 0;
  481. m_OriginalFileSizes[i] = 0;
  482. }
  483. }
  484. catch ( ComError Error )
  485. {
  486. LogError( "Unable to shrink file %u, error %!winerr!", i, Error.Error() );
  487. continue;
  488. }
  489. }
  490. }
  491. CQmgrReadStateFile::CQmgrReadStateFile( CQmgrStateFiles & StateFiles ) :
  492. m_StateFiles( StateFiles ),
  493. m_FileHandle( StateFiles.GetCurrentStateFile() )
  494. {
  495. // Validate the file
  496. SafeReadBlockBegin( m_FileHandle, QmgrStateStorageGUID );
  497. }
  498. void CQmgrReadStateFile::ValidateEndOfFile()
  499. {
  500. SafeReadBlockEnd( m_FileHandle, QmgrStateStorageGUID );
  501. }
  502. CQmgrWriteStateFile::CQmgrWriteStateFile( CQmgrStateFiles & StateFiles ) :
  503. m_StateFiles( StateFiles ),
  504. m_FileHandle( StateFiles.GetNextStateFile() )
  505. {
  506. SafeWriteBlockBegin( m_FileHandle, QmgrStateStorageGUID );
  507. }
  508. void CQmgrWriteStateFile::CommitFile()
  509. {
  510. SafeWriteBlockEnd( m_FileHandle, QmgrStateStorageGUID );
  511. m_StateFiles.UpdateStateFile();
  512. }