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.

1130 lines
33 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. vs_trace.cxx
  5. Abstract:
  6. This module defines the global debug\trace facilities used by the
  7. Long Term Storage service.
  8. Previous name: bsdebug.cxx
  9. Author:
  10. Revision History:
  11. Name Date Comments
  12. ssteiner 06/03/98 Made numerious changes and removed iostream
  13. dependencies, added a few new registry entries and
  14. added serialization.
  15. aoltean 06/06/99 Taken from atl30\atlbase.h in order to avoid linking ATL with BSCommon.lib
  16. ssteiner 05/15/00 Fixed bug #116688. Added file locking to prevent multiple processes from
  17. interferring with writing to the trace file. Added code to place a UNICODE
  18. BOM at the beginning of the trace file.
  19. --*/
  20. //
  21. // ***** Includes *****
  22. //
  23. #pragma warning(disable:4290)
  24. #pragma warning(disable:4127)
  25. #include <wtypes.h>
  26. #pragma warning( disable: 4201 ) // C4201: nonstandard extension used : nameless struct/union
  27. #include <winioctl.h>
  28. #pragma warning( default: 4201 ) // C4201: nonstandard extension used : nameless struct/union
  29. #include <winbase.h>
  30. #include <wchar.h>
  31. #include <string.h>
  32. #include <iostream.h>
  33. #include <fstream.h>
  34. #include <stdio.h>
  35. #include <process.h>
  36. #include <stdlib.h>
  37. #include <time.h>
  38. #include <errno.h>
  39. //#include <vssmsg.h>
  40. // Enabling asserts in ATL and VSS
  41. #include "vs_assert.hxx"
  42. #include <oleauto.h>
  43. #include <stddef.h>
  44. #pragma warning( disable: 4127 ) // warning C4127: conditional expression is constant
  45. #include <atlconv.h>
  46. #include <atlbase.h>
  47. #include <ntverp.h>
  48. #include "vs_inc.hxx"
  49. //#include "vs_idl.hxx"
  50. ////////////////////////////////////////////////////////////////////////
  51. // Standard foo for file name aliasing. This code block must be after
  52. // all includes of VSS header files.
  53. //
  54. #ifdef VSS_FILE_ALIAS
  55. #undef VSS_FILE_ALIAS
  56. #endif
  57. #define VSS_FILE_ALIAS "TRCTRCC"
  58. //
  59. ////////////////////////////////////////////////////////////////////////
  60. //
  61. // The following global, g_cDbgTrace must be declared BEFORE any of our
  62. // objects including _Module, since some of our static objects have destructors
  63. // that call trace methods. The following pragma ensures that this
  64. // module's static objects are initialized before any of our other
  65. // static objects, assuming they don't use this same pragma.
  66. //
  67. #pragma warning(disable:4073) // ignore init_seg warning
  68. #pragma init_seg(lib)
  69. CBsDbgTrace g_cDbgTrace;
  70. static VOID MakeFileUnicode(
  71. IN HANDLE hFile
  72. );
  73. /////////////////////////////////////////////////////////////////////////////
  74. // constants
  75. //
  76. const WCHAR VSS_TRACINGKEYPATH[] =
  77. L"SYSTEM\\CurrentControlSet\\Services\\VSS\\Debug\\Tracing";
  78. const WCHAR SETUP_KEY[] =
  79. L"SYSTEM\\Setup";
  80. const WCHAR SETUP_INPROGRESS_REG[] =
  81. L"SystemSetupInProgress";
  82. const DWORD SETUP_INPROGRESS_VALUE = 1;
  83. const x_nMaxCoCreateInstanceRetries = 10;
  84. /////////////////////////////////////////////////////////////////////////////
  85. // Globals
  86. //
  87. //
  88. // NOTE: g_cDbgTrace, the global instance of this class is declared in
  89. // ltss\modules\ltssvc\src\ltssvc.cxx since we have to make sure
  90. // this object is the last one being destructed, otherwise possible
  91. // calls to this object will fail.
  92. //
  93. //
  94. // Define a TLS var, stores the CLTermStg & intention list index.
  95. // The index is a counter that is incremented and set for each thread
  96. // coming into the service, in the CLTermStg::FinalConstruct method.
  97. // The counter is also incremented and set for each intention list
  98. // thread that is created by the service.
  99. //
  100. // WARNING
  101. //
  102. //
  103. //_declspec( thread ) DWORD CBsDbgTrace::m_dwContextNum = 0;
  104. //
  105. // Queries a registry value name and if found sets dwValue to the value.
  106. // If the value name is not found, dwValue remains unchanged.
  107. //
  108. static DWORD
  109. QuerySetValue (
  110. IN CRegKey &cRegKey,
  111. IN OUT DWORD &dwValue,
  112. IN LPCWSTR pwszValueName
  113. )
  114. {
  115. DWORD dwReadValue = 0;
  116. DWORD dwResult = cRegKey.QueryValue( dwReadValue, pwszValueName );
  117. if ( dwResult == ERROR_SUCCESS )
  118. dwValue = dwReadValue;
  119. return dwResult;
  120. }
  121. //
  122. // Queries a registry value name and if found sets bValue to the value.
  123. // If the value name is not found, bValue remains unchanged.
  124. //
  125. static DWORD
  126. QuerySetValue (
  127. IN CRegKey &cRegKey,
  128. IN OUT BOOL &bValue,
  129. IN LPCWSTR pwszValueName
  130. )
  131. {
  132. DWORD dwReadValue = 0;
  133. DWORD dwResult = cRegKey.QueryValue( dwReadValue, pwszValueName );
  134. if ( dwResult == ERROR_SUCCESS )
  135. bValue = (BOOL)(dwReadValue != 0);
  136. return dwResult;
  137. }
  138. //
  139. // Queries a registry value name and if found sets wsValue to the value.
  140. // If the value name is not found, wsValue remains unchanged.
  141. //
  142. static DWORD
  143. QuerySetValue (
  144. IN CRegKey &cRegKey,
  145. OUT LPWSTR &wsValue, // If allocated, must be freed before calling with ::VssFreeString
  146. IN LPCWSTR pwszValueName
  147. )
  148. {
  149. WCHAR pszValueBuffer[_MAX_PATH];
  150. DWORD dwCount = _MAX_PATH;
  151. DWORD dwResult = cRegKey.QueryValue( pszValueBuffer, pwszValueName, &dwCount );
  152. BS_ASSERT(wsValue == NULL);
  153. if ( dwResult == ERROR_SUCCESS )
  154. ::VssDuplicateStr(wsValue, pszValueBuffer);
  155. return dwResult;
  156. }
  157. //
  158. // ***** class definitions *****
  159. //
  160. CBsDbgTrace::CBsDbgTrace()
  161. /*++
  162. Routine Description:
  163. Constructor method. Default values are given to operational
  164. parameters and overwritten using values from the registry if
  165. set. Also prints out the trace file banner.
  166. Arguments:
  167. NONE
  168. Return Value:
  169. NONE
  170. --*/
  171. {
  172. m_bInitialized = false;
  173. m_bTracingEnabled = false;
  174. m_pcs = NULL;
  175. Initialize( TRUE );
  176. }
  177. CBsDbgTrace::~CBsDbgTrace()
  178. /*++
  179. Routine Description:
  180. Destructor method. Prints out the last record in the NTMS
  181. Arguments:
  182. LONG Indent - NOT USED YET [todo] this is the indentation indicator
  183. LONG Level - this is the debug trace level
  184. Return Value:
  185. BOOL
  186. --*/
  187. {
  188. if ( !m_bInitialized )
  189. return;
  190. if ( m_bTracingEnabled ) {
  191. //
  192. // Write out a finished tracing message
  193. //
  194. m_pcs->Enter();
  195. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"****************************************************************" ) );
  196. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"** TRACING FINISHED - ProcessId: 0x%x, ContextId: 0x%x",
  197. m_dwCurrentProcessId, m_dwContextId ) );
  198. WCHAR pwszCurrentTime[128];
  199. time_t ltime;
  200. struct tm *pToday;
  201. time( &ltime );
  202. pToday = localtime( &ltime );
  203. wcsftime( pwszCurrentTime, sizeof pwszCurrentTime, L"%c", pToday );
  204. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"** Current time: %s", pwszCurrentTime ) );
  205. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"** Elapsed time: %d seconds", ltime- m_lTimeStarted ) );
  206. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"** Command-line: %s", GetCommandLineW() ) );
  207. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"****************************************************************" ) );
  208. m_pcs->Leave();
  209. //
  210. // Make sure the file is flushed before leaving
  211. //
  212. if ( m_bTraceToFile ) {
  213. m_hTraceFile = ::CreateFile( m_pwszTraceFileName?
  214. m_pwszTraceFileName :
  215. BS_DBG_TRACE_FILE_NAME_DFLT,
  216. GENERIC_WRITE,
  217. FILE_SHARE_READ,
  218. NULL,
  219. OPEN_ALWAYS,
  220. FILE_ATTRIBUTE_NORMAL,
  221. NULL );
  222. if ( m_hTraceFile != INVALID_HANDLE_VALUE ) {
  223. ::FlushFileBuffers( m_hTraceFile );
  224. ::CloseHandle( m_hTraceFile );
  225. }
  226. }
  227. }
  228. ::VssFreeString(m_pwszTraceFileName);
  229. //
  230. // Delete the critical section
  231. //
  232. delete m_pcs;
  233. m_pcs = NULL;
  234. m_bInitialized = FALSE;
  235. }
  236. //
  237. // In certain cases the global trace object doesn't seem to get it's constructor called.
  238. // To fix this problem, this function was added to perform the initialization of the
  239. // object. This function is called both in the constructor and the set context call
  240. // which all DLLs that use the trace class call.
  241. //
  242. VOID
  243. CBsDbgTrace::Initialize(
  244. IN BOOL bInConstructor
  245. )
  246. {
  247. if ( !m_bInitialized )
  248. {
  249. try
  250. {
  251. //
  252. // Get the critical section created first
  253. //
  254. m_pcs = new CBsCritSec;
  255. if ( m_pcs == NULL )
  256. throw E_OUTOFMEMORY;
  257. m_bInitialized = TRUE;
  258. m_bTracingEnabled = FALSE;
  259. m_bTraceToFile = BS_DBG_TRACE_TO_FILE_DFLT;
  260. m_bTraceToDebugger = BS_DBG_TRACE_TO_DEBUGGER_DFLT;
  261. m_bTraceEnterExit = BS_DBG_TRACE_ENTER_EXIT_DFLT;
  262. m_dwTraceLevel = BS_DBG_TRACE_LEVEL_DFLT;
  263. m_bTraceFileLineInfo = BS_DBG_TRACE_FILE_LINE_INFO_DFLT;
  264. m_bTraceTimestamp = BS_DBG_TRACE_TIMESTAMP_DFLT;
  265. m_pwszTraceFileName = NULL;
  266. m_bForceFlush = BS_DBG_TRACE_FORCE_FLUSH_DFLT;
  267. m_dwTraceIndent = 0;
  268. m_bInTrace = FALSE;
  269. m_hTraceFile = INVALID_HANDLE_VALUE;
  270. m_dwLineNum = 0;
  271. m_dwCurrentProcessId = GetCurrentProcessId();
  272. m_bIsDuringSetup = FALSE;
  273. LARGE_INTEGER liTimer;
  274. if ( ::QueryPerformanceCounter( &liTimer ) )
  275. {
  276. // Got high performance counter, use the low part
  277. m_dwContextId = liTimer.LowPart;
  278. }
  279. else
  280. {
  281. m_dwContextId = ::GetTickCount();
  282. }
  283. ReadRegistry();
  284. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"****************************************************************" ) );
  285. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"** TRACING STARTED - ProcessId: 0x%x, ContextId: 0x%x",
  286. m_dwCurrentProcessId, m_dwContextId ) );
  287. if ( !bInConstructor )
  288. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"** N.B. NOT INITIALIZED BY THE CONSTRUCTOR" ) );
  289. WCHAR pwszCurrentTime[128];
  290. struct tm *pToday;
  291. time( &m_lTimeStarted );
  292. pToday = localtime( &m_lTimeStarted );
  293. wcsftime( pwszCurrentTime, sizeof pwszCurrentTime, L"%c", pToday );
  294. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"** Current time: %s", pwszCurrentTime ) );
  295. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"** Command-line: %s", GetCommandLineW() ) );
  296. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"** Product version: %d.%d.%d.%d", VER_PRODUCTVERSION ) );
  297. //BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"** VSS SKU ID: 0x%02x", (UINT)CVssSKU::GetSKU() ) );
  298. BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"****************************************************************" ) );
  299. //if ( CVssSKU::GetSKU() == CVssSKU::VSS_SKU_INVALID )
  300. //BsDebugTraceAlways( 0, DEBUG_TRACE_ALL, ( L"ERROR: Unable to determine the Windows SKU" ) );
  301. }
  302. catch(...)
  303. {
  304. delete m_pcs;
  305. m_pcs = NULL;
  306. m_bInitialized = false;
  307. m_bTracingEnabled = false;
  308. }
  309. }
  310. }
  311. BOOL
  312. CBsDbgTrace::IsDuringSetup()
  313. {
  314. return m_bIsDuringSetup;
  315. }
  316. HRESULT
  317. CBsDbgTrace::ReadRegistry()
  318. /*++
  319. Routine Description:
  320. Tries to read debug specific values from the registry and adds
  321. the values if they don't exist.
  322. Arguments:
  323. NONE
  324. Return Value:
  325. HRESULT
  326. --*/
  327. {
  328. DWORD dwRes;
  329. CRegKey cRegKeySetup;
  330. CRegKey cRegKeyTracing;
  331. m_bTracingEnabled = FALSE;
  332. m_bIsDuringSetup = FALSE;
  333. //
  334. // Open the Setup key
  335. //
  336. dwRes = cRegKeySetup.Open( HKEY_LOCAL_MACHINE, SETUP_KEY, KEY_READ );
  337. if ( dwRes == ERROR_SUCCESS ) {
  338. DWORD dwSetupInProgress = 0;
  339. QuerySetValue( cRegKeySetup, dwSetupInProgress, SETUP_INPROGRESS_REG );
  340. m_bIsDuringSetup = ( dwSetupInProgress == SETUP_INPROGRESS_VALUE );
  341. }
  342. //
  343. // Open the VSS tracing key
  344. //
  345. dwRes = cRegKeyTracing.Open( HKEY_LOCAL_MACHINE, VSS_TRACINGKEYPATH, KEY_READ );
  346. if ( dwRes == ERROR_SUCCESS ) {
  347. // The name of the optional trace file
  348. QuerySetValue( cRegKeyTracing, m_pwszTraceFileName, BS_DBG_TRACE_FILE_NAME_REG );
  349. // The trace level determines what type of traciung will occur. Zero
  350. // indicates that no tracing will occur, and is the default.
  351. QuerySetValue( cRegKeyTracing, m_dwTraceLevel, BS_DBG_TRACE_LEVEL_REG );
  352. // The TraceEnterExit flag determines whether or not function entry & exit
  353. // information is output to the trace file & the debug output stream.
  354. QuerySetValue( cRegKeyTracing, m_bTraceEnterExit, BS_DBG_TRACE_ENTER_EXIT_REG );
  355. // The TraceToFile flag determines whether or not trace information is output to
  356. // the trace file. If this value is FALSE, no output is sent to the trace file.
  357. QuerySetValue( cRegKeyTracing, m_bTraceToFile, BS_DBG_TRACE_TO_FILE_REG );
  358. // The TraceToDebugger flag determines whether or not trace information is output
  359. // to the debugger. If this value is FALSE, no output is sent to the debugger.
  360. QuerySetValue( cRegKeyTracing, m_bTraceToDebugger, BS_DBG_TRACE_TO_DEBUGGER_REG );
  361. // The Timestamp flag determines whether or not timestamp
  362. // information is output to the trace file & the debug output stream.
  363. QuerySetValue( cRegKeyTracing, m_bTraceTimestamp, BS_DBG_TRACE_TIMESTAMP_REG );
  364. // The FileLineInfo flag determines whether or not the module file name
  365. // and line number information is output to the trace file & the debug
  366. // output stream.
  367. QuerySetValue( cRegKeyTracing, m_bTraceFileLineInfo, BS_DBG_TRACE_FILE_LINE_INFO_REG );
  368. // The TraceForceFlush flag specifies whether or not after each trace message is
  369. // written to the trace file a forced flush occurs. If enabled, no trace records
  370. // are ever lost, however, performance is greatly reduced.
  371. QuerySetValue( cRegKeyTracing, m_bForceFlush, BS_DBG_TRACE_FORCE_FLUSH_REG );
  372. // Determine if tracing should be enabled
  373. if ( m_bTraceToDebugger || m_bTraceToFile )
  374. m_bTracingEnabled = TRUE;
  375. }
  376. return S_OK;
  377. }
  378. HRESULT
  379. CBsDbgTrace::PrePrint(
  380. IN LPCWSTR pwszSourceFileName,
  381. IN DWORD dwLineNum,
  382. IN DWORD dwIndent,
  383. IN DWORD dwLevel,
  384. IN LPCWSTR pwszFunctionName,
  385. IN BOOL bTraceEnter
  386. )
  387. /*++
  388. Routine Description:
  389. Acquires the critical section so that other threads are
  390. now serialized. Opens the trace file if necessary.
  391. N.B. Any A/V's in this code can cause a hang since the SEH translator function
  392. calls these trace functions.
  393. Arguments:
  394. pszSourceFileName - Source file name of the module whose
  395. code called this method.
  396. dwLineNum - Line number in the source
  397. dwIndent - Number to increase or decrease the indendation level
  398. dwLevel - Trace level that specifies for which component
  399. the code resides in.
  400. pwszFunctionName - For entry/exit tracing. Specifies the
  401. function name constains a call the a trace macro.
  402. bTraceEnter - True if this is a entry trace.
  403. Return Value:
  404. HRESULT
  405. --*/
  406. {
  407. m_pcs->Enter();
  408. //
  409. // Assume the trace macros have already filtered out traces based
  410. // on m_bTracingEnabled and on the active trace level.
  411. //
  412. if ( m_bTracingEnabled && (dwLevel & m_dwTraceLevel) != 0) {
  413. if ( pwszSourceFileName == NULL )
  414. m_pwszSourceFileName = L"(Unknown source file)";
  415. else
  416. {
  417. //
  418. // Keep only two levels deep of directory components
  419. //
  420. LPCWSTR pwszTemp = pwszSourceFileName + ::wcslen( pwszSourceFileName ) - 1;
  421. for ( int i = 0; pwszTemp > pwszSourceFileName && i < 3; ++i )
  422. {
  423. do
  424. {
  425. --pwszTemp;
  426. }
  427. while( *pwszTemp != L'\\' && pwszTemp > pwszSourceFileName ) ;
  428. }
  429. if ( pwszTemp > pwszSourceFileName )
  430. m_pwszSourceFileName = pwszTemp + 1;
  431. else
  432. m_pwszSourceFileName = pwszSourceFileName;
  433. }
  434. m_pwszFunctionName = pwszFunctionName;
  435. m_dwLineNum = dwLineNum;
  436. m_bTraceEnter = bTraceEnter;
  437. BS_ASSERT( m_hTraceFile == INVALID_HANDLE_VALUE );
  438. if ( m_bTraceToFile ) {
  439. m_hTraceFile = ::CreateFile( m_pwszTraceFileName?
  440. m_pwszTraceFileName :
  441. BS_DBG_TRACE_FILE_NAME_DFLT,
  442. GENERIC_WRITE,
  443. FILE_SHARE_READ | FILE_SHARE_WRITE,
  444. NULL,
  445. OPEN_ALWAYS,
  446. FILE_ATTRIBUTE_NORMAL,
  447. NULL );
  448. if ( m_hTraceFile == INVALID_HANDLE_VALUE ) {
  449. //
  450. // Error opening the file, print a message to the debugger if debugger
  451. // tracing is enabled
  452. //
  453. Print( L"CBsDbgTrace::PrePrint: TRACING ERROR: Unable to open trace file, dwRet: %u", ::GetLastError() );
  454. } else {
  455. //
  456. // Now lock the process from other processes and threads that are concurrently
  457. // accessing the file. Just lock the first byte of the file.
  458. //
  459. OVERLAPPED ovStart = { NULL, NULL, { 0, 0 }, 0 };
  460. if ( !::LockFileEx( m_hTraceFile,
  461. LOCKFILE_EXCLUSIVE_LOCK,
  462. 0,
  463. 1,
  464. 0,
  465. &ovStart ) ) {
  466. //
  467. // Tracing to file will be skipped for this record. This should
  468. // never happen in practice.
  469. //
  470. ::CloseHandle( m_hTraceFile );
  471. m_hTraceFile = INVALID_HANDLE_VALUE;
  472. //
  473. // Try printing a trace message that will get to the debugger if debugger
  474. // tracing is enabled
  475. //
  476. Print( L"CBsDbgTrace::PrePrint: TRACING ERROR: Unable to lock trace file, skipping trace record, dwRet: %u", ::GetLastError() );
  477. } else {
  478. //
  479. // If the file is new (empty) put the UNICODE BOM at the beginning of the file
  480. //
  481. LARGE_INTEGER liPointer;
  482. if ( ::GetFileSizeEx( m_hTraceFile, &liPointer ) ) {
  483. if ( liPointer.QuadPart == 0 )
  484. ::MakeFileUnicode( m_hTraceFile );
  485. }
  486. //
  487. // Now move the file pointer to the end of the file
  488. //
  489. liPointer.QuadPart = 0;
  490. if ( !::SetFilePointerEx( m_hTraceFile,
  491. liPointer,
  492. NULL,
  493. FILE_END ) ) {
  494. //
  495. // Don't write to the file since it might overwrite valid records.
  496. // Tracing to file will be skipped for this record. This should
  497. // never happen in practice.
  498. //
  499. ::CloseHandle( m_hTraceFile );
  500. m_hTraceFile = INVALID_HANDLE_VALUE;
  501. //
  502. // Try printing a trace message that will get to the debugger if debugger
  503. // tracing is enabled
  504. //
  505. Print( L"CBsDbgTrace::PrePrint: TRACING ERROR: Unable to set end of file, skipping trace record, dwRet: %u", ::GetLastError() );
  506. }
  507. }
  508. }
  509. }
  510. m_bInTrace = TRUE;
  511. }
  512. return S_OK;
  513. UNREFERENCED_PARAMETER( dwIndent );
  514. }
  515. HRESULT
  516. CBsDbgTrace::PostPrint(
  517. IN DWORD dwIndent
  518. )
  519. /*++
  520. Routine Description:
  521. Releases the critical section so that other threads
  522. can now call perform tracing. Closes the trace file
  523. and resets variables.
  524. Arguments:
  525. dwIndent - Number to increase or decrease the indendation level
  526. Return Value:
  527. HRESULT
  528. --*/
  529. {
  530. if ( m_hTraceFile != INVALID_HANDLE_VALUE ) {
  531. OVERLAPPED ovStart = { NULL, NULL, { 0, 0 }, 0 };
  532. if ( !::UnlockFileEx( m_hTraceFile,
  533. 0,
  534. 1,
  535. 0,
  536. &ovStart ) ) {
  537. Print( L"CBsDbgTrace::PrePrint: TRACING ERROR: Unable to unlock trace file, dwRet: %u", ::GetLastError() );
  538. }
  539. if ( m_bForceFlush )
  540. ::FlushFileBuffers( m_hTraceFile );
  541. ::CloseHandle( m_hTraceFile );
  542. m_hTraceFile = INVALID_HANDLE_VALUE;
  543. }
  544. m_pwszSourceFileName = NULL;
  545. m_pwszFunctionName = NULL;
  546. m_dwLineNum = 0;
  547. m_bInTrace = FALSE;
  548. m_pcs->Leave();
  549. return S_OK;
  550. UNREFERENCED_PARAMETER( dwIndent );
  551. }
  552. HRESULT _cdecl
  553. CBsDbgTrace::Print(
  554. IN LPCWSTR pwszFormatStr,
  555. IN ...
  556. )
  557. /*++
  558. Routine Description:
  559. Formats the trace message out to the trace file and/or debugger.
  560. Arguments:
  561. pwszFormatStr - printf style format string
  562. ... - Arguments for the message
  563. Return Value:
  564. HRESULT
  565. --*/
  566. {
  567. va_list pArg;
  568. if ( m_bInTrace ) {
  569. if ( m_bTraceTimestamp )
  570. swprintf( m_pwszOutBuf,
  571. L"[%010u,",
  572. GetTickCount() );
  573. else
  574. swprintf( m_pwszOutBuf,
  575. L"[-," );
  576. swprintf( m_pwszOutBuf + wcslen( m_pwszOutBuf ),
  577. L"0x%06x:0x%04x:0x%08x] ",
  578. m_dwCurrentProcessId,
  579. GetCurrentThreadId(),
  580. m_dwContextId );
  581. if ( m_bTraceFileLineInfo )
  582. swprintf( m_pwszOutBuf + wcslen( m_pwszOutBuf ),
  583. L"%s(%04u): ",
  584. m_pwszSourceFileName,
  585. m_dwLineNum );
  586. OutputString();
  587. //
  588. // read the variable length parameter list into a formatted string
  589. //
  590. va_start( pArg, pwszFormatStr );
  591. _vsnwprintf( m_pwszOutBuf, BS_DBG_OUT_BUF_SIZE-1, pwszFormatStr, pArg );
  592. va_end( pArg );
  593. OutputString();
  594. //
  595. // Finish up with a carriage return.
  596. //
  597. wcscpy( m_pwszOutBuf, L"\r\n" );
  598. OutputString();
  599. }
  600. return S_OK;
  601. }
  602. HRESULT _cdecl
  603. CBsDbgTrace::PrintEnterExit(
  604. IN LPCWSTR pwszFormatStr,
  605. IN ...
  606. )
  607. /*++
  608. Routine Description:
  609. Formats the entry/exit trace message out to the trace file and/or debugger.
  610. Arguments:
  611. pwszFormatStr - printf style format string
  612. ... - Arguments for the message
  613. Return Value:
  614. HRESULT
  615. --*/
  616. {
  617. va_list pArg;
  618. if ( m_bInTrace ) {
  619. if ( m_bTraceTimestamp )
  620. swprintf( m_pwszOutBuf,
  621. L"[%010u,",
  622. GetTickCount() );
  623. else
  624. swprintf( m_pwszOutBuf,
  625. L"[-," );
  626. swprintf( m_pwszOutBuf + wcslen( m_pwszOutBuf ),
  627. L"0x%06x:0x%04x:0x%08x] %s {%s}: ",
  628. m_dwCurrentProcessId,
  629. GetCurrentThreadId(),
  630. m_dwContextId,
  631. m_bTraceEnter ? L"ENTER" : L"EXIT ",
  632. m_pwszFunctionName );
  633. OutputString();
  634. //
  635. // read the variable length parameter list into a formatted string
  636. //
  637. va_start( pArg, pwszFormatStr );
  638. _vsnwprintf( m_pwszOutBuf, BS_DBG_OUT_BUF_SIZE-1, pwszFormatStr, pArg );
  639. va_end( pArg );
  640. OutputString();
  641. //
  642. // Finish up with a carriage return.
  643. //
  644. wcscpy( m_pwszOutBuf, L"\r\n" );
  645. OutputString();
  646. }
  647. return S_OK;
  648. }
  649. HRESULT
  650. CBsDbgTrace::OutputString()
  651. /*++
  652. Routine Description:
  653. Prints the trace message out to the trace file and/or debugger.
  654. Arguments:
  655. Assumes m_pwszOutBuf has the string to be printed.
  656. Return Value:
  657. HRESULT
  658. --*/
  659. {
  660. //
  661. // Make sure we didn't go off the end. Can't use BS_ASSERT(), it
  662. // will cause an deadlock.
  663. //
  664. _ASSERTE( wcslen( m_pwszOutBuf ) < BS_DBG_OUT_BUF_SIZE );
  665. //
  666. // Print to the debug stream for debug builds
  667. //
  668. if ( m_bTraceToDebugger )
  669. OutputDebugString( m_pwszOutBuf );
  670. //
  671. // If file tracing is enabled, dump to file
  672. //
  673. if ( m_hTraceFile != INVALID_HANDLE_VALUE ) {
  674. DWORD dwBytesWritten;
  675. ::WriteFile( m_hTraceFile,
  676. m_pwszOutBuf,
  677. (DWORD)(wcslen( m_pwszOutBuf ) * sizeof(WCHAR)),
  678. &dwBytesWritten,
  679. NULL );
  680. }
  681. return S_OK;
  682. }
  683. VOID CBsDbgTrace::SetContextNum(
  684. IN DWORD dwContextNum
  685. )
  686. /*++
  687. Routine Description:
  688. Use to be used to set the context number of the operation. Now it is only
  689. used to determine if a DLL is loading using the trace class.
  690. Arguments:
  691. LTS_CONTEXT_DELAYED_DLL - DLL is using the class object.
  692. --*/
  693. {
  694. if (dwContextNum == LTS_CONTEXT_DELAYED_DLL && !m_bInitialized )
  695. {
  696. Initialize();
  697. }
  698. }
  699. /*++
  700. Routine Description:
  701. Puts the UNICODE UCS-2 BOM (Byte Order Mark) at the beginning of the file
  702. to let applications know that 1. this is a UCS-2 UNICODE file and 2. that
  703. the byte ordering is little-endian.
  704. Assumes the file is empty.
  705. Arguments:
  706. hFile - Handle to the file
  707. Return Value:
  708. <Enter return values here>
  709. --*/
  710. static VOID MakeFileUnicode(
  711. IN HANDLE hFile
  712. )
  713. {
  714. BS_ASSERT( hFile != INVALID_HANDLE_VALUE );
  715. BYTE byteBOM[2] = { 0xFF, 0xFE };
  716. DWORD dwBytesWritten;
  717. ::WriteFile( hFile,
  718. byteBOM,
  719. sizeof byteBOM,
  720. &dwBytesWritten,
  721. NULL );
  722. }
  723. void __cdecl CVssFunctionTracer::TranslateError
  724. (
  725. IN CVssDebugInfo dbgInfo, // Caller debugging info
  726. IN HRESULT hr,
  727. IN LPCWSTR wszRoutine
  728. )
  729. /*++
  730. Routine Description:
  731. Translates an error into a well defined error code. May log to
  732. the event log if the error is unexpected
  733. --*/
  734. {
  735. if (hr == E_OUTOFMEMORY ||
  736. hr == HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY) ||
  737. hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_SEARCH_HANDLES) ||
  738. hr == HRESULT_FROM_WIN32(ERROR_NO_LOG_SPACE) ||
  739. hr == HRESULT_FROM_WIN32(ERROR_DISK_FULL) ||
  740. hr == HRESULT_FROM_WIN32(ERROR_NO_SYSTEM_RESOURCES) ||
  741. hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_USER_HANDLES))
  742. Throw(dbgInfo, E_OUTOFMEMORY, L"Out of memory detected in function %s", wszRoutine);
  743. else
  744. {
  745. #ifdef LOG_ERROR
  746. LogError(VSS_ERROR_UNEXPECTED_CALLING_ROUTINE, dbgInfo << wszRoutine << hr);
  747. #endif
  748. Throw(dbgInfo, E_UNEXPECTED, L"Unexpected error in routine %s. hr = 0x%08lx", wszRoutine, hr);
  749. }
  750. }
  751. void __cdecl CVssFunctionTracer::TranslateGenericError
  752. (
  753. IN CVssDebugInfo dbgInfo, // Caller debugging info
  754. IN HRESULT hr,
  755. IN LPCWSTR wszErrorTextFormat,
  756. IN ...
  757. )
  758. /*++
  759. Routine Description:
  760. Translates an error into a well defined error code. May log to
  761. the event log if the error is unexpected
  762. Throws:
  763. E_UNEXPECTED
  764. - on unrecognized error codes
  765. --*/
  766. {
  767. CVssOutputBuffer buffer;
  768. if (!buffer.IsBufferValid())
  769. throw(E_OUTOFMEMORY);
  770. va_list marker;
  771. va_start( marker, wszErrorTextFormat );
  772. _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), wszErrorTextFormat, marker );
  773. va_end( marker );
  774. if (hr == E_OUTOFMEMORY ||
  775. hr == HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY) ||
  776. hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_SEARCH_HANDLES) ||
  777. hr == HRESULT_FROM_WIN32(ERROR_NO_LOG_SPACE) ||
  778. hr == HRESULT_FROM_WIN32(ERROR_DISK_FULL) ||
  779. hr == HRESULT_FROM_WIN32(ERROR_NO_SYSTEM_RESOURCES) ||
  780. hr == HRESULT_FROM_WIN32(ERROR_NO_MORE_USER_HANDLES))
  781. Throw(dbgInfo, E_OUTOFMEMORY, L"Out of memory detected. %s", buffer.GetBuffer());
  782. else
  783. {
  784. #ifdef LOG_ERROR
  785. LogError(VSS_ERROR_UNEXPECTED_ERRORCODE, dbgInfo << buffer.GetBuffer() << hr);
  786. #endif
  787. Throw(dbgInfo, E_UNEXPECTED, L"Unexpected error: %s [hr = 0x%08lx]", buffer.GetBuffer(), hr);
  788. }
  789. }
  790. void __cdecl CVssFunctionTracer::LogGenericWarning
  791. (
  792. IN CVssDebugInfo dbgInfo, // Caller debugging info
  793. IN LPCWSTR wszErrorTextFormat,
  794. IN ...
  795. )
  796. /*++
  797. Routine Description:
  798. Log a generic warning.
  799. --*/
  800. {
  801. CVssOutputBuffer buffer;
  802. if (!buffer.IsBufferValid())
  803. throw(E_OUTOFMEMORY);
  804. va_list marker;
  805. va_start( marker, wszErrorTextFormat );
  806. _vsnwprintf( buffer.GetBuffer(), buffer.GetBufferSize(), wszErrorTextFormat, marker );
  807. va_end( marker );
  808. #ifdef LOG_ERROR
  809. LogError(VSS_WARNING_UNEXPECTED, dbgInfo << buffer.GetBuffer() << hr, EVENTLOG_WARNING_TYPE);
  810. #endif
  811. Trace(dbgInfo, L"WARNING: %s [hr = 0x%08lx]", buffer.GetBuffer(), hr);
  812. }
  813. // This method must be called prior to calling a CoCreateInstance that may start VSS
  814. void CVssFunctionTracer::LogVssStartupAttempt()
  815. {
  816. // the name of the Volume Snapshot Service
  817. const LPCWSTR wszVssvcServiceName = L"VSS";
  818. SC_HANDLE shSCManager = NULL;
  819. SC_HANDLE shSCService = NULL;
  820. try
  821. {
  822. //
  823. // Check to see if VSSVC is running. If not, we are putting an entry into the trace log if enabled.
  824. //
  825. // Connect to the local service control manager
  826. shSCManager = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT);
  827. if (!shSCManager)
  828. TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(GetLastError()),
  829. L"OpenSCManager(NULL,NULL,SC_MANAGER_CONNECT)");
  830. // Get a handle to the service
  831. shSCService = OpenService (shSCManager, wszVssvcServiceName, SERVICE_QUERY_STATUS);
  832. if (!shSCService)
  833. TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(GetLastError()),
  834. L" OpenService (shSCManager, \'%s\', SERVICE_QUERY_STATUS)", wszVssvcServiceName);
  835. // Now query the service to see what state it is in at the moment.
  836. SERVICE_STATUS sSStat;
  837. if (!QueryServiceStatus (shSCService, &sSStat))
  838. TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(GetLastError()),
  839. L"QueryServiceStatus (shSCService, &sSStat)");
  840. // If the service is not running, then we will put an informational error log entry
  841. // if (sSStat.dwCurrentState != SERVICE_RUNNING)
  842. // LogError(VSS_INFO_SERVICE_STARTUP,
  843. // VSSDBG_GEN << GetCommandLineW() << (HRESULT)sSStat.dwCurrentState,
  844. // EVENTLOG_INFORMATION_TYPE);
  845. if (sSStat.dwCurrentState != SERVICE_RUNNING)
  846. Trace( VSSDBG_GEN,
  847. L"Volume Snapshots Service information: Service starting at request of process '%s'. [0x%08x]",
  848. GetCommandLineW(), sSStat.dwCurrentState );
  849. } VSS_STANDARD_CATCH ((*this));
  850. // Close handles
  851. if (NULL != shSCService) CloseServiceHandle (shSCService);
  852. if (NULL != shSCManager) CloseServiceHandle (shSCManager);
  853. }
  854. void CVssFunctionTracer::CoCreateInstanceWithLog(
  855. IN CVssDebugInfo dbgInfo, // Caller debugging info
  856. IN CLSID ServerClassID,
  857. IN LPCWSTR ServerName,
  858. IN DWORD dwContext,
  859. IN IID InterfaceID,
  860. OUT IUnknown ** ppUnknown
  861. )
  862. {
  863. for(int nRetries = 0; nRetries < x_nMaxCoCreateInstanceRetries; nRetries++)
  864. {
  865. hr = ::CoCreateInstance(
  866. ServerClassID,
  867. NULL,
  868. dwContext,
  869. InterfaceID,
  870. (void**)ppUnknown);
  871. if (hr != CO_E_SERVER_EXEC_FAILURE)
  872. break;
  873. }
  874. // Treatment of the error cases
  875. switch(hr)
  876. {
  877. case S_OK:
  878. break;
  879. case E_OUTOFMEMORY:
  880. break;
  881. case CO_E_SERVER_EXEC_FAILURE:
  882. #ifdef LOG_ERROR
  883. LogError( VSS_ERROR_STARTING_COM_SERVER_HEAVYLOAD,
  884. dbgInfo << ServerClassID << ServerName << hr );
  885. #endif
  886. break;
  887. default:
  888. BS_ASSERT(FAILED(hr));
  889. #ifdef LOG_ERROR
  890. LogError( VSS_ERROR_STARTING_COM_SERVER,
  891. dbgInfo << ServerClassID << ServerName << hr );
  892. #endif
  893. break;
  894. }
  895. }