Leaked source code of windows server 2003
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.

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