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.

1486 lines
39 KiB

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1997-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // LogSrc.cpp
  7. //
  8. // Description:
  9. // Logging utilities.
  10. //
  11. // Documentation:
  12. // Spec\Admin\Debugging.ppt
  13. //
  14. // Maintained By:
  15. // Galen Barbee (GalenB) 05-DEC-2000
  16. //
  17. // Note:
  18. // THRs and TW32s should NOT be used in this module because they
  19. // could cause an infinite loop.
  20. //
  21. //////////////////////////////////////////////////////////////////////////////
  22. // #include <Pch.h> // should be included by includer of this file
  23. #include <stdio.h>
  24. #include <StrSafe.h> // in case it isn't included by header file
  25. #include <windns.h>
  26. #include "Common.h"
  27. //****************************************************************************
  28. //****************************************************************************
  29. //
  30. // Logging Functions
  31. //
  32. // These are in both DEBUG and RETAIL.
  33. //
  34. //****************************************************************************
  35. //****************************************************************************
  36. //
  37. // Constants
  38. //
  39. static const int LOG_OUTPUT_BUFFER_SIZE = 1024;
  40. static const int TIMESTAMP_BUFFER_SIZE = 25;
  41. //
  42. // Globals
  43. //
  44. static CRITICAL_SECTION * g_pcsLogging = NULL;
  45. static HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
  46. static WCHAR g_szLogFilePath[ MAX_PATH ];
  47. //////////////////////////////////////////////////////////////////////////////
  48. //++
  49. //
  50. // PszLogFilePath
  51. //
  52. // Description:
  53. // Returns the log file path that is currently used by the wizard.
  54. //
  55. // Arguments:
  56. // None.
  57. //
  58. // Return Values:
  59. // LPCWSTR - The log file path that is currently used by the wizard
  60. //
  61. //--
  62. //////////////////////////////////////////////////////////////////////////////
  63. LPCWSTR
  64. PszLogFilePath( void )
  65. {
  66. return g_szLogFilePath;
  67. } //*** PszLogFilePath
  68. //////////////////////////////////////////////////////////////////////////////
  69. //++
  70. //
  71. // HrGetLogFilePath
  72. //
  73. // Description:
  74. // Takes in a directory path and appends module log file name to it and
  75. // returns the full log file path.
  76. //
  77. // Arguments:
  78. // pszPathIn - The directory where the log file will be created.
  79. // pszFilePathOut - Log file path.
  80. // pcchFilePathInout - Size of the log file path buffer.
  81. //
  82. // Return Values:
  83. // S_OK - Success
  84. // ERROR_MORE_DATA - If the output buffer is too small.
  85. // Other HRESULTs
  86. //
  87. //--
  88. //////////////////////////////////////////////////////////////////////////////
  89. HRESULT
  90. HrGetLogFilePath(
  91. const WCHAR * pszPathIn
  92. , WCHAR * pszFilePathOut
  93. , size_t * pcchFilePathInout
  94. , HINSTANCE hInstanceIn
  95. )
  96. {
  97. HRESULT hr = S_OK;
  98. WCHAR szModulePath[ MAX_PATH ];
  99. DWORD dwLen;
  100. LPWSTR psz;
  101. //
  102. // Create the directory tree.
  103. //
  104. dwLen = ExpandEnvironmentStringsW( pszPathIn, pszFilePathOut, static_cast< DWORD >( *pcchFilePathInout ) );
  105. if ( dwLen > *pcchFilePathInout )
  106. {
  107. hr = HRESULT_FROM_WIN32( ERROR_MORE_DATA );
  108. *pcchFilePathInout = dwLen;
  109. goto Cleanup;
  110. }
  111. hr = HrCreateDirectoryPath( pszFilePathOut );
  112. if ( FAILED( hr ) )
  113. {
  114. #if defined( DEBUG )
  115. if ( !( g_tfModule & mtfOUTPUTTODISK ) )
  116. {
  117. DebugMsg( "*ERROR* Failed to create directory tree %s", pszFilePathOut );
  118. } // if: not logging to disk
  119. #endif
  120. goto Cleanup;
  121. } // if: failed
  122. //
  123. // Add filename.
  124. //
  125. dwLen = GetModuleFileNameW( hInstanceIn, szModulePath, ARRAYSIZE( szModulePath ) );
  126. Assert( dwLen != 0 );
  127. // Replace extension.
  128. psz = wcsrchr( szModulePath, L'.' );
  129. Assert( psz != NULL );
  130. if ( psz == NULL )
  131. {
  132. hr = E_POINTER;
  133. goto Cleanup;
  134. }
  135. THR( StringCchCopyW( psz, ( psz - szModulePath ) / sizeof( *psz ), L".log" ) );
  136. // Copy resulting filename to output buffer.
  137. psz = wcsrchr( szModulePath, L'\\' );
  138. Assert( psz != NULL );
  139. if ( psz == NULL )
  140. {
  141. hr = E_POINTER;
  142. goto Cleanup;
  143. }
  144. THR( StringCchCatW( pszFilePathOut, *pcchFilePathInout, psz ) );
  145. Cleanup:
  146. return hr;
  147. } //*** HrGetLogFilePath
  148. //////////////////////////////////////////////////////////////////////////////
  149. //++
  150. //
  151. // FormatTimeStamp
  152. //
  153. // Description:
  154. // Format a string from the given time stamp.
  155. //
  156. // Arguments:
  157. // pTimeStampIn
  158. // The time stamp to format.
  159. //
  160. // pszTextOut
  161. // A pointer to a buffer that receives the text. The caller must
  162. // provide this buffer--the argument may not be null.
  163. //
  164. // cchTextIn
  165. // The size of pszTextOut in characters.
  166. //
  167. // Return Values:
  168. // None.
  169. //
  170. //--
  171. //////////////////////////////////////////////////////////////////////////////
  172. static
  173. inline
  174. void
  175. FormatTimeStamp(
  176. const SYSTEMTIME * pTimeStampIn
  177. , LPWSTR pszTextOut
  178. , size_t cchTextIn
  179. )
  180. {
  181. Assert( pTimeStampIn != NULL );
  182. Assert( pszTextOut != NULL );
  183. THR( StringCchPrintfW(
  184. pszTextOut
  185. , cchTextIn
  186. , L"%04u-%02u-%02u %02u:%02u:%02u.%03u"
  187. , pTimeStampIn->wYear
  188. , pTimeStampIn->wMonth
  189. , pTimeStampIn->wDay
  190. , pTimeStampIn->wHour
  191. , pTimeStampIn->wMinute
  192. , pTimeStampIn->wSecond
  193. , pTimeStampIn->wMilliseconds
  194. ) );
  195. } //*** FormatTimeStamp
  196. //////////////////////////////////////////////////////////////////////////////
  197. //++
  198. //
  199. // WideCharToUTF8
  200. //
  201. // Description:
  202. // Convert a wide character string to a UTF-8 encoded narrow string.
  203. //
  204. // Arguments:
  205. // pwszSourceIn - The string to convert.
  206. // cchDestIn - The maximum number of characters the destination can hold.
  207. // paszDestOut - The destination for the converted string.
  208. //
  209. // Return Values:
  210. // The number of characters in the converted string.
  211. //
  212. //--
  213. //////////////////////////////////////////////////////////////////////////////
  214. static
  215. inline
  216. size_t
  217. WideCharToUTF8(
  218. LPCWSTR pwszSourceIn
  219. , size_t cchDestIn
  220. , LPSTR paszDestOut
  221. )
  222. {
  223. Assert( pwszSourceIn != NULL );
  224. Assert( paszDestOut != NULL );
  225. size_t cchUTF8 = 0;
  226. cchUTF8 = WideCharToMultiByte(
  227. CP_UTF8
  228. , 0 // flags, must be zero for utf8
  229. , pwszSourceIn
  230. , -1 // calculate length automatically
  231. , paszDestOut
  232. , static_cast< int >( cchDestIn )
  233. , NULL // default character, must be null for utf8
  234. , NULL // default character used flag, must be null for utf8
  235. );
  236. return cchUTF8;
  237. } //*** WideCharToUTF8
  238. //////////////////////////////////////////////////////////////////////////////
  239. //++
  240. //
  241. // HrInitializeLogLock
  242. //
  243. // Description:
  244. // Create the spin lock that protects the log file from concurrent writes.
  245. //
  246. // Arguments:
  247. // None.
  248. //
  249. // Return Values:
  250. // S_OK
  251. // E_OUTOFMEMORY
  252. //
  253. //--
  254. //////////////////////////////////////////////////////////////////////////////
  255. static
  256. HRESULT
  257. HrInitializeLogLock( void )
  258. {
  259. HRESULT hr = S_OK;
  260. PCRITICAL_SECTION pNewCritSect =
  261. (PCRITICAL_SECTION) HeapAlloc( GetProcessHeap(), 0, sizeof( CRITICAL_SECTION ) );
  262. if ( pNewCritSect == NULL )
  263. {
  264. DebugMsg( "DEBUG: Out of Memory. Logging disabled." );
  265. hr = E_OUTOFMEMORY;
  266. goto Cleanup;
  267. } // if: creation failed
  268. if ( InitializeCriticalSectionAndSpinCount( pNewCritSect, 4000 ) == 0 ) // MSDN recommends 4000.
  269. {
  270. DWORD scError = GetLastError();
  271. hr = HRESULT_FROM_WIN32( scError );
  272. goto Cleanup;
  273. }
  274. // Make sure we only have one log critical section
  275. InterlockedCompareExchangePointer( (PVOID *) &g_pcsLogging, pNewCritSect, 0 );
  276. if ( g_pcsLogging != pNewCritSect )
  277. {
  278. DebugMsg( "DEBUG: Another thread already created the CS. Deleting this one." );
  279. DeleteCriticalSection( pNewCritSect );
  280. } // if: already have another critical section
  281. else
  282. {
  283. pNewCritSect = NULL;
  284. }
  285. Cleanup:
  286. if ( pNewCritSect != NULL )
  287. {
  288. HeapFree( GetProcessHeap(), 0, pNewCritSect );
  289. }
  290. return hr;
  291. } //*** HrInitializeLogLock
  292. //////////////////////////////////////////////////////////////////////////////
  293. //++
  294. //
  295. // ScGetTokenInformation
  296. //
  297. // Description:
  298. // Get the requested information from the passed in client token.
  299. //
  300. // Arguments:
  301. // hClientTokenIn
  302. // The client token to dump.
  303. //
  304. // ticRequestIn
  305. //
  306. // ppbOut
  307. //
  308. // Return Value:
  309. // ERROR_SUCCESS for success.
  310. //
  311. // Other error codes.
  312. //
  313. //--
  314. //////////////////////////////////////////////////////////////////////////////
  315. static DWORD
  316. ScGetTokenInformation(
  317. HANDLE hClientTokenIn
  318. , TOKEN_INFORMATION_CLASS ticRequestIn
  319. , PBYTE * ppbOut
  320. )
  321. {
  322. Assert( ppbOut != NULL );
  323. PBYTE pb = NULL;
  324. DWORD cb = 64;
  325. DWORD sc = ERROR_SUCCESS;
  326. int idx;
  327. //
  328. // Get the user information from the client token.
  329. //
  330. for ( idx = 0; idx < 10; idx++ )
  331. {
  332. pb = (PBYTE) TraceAlloc( 0, cb );
  333. if ( pb == NULL )
  334. {
  335. sc = TW32( ERROR_OUTOFMEMORY );
  336. goto Cleanup;
  337. } // if:
  338. if ( !GetTokenInformation( hClientTokenIn, ticRequestIn, pb, cb, &cb ) )
  339. {
  340. sc = GetLastError();
  341. if ( sc == ERROR_INSUFFICIENT_BUFFER )
  342. {
  343. TraceFree( pb );
  344. pb = NULL;
  345. continue;
  346. } // if:
  347. TW32( sc );
  348. goto Cleanup;
  349. } // if:
  350. else
  351. {
  352. *ppbOut = pb;
  353. pb = NULL; // give away ownership
  354. sc = ERROR_SUCCESS;
  355. break;
  356. } // else:
  357. } // for:
  358. //
  359. // The loop should not exit because of idx == 10!
  360. //
  361. Assert( idx <= 9 );
  362. Cleanup:
  363. TraceFree( pb );
  364. return sc;
  365. } // *** ScGetTokenInformation
  366. //////////////////////////////////////////////////////////////////////////////
  367. //++
  368. //
  369. // ScGetDomainAndUserName
  370. //
  371. // Description:
  372. // Get the domain user name for the logged on user.
  373. //
  374. // Arguments:
  375. // pwszDomainAndUserNameOut
  376. // This string should be at least DNS_MAX_NAME_BUFFER_LENGTH + 128 characters long.
  377. //
  378. // cchDomainAndUserNameIn
  379. //
  380. // Return Value:
  381. // ERROR_SUCCESS for success.
  382. //
  383. // Other error codes.
  384. //
  385. //--
  386. //////////////////////////////////////////////////////////////////////////////
  387. static DWORD
  388. ScGetDomainAndUserName(
  389. LPWSTR pwszDomainAndUserNameOut
  390. , size_t cchDomainAndUserNameIn
  391. )
  392. {
  393. WCHAR * pwszUserName = pwszDomainAndUserNameOut + DNS_MAX_NAME_BUFFER_LENGTH;
  394. WCHAR * pwszDomainName = pwszDomainAndUserNameOut;
  395. DWORD cchUser = 128;
  396. DWORD cchDomain = DNS_MAX_NAME_BUFFER_LENGTH;
  397. HANDLE hClientToken = NULL;
  398. DWORD sc = ERROR_SUCCESS;
  399. TOKEN_USER * pTokenBuf = NULL;
  400. WCHAR * pwszOperation;
  401. SID_NAME_USE snuSidType;
  402. if (cchDomainAndUserNameIn < cchUser + cchDomain)
  403. {
  404. pwszOperation = L"BufferTooSmall";
  405. sc = TW32(ERROR_INSUFFICIENT_BUFFER);
  406. goto Cleanup;
  407. }
  408. pwszOperation = L"OpenThreadToken";
  409. if ( !OpenThreadToken( GetCurrentThread(), TOKEN_READ, FALSE, &hClientToken ) )
  410. {
  411. sc= GetLastError();
  412. if ( sc == ERROR_NO_TOKEN )
  413. {
  414. pwszOperation = L"OpenProcessToken";
  415. if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_READ, &hClientToken ) )
  416. {
  417. sc = TW32( GetLastError() );
  418. goto Cleanup;
  419. } // if: OpenProcessToken failed
  420. } // if: OpenThreadToken failed with ERROR_NO_TOKEN
  421. else
  422. {
  423. TW32( sc );
  424. goto Cleanup;
  425. } // else:
  426. } // if: OpenThreadToken failed
  427. pwszOperation = L"GetTokenInformation";
  428. sc = TW32( ScGetTokenInformation( hClientToken, TokenUser, (PBYTE *) &pTokenBuf ) );
  429. if ( sc != ERROR_SUCCESS )
  430. {
  431. goto Cleanup;
  432. } // if: failed to get token information
  433. pwszOperation = L"LookupAccoundSid";
  434. if ( !LookupAccountSidW( NULL, pTokenBuf->User.Sid, pwszUserName, &cchUser, pwszDomainName, &cchDomain, &snuSidType ) )
  435. {
  436. sc = TW32( GetLastError() );
  437. goto Cleanup;
  438. } // if: failed to lookup accound name
  439. pwszDomainName[ cchDomain ] = L'\\';
  440. MoveMemory( pwszDomainAndUserNameOut + cchDomain + 1, pwszUserName, ( cchUser + 1 ) * sizeof ( pwszUserName[0] ) );
  441. Cleanup:
  442. if ( hClientToken != NULL )
  443. {
  444. CloseHandle( hClientToken );
  445. } // if: needed to close hClientToken
  446. TraceFree( pTokenBuf );
  447. if ( sc != ERROR_SUCCESS )
  448. {
  449. HRESULT hr;
  450. hr = THR( StringCchPrintfW( pwszDomainAndUserNameOut, cchDomainAndUserNameIn, L"%ws failed with error %d", pwszOperation, sc ) );
  451. if ( FAILED( hr ) )
  452. {
  453. ; // the secondary error is not really interesting!
  454. } // if:
  455. } // else: report failure
  456. return sc;
  457. } //*** ScGetDomainAndUserName
  458. //////////////////////////////////////////////////////////////////////////////
  459. //++
  460. //
  461. // HrInitializeLogFile
  462. //
  463. // Description:
  464. // Open the log file and prepare it for writing.
  465. //
  466. // Arguments:
  467. // None.
  468. //
  469. // Return Values:
  470. //
  471. //--
  472. //////////////////////////////////////////////////////////////////////////////
  473. static
  474. HRESULT
  475. HrInitializeLogFile( void )
  476. {
  477. WCHAR szFilePath[ MAX_PATH ];
  478. size_t cchPath = MAX_PATH - 1;
  479. CHAR aszBuffer[ LOG_OUTPUT_BUFFER_SIZE ];
  480. WCHAR wszBuffer[ LOG_OUTPUT_BUFFER_SIZE ];
  481. WCHAR wszDomainAndUserName[ DNS_MAX_NAME_BUFFER_LENGTH + 128 ];
  482. DWORD cbWritten = 0;
  483. DWORD cbBytesToWrite = 0;
  484. BOOL fReturn;
  485. HRESULT hr = S_OK;
  486. DWORD sc = ERROR_SUCCESS;
  487. size_t cch;
  488. SYSTEMTIME SystemTime;
  489. hr = HrGetLogFilePath( L"%windir%\\system32\\LogFiles\\Cluster", szFilePath, &cchPath, g_hInstance );
  490. if ( FAILED( hr ) )
  491. {
  492. goto Error;
  493. }
  494. //
  495. // Create it
  496. //
  497. g_hLogFile = CreateFile(
  498. szFilePath
  499. , GENERIC_WRITE
  500. , FILE_SHARE_READ | FILE_SHARE_WRITE
  501. , NULL
  502. , OPEN_ALWAYS
  503. , FILE_FLAG_WRITE_THROUGH
  504. , NULL
  505. );
  506. if ( g_hLogFile == INVALID_HANDLE_VALUE )
  507. {
  508. #if defined( DEBUG )
  509. if ( !( g_tfModule & mtfOUTPUTTODISK ) )
  510. {
  511. DebugMsg( "*ERROR* Failed to create log at %s", szFilePath );
  512. } // if: not logging to disk
  513. #endif
  514. sc = GetLastError();
  515. hr = HRESULT_FROM_WIN32( sc );
  516. //
  517. // If we can not create the log file, try creating it under the alternate %TEMP% directory.
  518. //
  519. if ( ( sc == ERROR_ACCESS_DENIED ) || ( sc == ERROR_FILE_NOT_FOUND ) )
  520. {
  521. cch = ARRAYSIZE( szFilePath );
  522. hr = HrGetLogFilePath( TEXT("%TEMP%"), szFilePath, &cch, g_hInstance );
  523. if ( FAILED( hr ) )
  524. {
  525. goto Error;
  526. }
  527. //
  528. // Create it
  529. //
  530. g_hLogFile = CreateFile(
  531. szFilePath
  532. , GENERIC_WRITE
  533. , FILE_SHARE_READ | FILE_SHARE_WRITE
  534. , NULL
  535. , OPEN_ALWAYS
  536. , FILE_FLAG_WRITE_THROUGH
  537. , NULL
  538. );
  539. if ( g_hLogFile == INVALID_HANDLE_VALUE )
  540. {
  541. #if defined( DEBUG )
  542. if ( !( g_tfModule & mtfOUTPUTTODISK ) )
  543. {
  544. DebugMsg( "*ERROR* Failed to create log at %s", szFilePath );
  545. } // if: not logging to disk
  546. #endif
  547. hr = HRESULT_FROM_WIN32( GetLastError() );
  548. goto Error;
  549. } // if: ( g_hLogFile == INVALID_HANDLE_VALUE )
  550. } // if: ( ( sc == ERROR_ACCESS_DENIED ) || ( sc == ERROR_FILE_NOT_FOUND ) )
  551. else
  552. {
  553. goto Error;
  554. } // else:
  555. } // if: ( g_hLogFile == INVALID_HANDLE_VALUE )
  556. //
  557. // Copy which log file path we are using to g_szLogFilePath.
  558. //
  559. THR( StringCchCopyW( g_szLogFilePath, ARRAYSIZE( g_szLogFilePath ), szFilePath ) );
  560. // If the file is empty, begin with UTF-8 byte-order mark.
  561. {
  562. LARGE_INTEGER liFileSize = { 0, 0 };
  563. #if defined( DEBUG_SUPPORT_NT4 )
  564. liFileSize.LowPart = GetFileSize( g_hLogFile, (LPDWORD) &liFileSize.HighPart );
  565. if ( liFileSize.LowPart == INVALID_FILE_SIZE )
  566. #else
  567. fReturn = GetFileSizeEx( g_hLogFile, &liFileSize );
  568. if ( fReturn == FALSE )
  569. #endif
  570. {
  571. DWORD scError = GetLastError();
  572. hr = HRESULT_FROM_WIN32( scError );
  573. goto Error;
  574. } // if: GetFileSizeEx failed
  575. if ( liFileSize.QuadPart == 0 )
  576. {
  577. const char * aszUTF8ByteOrderMark = "\x0EF\x0BB\x0BF";
  578. const size_t cchByteOrderMark = 3;
  579. cbBytesToWrite = cchByteOrderMark * sizeof( aszUTF8ByteOrderMark[ 0 ] );
  580. fReturn = WriteFile( g_hLogFile, aszUTF8ByteOrderMark, cbBytesToWrite, &cbWritten, NULL );
  581. if ( fReturn == FALSE )
  582. {
  583. DWORD scError = GetLastError();
  584. hr = HRESULT_FROM_WIN32( scError );
  585. goto Error;
  586. } // if: WriteFile failed
  587. Assert( cbWritten == cbBytesToWrite );
  588. } // if starting log file
  589. else
  590. {
  591. // Seek to the end
  592. SetFilePointer( g_hLogFile, 0, NULL, FILE_END );
  593. }
  594. } // put utf-8 mark at beginning of file
  595. //
  596. // When an error occurs a formatted error string is placed in wszDomainAndUserName.
  597. //
  598. TW32( ScGetDomainAndUserName( wszDomainAndUserName, RTL_NUMBER_OF( wszDomainAndUserName ) ) );
  599. //
  600. // Write the time/date the log was (re)openned.
  601. //
  602. GetLocalTime( &SystemTime );
  603. THR( StringCchPrintfW(
  604. wszBuffer
  605. , ARRAYSIZE( wszBuffer )
  606. , L"*\r\n* %04u-%02u-%02u %02u:%02u:%02u.%03u (%ws)\r\n*\r\n"
  607. , SystemTime.wYear
  608. , SystemTime.wMonth
  609. , SystemTime.wDay
  610. , SystemTime.wHour
  611. , SystemTime.wMinute
  612. , SystemTime.wSecond
  613. , SystemTime.wMilliseconds
  614. , wszDomainAndUserName
  615. ) );
  616. WideCharToUTF8( wszBuffer, ARRAYSIZE( aszBuffer), aszBuffer );
  617. cbBytesToWrite = static_cast< DWORD >( strlen( aszBuffer ) * sizeof( aszBuffer[ 0 ] ) );
  618. fReturn = WriteFile( g_hLogFile, aszBuffer, cbBytesToWrite, &cbWritten, NULL );
  619. if ( ! fReturn )
  620. {
  621. hr = HRESULT_FROM_WIN32( GetLastError() );
  622. goto Error;
  623. } // if: failed
  624. Assert( cbWritten == cbBytesToWrite );
  625. DebugMsg( "DEBUG: Created log at %s", szFilePath );
  626. Cleanup:
  627. return hr;
  628. Error:
  629. DebugMsg( "HrInitializeLogFile: Failed hr = 0x%08x", hr );
  630. if ( g_hLogFile != INVALID_HANDLE_VALUE )
  631. {
  632. CloseHandle( g_hLogFile );
  633. g_hLogFile = INVALID_HANDLE_VALUE;
  634. } // if: handle was open
  635. goto Cleanup;
  636. } //*** HrInitializeLogFile
  637. //////////////////////////////////////////////////////////////////////////////
  638. //++
  639. //
  640. // HrLogOpen
  641. //
  642. // Description:
  643. // This function:
  644. // - initializes the log critical section
  645. // - enters the log critical section assuring only one thread is
  646. // writing to the log at a time
  647. // - creates the directory tree to the log file (if needed)
  648. // - initializes the log file by:
  649. // - creating a new log file if one doesn't exist.
  650. // - opens an existing log file (for append)
  651. // - appends a time/date stamp that the log was (re)opened.
  652. //
  653. // Use LogClose() to exit the log critical section.
  654. //
  655. // If there is a failure inside this function, the log critical
  656. // section will be released before returning.
  657. //
  658. // Arguments:
  659. // None.
  660. //
  661. // Return Values:
  662. // S_OK - log critical section held and log open successfully
  663. // Otherwize HRESULT error code.
  664. //
  665. //--
  666. //////////////////////////////////////////////////////////////////////////////
  667. inline
  668. HRESULT
  669. HrLogOpen( void )
  670. {
  671. HRESULT hr = S_OK;
  672. // If lock has not been initialized, initialize it.
  673. if ( g_pcsLogging == NULL )
  674. {
  675. hr = HrInitializeLogLock();
  676. if ( FAILED( hr ) )
  677. {
  678. goto Cleanup;
  679. }
  680. }
  681. // Grab lock.
  682. Assert( g_pcsLogging != NULL );
  683. EnterCriticalSection( g_pcsLogging );
  684. // If file has not been initialized, initialize it.
  685. if ( g_hLogFile == INVALID_HANDLE_VALUE )
  686. {
  687. hr = HrInitializeLogFile();
  688. }
  689. Cleanup:
  690. return hr;
  691. } //*** HrLogOpen
  692. //////////////////////////////////////////////////////////////////////////////
  693. //++
  694. //
  695. // HrLogRelease
  696. //
  697. // Description:
  698. // This actually just leaves the log critical section.
  699. //
  700. // Arguments:
  701. // None.
  702. //
  703. // Return Values:
  704. // S_OK always.
  705. //
  706. //--
  707. //////////////////////////////////////////////////////////////////////////////
  708. inline
  709. HRESULT
  710. HrLogRelease( void )
  711. {
  712. if ( g_pcsLogging != NULL )
  713. {
  714. LeaveCriticalSection( g_pcsLogging );
  715. }
  716. return S_OK;
  717. } //*** HrLogRelease
  718. //////////////////////////////////////////////////////////////////////////////
  719. //++
  720. //
  721. // LogFormattedText
  722. //
  723. // Description:
  724. // Convert a wide string to UTF-8 and write it to the log file.
  725. //
  726. // Arguments:
  727. // fTimeStampIn
  728. // fNewlineIn
  729. // nLogEntryTypeIn
  730. // pwszTextIn
  731. //
  732. // Return Values:
  733. // None.
  734. //
  735. //--
  736. //////////////////////////////////////////////////////////////////////////////
  737. static
  738. void
  739. LogFormattedText(
  740. BOOL fTimeStampIn
  741. , BOOL fNewlineIn
  742. , DWORD nLogEntryTypeIn
  743. , LPCWSTR pwszTextIn
  744. )
  745. {
  746. char aszTimeStamp[ TIMESTAMP_BUFFER_SIZE ];
  747. char aszLogText[ LOG_OUTPUT_BUFFER_SIZE ];
  748. char * paszLogEntryType;
  749. size_t cchTimeStamp = 0;
  750. size_t cchLogText = 0;
  751. DWORD cbWritten;
  752. DWORD cbToWrite;
  753. HRESULT hr = S_OK;
  754. BOOL fSuccess;
  755. Assert( pwszTextIn != NULL );
  756. // Format time stamp (and convert to UTF-8) if requested.
  757. if ( fTimeStampIn )
  758. {
  759. WCHAR szCurrentTime[ TIMESTAMP_BUFFER_SIZE ];
  760. SYSTEMTIME stCurrentTime;
  761. GetLocalTime( &stCurrentTime );
  762. FormatTimeStamp( &stCurrentTime, szCurrentTime, ARRAYSIZE( szCurrentTime ) );
  763. cchTimeStamp = WideCharToUTF8( szCurrentTime, ARRAYSIZE( aszTimeStamp ), aszTimeStamp );
  764. } // if: time stamp requested
  765. // Convert formatted text to UTF-8.
  766. cchLogText = WideCharToUTF8( pwszTextIn, ARRAYSIZE( aszLogText ), aszLogText );
  767. // Grab file.
  768. hr = THR( HrLogOpen() );
  769. if ( FAILED( hr ) )
  770. {
  771. goto Cleanup;
  772. }
  773. // Write time stamp to log if requested.
  774. if ( fTimeStampIn )
  775. {
  776. cbToWrite = static_cast< DWORD >( cchTimeStamp * sizeof( aszTimeStamp[ 0 ] ) );
  777. fSuccess = WriteFile( g_hLogFile, aszTimeStamp, cbToWrite, &cbWritten, NULL );
  778. if ( fSuccess == FALSE )
  779. {
  780. TW32( GetLastError() );
  781. }
  782. else
  783. {
  784. Assert( cbWritten == cbToWrite );
  785. }
  786. } // if: timestamp requested
  787. // Write the log entry type.
  788. if ( nLogEntryTypeIn != LOGTYPE_NONE )
  789. {
  790. if ( nLogEntryTypeIn == LOGTYPE_DEBUG )
  791. {
  792. paszLogEntryType = "[DBG ] ";
  793. }
  794. else if ( ( nLogEntryTypeIn == LOGTYPE_INFO ) || ( nLogEntryTypeIn == S_OK ) )
  795. {
  796. paszLogEntryType = "[INFO] ";
  797. }
  798. else if ( ( nLogEntryTypeIn == LOGTYPE_WARNING ) )
  799. {
  800. paszLogEntryType = "[WARN] ";
  801. }
  802. else if ( ( nLogEntryTypeIn == LOGTYPE_ERROR ) || FAILED( nLogEntryTypeIn ) )
  803. {
  804. paszLogEntryType = "[ERR ] ";
  805. }
  806. else
  807. {
  808. // Can't do the other warning test here because LOGTYPE_WARNING would
  809. // cause the FAILED() macro to return TRUE, and therefore the code
  810. // would be treated as an error type.
  811. paszLogEntryType = "[WARN] ";
  812. }
  813. cbToWrite = static_cast< DWORD >( strlen( paszLogEntryType ) );
  814. fSuccess = WriteFile( g_hLogFile, paszLogEntryType, cbToWrite, &cbWritten, NULL );
  815. if ( fSuccess == FALSE )
  816. {
  817. TW32( GetLastError() );
  818. }
  819. else
  820. {
  821. Assert( cbWritten == cbToWrite );
  822. }
  823. } // if: log entry type requested
  824. // Write UTF-8 to log.
  825. cbToWrite = static_cast< DWORD >( cchLogText );
  826. fSuccess = WriteFile( g_hLogFile, aszLogText, cbToWrite, &cbWritten, NULL );
  827. if ( fSuccess == FALSE )
  828. {
  829. TW32( GetLastError() );
  830. }
  831. else
  832. {
  833. Assert( cbWritten == cbToWrite );
  834. }
  835. // Write newline to log if requested.
  836. if ( fNewlineIn )
  837. {
  838. cbToWrite = SIZEOF_ASZ_NEWLINE;
  839. fSuccess = WriteFile( g_hLogFile, ASZ_NEWLINE, cbToWrite, &cbWritten, NULL );
  840. if ( fSuccess == FALSE )
  841. {
  842. TW32( GetLastError() );
  843. }
  844. else
  845. {
  846. Assert( cbWritten == cbToWrite );
  847. }
  848. }
  849. Cleanup:
  850. // Release file.
  851. hr = THR( HrLogRelease() );
  852. return;
  853. } //*** LogFormattedText
  854. //////////////////////////////////////////////////////////////////////////////
  855. //++
  856. //
  857. // LogUnformattedText
  858. //
  859. // Description:
  860. // Format a string and pass it on to LogFormattedText.
  861. //
  862. // Arguments:
  863. // fTimeStampIn
  864. // fNewlineIn
  865. // nLogEntryTypeIn
  866. // pwszFormatIn
  867. // pvlFormatArgsIn
  868. //
  869. // Return Values:
  870. // None.
  871. //
  872. //--
  873. //////////////////////////////////////////////////////////////////////////////
  874. static
  875. inline
  876. void
  877. LogUnformattedText(
  878. BOOL fTimeStampIn
  879. , BOOL fNewlineIn
  880. , DWORD nLogEntryTypeIn
  881. , LPCWSTR pwszFormatIn
  882. , va_list * pvlFormatArgsIn
  883. )
  884. {
  885. WCHAR wszFormatted[ LOG_OUTPUT_BUFFER_SIZE ];
  886. Assert( pwszFormatIn != NULL );
  887. Assert( pvlFormatArgsIn != NULL );
  888. // Format string.
  889. THR( StringCchVPrintfW( wszFormatted, ARRAYSIZE( wszFormatted ), pwszFormatIn, *pvlFormatArgsIn ) );
  890. // Pass formatted string through to LogFormattedText.
  891. LogFormattedText( fTimeStampIn, fNewlineIn, nLogEntryTypeIn, wszFormatted );
  892. } //*** LogUnformattedText
  893. //////////////////////////////////////////////////////////////////////////////
  894. //++
  895. //
  896. // HrLogClose
  897. //
  898. // Description:
  899. // Close the file. This function expects the critical section to have
  900. // already been released.
  901. //
  902. // Arguments:
  903. // None.
  904. //
  905. // Return Values:
  906. // S_OK always.
  907. //
  908. //--
  909. //////////////////////////////////////////////////////////////////////////////
  910. HRESULT
  911. HrLogClose( void )
  912. {
  913. TraceFunc( "" );
  914. HRESULT hr = S_OK;
  915. if ( g_pcsLogging != NULL )
  916. {
  917. DeleteCriticalSection( g_pcsLogging );
  918. HeapFree( GetProcessHeap(), 0, g_pcsLogging );
  919. g_pcsLogging = NULL;
  920. } // if:
  921. if ( g_hLogFile != INVALID_HANDLE_VALUE )
  922. {
  923. CloseHandle( g_hLogFile );
  924. g_hLogFile = INVALID_HANDLE_VALUE;
  925. } // if: handle was open
  926. HRETURN( hr );
  927. } //*** HrLogClose
  928. //////////////////////////////////////////////////////////////////////////////
  929. //++
  930. //
  931. // ASCII
  932. //
  933. // LogMsgNoNewline
  934. //
  935. // Description:
  936. // Logs a message to the log file without adding a newline.
  937. //
  938. // Arguments:
  939. // paszFormatIn - A printf format string to be printed.
  940. // ,,, - Arguments for the printf string.
  941. //
  942. // Return Values:
  943. // None.
  944. //
  945. //--
  946. //////////////////////////////////////////////////////////////////////////////
  947. void
  948. __cdecl
  949. LogMsgNoNewline(
  950. LPCSTR paszFormatIn,
  951. ...
  952. )
  953. {
  954. va_list valist;
  955. WCHAR wszFormat[ LOG_OUTPUT_BUFFER_SIZE ];
  956. Assert( paszFormatIn != NULL );
  957. size_t cchWideFormat = MultiByteToWideChar(
  958. CP_ACP
  959. , MB_PRECOMPOSED
  960. , paszFormatIn
  961. , -1
  962. , wszFormat
  963. , ARRAYSIZE( wszFormat )
  964. );
  965. if ( cchWideFormat > 0 )
  966. {
  967. va_start( valist, paszFormatIn );
  968. LogUnformattedText( FALSE, FALSE, LOGTYPE_NONE, wszFormat, &valist );
  969. va_end( valist );
  970. }
  971. } //*** LogMsgNoNewline ASCII
  972. //////////////////////////////////////////////////////////////////////////////
  973. //++
  974. //
  975. // ASCII
  976. //
  977. // LogMsgNoNewline
  978. //
  979. // Description:
  980. // Logs a message to the log file without adding a newline.
  981. //
  982. // Arguments:
  983. // nLogEntryTypeIn - Log entry type.
  984. // paszFormatIn - A printf format string to be printed.
  985. // ,,, - Arguments for the printf string.
  986. //
  987. // Return Values:
  988. // None.
  989. //
  990. //--
  991. //////////////////////////////////////////////////////////////////////////////
  992. void
  993. __cdecl
  994. LogMsgNoNewline(
  995. DWORD nLogEntryTypeIn
  996. , LPCSTR paszFormatIn
  997. , ...
  998. )
  999. {
  1000. va_list valist;
  1001. WCHAR wszFormat[ LOG_OUTPUT_BUFFER_SIZE ];
  1002. Assert( paszFormatIn != NULL );
  1003. size_t cchWideFormat = MultiByteToWideChar(
  1004. CP_ACP
  1005. , MB_PRECOMPOSED
  1006. , paszFormatIn
  1007. , -1
  1008. , wszFormat
  1009. , ARRAYSIZE( wszFormat )
  1010. );
  1011. if ( cchWideFormat > 0 )
  1012. {
  1013. va_start( valist, paszFormatIn );
  1014. LogUnformattedText( FALSE, FALSE, nLogEntryTypeIn, wszFormat, &valist );
  1015. va_end( valist );
  1016. }
  1017. } //*** LogMsgNoNewline ASCII
  1018. //////////////////////////////////////////////////////////////////////////////
  1019. //++
  1020. //
  1021. // UNICODE
  1022. //
  1023. // LogMsgNoNewline
  1024. //
  1025. // Description:
  1026. // Logs a message to the log file without adding a newline.
  1027. //
  1028. // Arguments:
  1029. // pszFormatIn - A printf format string to be printed.
  1030. // ,,, - Arguments for the printf string.
  1031. //
  1032. // Return Values:
  1033. // None.
  1034. //
  1035. //--
  1036. //////////////////////////////////////////////////////////////////////////////
  1037. void
  1038. __cdecl
  1039. LogMsgNoNewline(
  1040. LPCWSTR pszFormatIn,
  1041. ...
  1042. )
  1043. {
  1044. va_list valist;
  1045. Assert( pszFormatIn != NULL );
  1046. va_start( valist, pszFormatIn );
  1047. LogUnformattedText( FALSE, FALSE, LOGTYPE_NONE, pszFormatIn, &valist );
  1048. va_end( valist );
  1049. } //*** LogMsgNoNewline UNICODE
  1050. //////////////////////////////////////////////////////////////////////////////
  1051. //++
  1052. //
  1053. // UNICODE
  1054. //
  1055. // LogMsgNoNewline
  1056. //
  1057. // Description:
  1058. // Logs a message to the log file without adding a newline.
  1059. //
  1060. // Arguments:
  1061. // nLogEntryTypeIn - Log entry type.
  1062. // pszFormatIn - A printf format string to be printed.
  1063. // ,,, - Arguments for the printf string.
  1064. //
  1065. // Return Values:
  1066. // None.
  1067. //
  1068. //--
  1069. //////////////////////////////////////////////////////////////////////////////
  1070. void
  1071. __cdecl
  1072. LogMsgNoNewline(
  1073. DWORD nLogEntryTypeIn
  1074. , LPCWSTR pszFormatIn
  1075. , ...
  1076. )
  1077. {
  1078. va_list valist;
  1079. Assert( pszFormatIn != NULL );
  1080. va_start( valist, pszFormatIn );
  1081. LogUnformattedText( FALSE, FALSE, nLogEntryTypeIn, pszFormatIn, &valist );
  1082. va_end( valist );
  1083. } //*** LogMsgNoNewline UNICODE
  1084. //////////////////////////////////////////////////////////////////////////////
  1085. //++
  1086. //
  1087. // ASCII
  1088. //
  1089. // LogMsg
  1090. //
  1091. // Description:
  1092. // Logs a message to the log file and adds a newline.
  1093. //
  1094. // Arguments:
  1095. // paszFormatIn - A printf format string to be printed.
  1096. // ,,, - Arguments for the printf string.
  1097. //
  1098. // Return Values:
  1099. // None.
  1100. //
  1101. //--
  1102. //////////////////////////////////////////////////////////////////////////////
  1103. void
  1104. __cdecl
  1105. LogMsg(
  1106. LPCSTR paszFormatIn,
  1107. ...
  1108. )
  1109. {
  1110. va_list valist;
  1111. WCHAR wszFormat[ LOG_OUTPUT_BUFFER_SIZE ];
  1112. size_t cchWideFormat = 0;
  1113. Assert( paszFormatIn != NULL );
  1114. cchWideFormat = MultiByteToWideChar(
  1115. CP_ACP
  1116. , MB_PRECOMPOSED
  1117. , paszFormatIn
  1118. , -1
  1119. , wszFormat
  1120. , ARRAYSIZE( wszFormat )
  1121. );
  1122. if ( cchWideFormat > 0 )
  1123. {
  1124. va_start( valist, paszFormatIn );
  1125. LogUnformattedText( TRUE, TRUE, LOGTYPE_INFO, wszFormat, &valist );
  1126. va_end( valist );
  1127. }
  1128. } //*** LogMsg ASCII
  1129. //////////////////////////////////////////////////////////////////////////////
  1130. //++
  1131. //
  1132. // ASCII
  1133. //
  1134. // LogMsg
  1135. //
  1136. // Description:
  1137. // Logs a message to the log file and adds a newline.
  1138. //
  1139. // Arguments:
  1140. // nLogEntryTypeIn - Log entry type.
  1141. // paszFormatIn - A printf format string to be printed.
  1142. // ,,, - Arguments for the printf string.
  1143. //
  1144. // Return Values:
  1145. // None.
  1146. //
  1147. //--
  1148. //////////////////////////////////////////////////////////////////////////////
  1149. void
  1150. __cdecl
  1151. LogMsg(
  1152. DWORD nLogEntryTypeIn
  1153. , LPCSTR paszFormatIn
  1154. , ...
  1155. )
  1156. {
  1157. va_list valist;
  1158. WCHAR wszFormat[ LOG_OUTPUT_BUFFER_SIZE ];
  1159. size_t cchWideFormat = 0;
  1160. Assert( paszFormatIn != NULL );
  1161. cchWideFormat = MultiByteToWideChar(
  1162. CP_ACP
  1163. , MB_PRECOMPOSED
  1164. , paszFormatIn
  1165. , -1
  1166. , wszFormat
  1167. , ARRAYSIZE( wszFormat )
  1168. );
  1169. if ( cchWideFormat > 0 )
  1170. {
  1171. va_start( valist, paszFormatIn );
  1172. LogUnformattedText( TRUE, TRUE, nLogEntryTypeIn, wszFormat, &valist );
  1173. va_end( valist );
  1174. }
  1175. } //*** LogMsg ASCII
  1176. //////////////////////////////////////////////////////////////////////////////
  1177. //++
  1178. //
  1179. // UNICODE
  1180. //
  1181. // LogMsg
  1182. //
  1183. // Description:
  1184. // Logs a message to the log file and adds a newline.
  1185. //
  1186. // Arguments:
  1187. // pszFormatIn - A printf format string to be printed.
  1188. // ,,, - Arguments for the printf string.
  1189. //
  1190. // Return Values:
  1191. // None.
  1192. //
  1193. //--
  1194. //////////////////////////////////////////////////////////////////////////////
  1195. void
  1196. __cdecl
  1197. LogMsg(
  1198. LPCWSTR pszFormatIn
  1199. , ...
  1200. )
  1201. {
  1202. va_list valist;
  1203. Assert( pszFormatIn != NULL );
  1204. va_start( valist, pszFormatIn );
  1205. LogUnformattedText( TRUE, TRUE, LOGTYPE_INFO, pszFormatIn, &valist );
  1206. va_end( valist );
  1207. } //*** LogMsg UNICODE
  1208. //////////////////////////////////////////////////////////////////////////////
  1209. //++
  1210. //
  1211. // UNICODE
  1212. //
  1213. // LogMsg
  1214. //
  1215. // Description:
  1216. // Logs a message to the log file and adds a newline.
  1217. //
  1218. // Arguments:
  1219. // nLogEntryTypeIn - Log entry type.
  1220. // pszFormatIn - A printf format string to be printed.
  1221. // ,,, - Arguments for the printf string.
  1222. //
  1223. // Return Values:
  1224. // None.
  1225. //
  1226. //--
  1227. //////////////////////////////////////////////////////////////////////////////
  1228. void
  1229. __cdecl
  1230. LogMsg(
  1231. DWORD nLogENtryTypeIn
  1232. , LPCWSTR pszFormatIn
  1233. , ...
  1234. )
  1235. {
  1236. va_list valist;
  1237. Assert( pszFormatIn != NULL );
  1238. va_start( valist, pszFormatIn );
  1239. LogUnformattedText( TRUE, TRUE, nLogENtryTypeIn, pszFormatIn, &valist );
  1240. va_end( valist );
  1241. } //*** LogMsg UNICODE
  1242. //////////////////////////////////////////////////////////////////////////////
  1243. //++
  1244. //
  1245. // LogStatusReport
  1246. //
  1247. // Description:
  1248. // Writes a status report to the log file.
  1249. //
  1250. // Arugments:
  1251. // pstTimeIn -
  1252. // pcszNodeNameIn -
  1253. // clsidTaskMajorIn -
  1254. // clsidTaskMinorIn -
  1255. // ulMinIn -
  1256. // ulMaxIn -
  1257. // ulCurrentIn -
  1258. // hrStatusIn -
  1259. // pcszDescriptionIn -
  1260. // pcszUrlIn -
  1261. //
  1262. // Return Values:
  1263. // None.
  1264. //
  1265. //--
  1266. //////////////////////////////////////////////////////////////////////////////
  1267. void
  1268. LogStatusReport(
  1269. SYSTEMTIME * pstTimeIn,
  1270. const WCHAR * pcszNodeNameIn,
  1271. CLSID clsidTaskMajorIn,
  1272. CLSID clsidTaskMinorIn,
  1273. ULONG ulMinIn,
  1274. ULONG ulMaxIn,
  1275. ULONG ulCurrentIn,
  1276. HRESULT hrStatusIn,
  1277. const WCHAR * pcszDescriptionIn,
  1278. const WCHAR * pcszUrlIn
  1279. )
  1280. {
  1281. SYSTEMTIME stCurrent;
  1282. SYSTEMTIME stReport;
  1283. WCHAR szCurrent[ TIMESTAMP_BUFFER_SIZE ];
  1284. WCHAR szReport[ TIMESTAMP_BUFFER_SIZE ];
  1285. const size_t cchGuid = 40;
  1286. WCHAR wszMajorGuid[ cchGuid ];
  1287. WCHAR wszMinorGuid[ cchGuid ];
  1288. WCHAR wszFormattedReport[ LOG_OUTPUT_BUFFER_SIZE ];
  1289. GetLocalTime( &stCurrent );
  1290. if ( pstTimeIn )
  1291. {
  1292. memcpy( &stReport, pstTimeIn, sizeof( stReport ) );
  1293. }
  1294. else
  1295. {
  1296. memset( &stReport, 0, sizeof( stReport) );
  1297. }
  1298. FormatTimeStamp( &stCurrent, szCurrent, ARRAYSIZE( szCurrent ) );
  1299. FormatTimeStamp( &stReport, szReport, ARRAYSIZE( szReport ) );
  1300. StringFromGUID2( clsidTaskMajorIn, wszMajorGuid, cchGuid );
  1301. StringFromGUID2( clsidTaskMinorIn, wszMinorGuid, cchGuid );
  1302. THR( StringCchPrintfW(
  1303. wszFormattedReport
  1304. , ARRAYSIZE( wszFormattedReport )
  1305. , L"%ws - %ws %ws, %ws (%2d / %2d .. %2d ) <%ws> hr=%08X %ws %ws"
  1306. , szCurrent
  1307. , szReport
  1308. , wszMajorGuid
  1309. , wszMinorGuid
  1310. , ulCurrentIn
  1311. , ulMinIn
  1312. , ulMaxIn
  1313. , pcszNodeNameIn
  1314. , hrStatusIn
  1315. , pcszDescriptionIn
  1316. , pcszUrlIn
  1317. ) );
  1318. LogFormattedText( FALSE, TRUE, hrStatusIn, wszFormattedReport );
  1319. } //*** LogStatusReport