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.

1080 lines
28 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. VerifLog.cpp
  5. Abstract:
  6. This module implements the code for manipulating the AppVerifier log file.
  7. Author:
  8. dmunsil created 04/26/2001
  9. Revision History:
  10. 08/14/2001 robkenny Moved code inside the ShimLib namespace.
  11. 09/21/2001 rparsons Logging code now uses NT calls.
  12. 09/25/2001 rparsons Added critical section.
  13. --*/
  14. #include "avrfutil.h"
  15. #include "ShimHook.h"
  16. #include "VerifLog.h"
  17. #include "strsafe.h"
  18. #include "string.h"
  19. namespace ShimLib
  20. {
  21. typedef struct _VLOG_GLOBAL_DATA {
  22. BOOL bLoggingDisabled; // was logging disabled?
  23. PRTL_CRITICAL_SECTION pcsLogging;
  24. WCHAR szSessionLog[MAX_PATH];
  25. WCHAR szProcessLog[MAX_PATH];
  26. } VLOG_GLOBAL_DATA, *PVLOG_GLOBAL_DATA;
  27. PVLOG_GLOBAL_DATA g_pData = NULL;
  28. HANDLE g_hMap = NULL; // mapping handle for global data
  29. BOOL g_bVerifierLogInited = FALSE; // have we been through the init sequence?
  30. BOOL g_bLoggingDisabled = TRUE; // have we been through the init sequence?
  31. BOOL g_bLogBreakIn = FALSE;
  32. CString g_strSessionLog;
  33. CString g_strProcessLog;
  34. PRTL_CRITICAL_SECTION g_pcsLogging;
  35. LPVOID g_pDllBase; // our own DLL base
  36. LPVOID g_pDllEnd; // one past the DLL's last byte
  37. DWORD g_dwSizeOfImage; // our own DLL image size
  38. void
  39. CheckForDebuggerBreakIn(
  40. void
  41. )
  42. {
  43. WCHAR szExe[MAX_PATH];
  44. if (!GetCurrentExeName(szExe, ARRAYSIZE(szExe))) {
  45. g_bLogBreakIn = FALSE;
  46. }
  47. g_bLogBreakIn = GetShimSettingDWORD(L"General", szExe, AV_BREAKIN, FALSE);
  48. }
  49. BOOL
  50. GetModuleNameAndOffset(
  51. LPVOID lpAddress, // IN return address to search for
  52. LPWSTR lpwszModuleName, // OUT name of module that contains address
  53. DWORD dwBufferChars, // IN size in chars of module name buffer
  54. PDWORD pdwOffset // OUT offset within module
  55. )
  56. {
  57. PPEB Peb = NtCurrentPeb();
  58. PLIST_ENTRY LdrHead;
  59. PLIST_ENTRY LdrNext;
  60. DWORD i;
  61. BOOL bRet = FALSE;
  62. if (!lpAddress || !lpwszModuleName || !pdwOffset) {
  63. return FALSE;
  64. }
  65. //
  66. // search for the module
  67. //
  68. LdrHead = &Peb->Ldr->InMemoryOrderModuleList;
  69. LdrNext = LdrHead->Flink;
  70. while (LdrNext != LdrHead) {
  71. PLDR_DATA_TABLE_ENTRY LdrEntry;
  72. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
  73. //
  74. // Is this it?
  75. //
  76. if (lpAddress >= LdrEntry->DllBase && lpAddress < ((PBYTE)(LdrEntry->DllBase) + LdrEntry->SizeOfImage)) {
  77. //
  78. // we special-case shimeng and ntdll, because we don't want them to be filtered out by the
  79. // "system dll" filter.
  80. //
  81. if (_wcsicmp(LdrEntry->BaseDllName.Buffer, L"shimeng.dll") == 0 || _wcsicmp(LdrEntry->BaseDllName.Buffer, L"ntdll.dll") == 0) {
  82. StringCchCopyW(lpwszModuleName, dwBufferChars, L"?");
  83. *pdwOffset = 0;
  84. } else {
  85. StringCchCopyW(lpwszModuleName, dwBufferChars, LdrEntry->BaseDllName.Buffer);
  86. *pdwOffset = (DWORD)((PBYTE)lpAddress - (PBYTE)(LdrEntry->DllBase));
  87. }
  88. bRet = TRUE;
  89. break;
  90. }
  91. LdrNext = LdrEntry->InMemoryOrderLinks.Flink;
  92. }
  93. return bRet;
  94. }
  95. void
  96. GetCallingModule(
  97. LPWSTR szModule,
  98. DWORD dwChars,
  99. PDWORD pdwOffset
  100. )
  101. {
  102. PVOID apRetAddresses[10];
  103. USHORT unAddresses, i;
  104. BOOL bFound = FALSE;
  105. ULONG ulHash;
  106. //
  107. // On W2K, RtlCaptureStackBackTrace tries to dereference the fourth
  108. // argument (the returned hash) without ensuring that it's valid.
  109. // This causes on an access violation. On XP, the problem has been
  110. // fixed. We get a hash value back, but we'll never use it.
  111. //
  112. unAddresses = RtlCaptureStackBackTrace(3, 10, apRetAddresses, &ulHash);
  113. for (i = 0; i != unAddresses; i++) {
  114. PVOID pAddress = apRetAddresses[i];
  115. if (pAddress < g_pDllBase || pAddress >= g_pDllEnd) {
  116. bFound = GetModuleNameAndOffset(pAddress, szModule, dwChars, pdwOffset);
  117. if (bFound) {
  118. break;
  119. }
  120. }
  121. }
  122. if (!bFound) {
  123. if (pdwOffset) {
  124. *pdwOffset = 0;
  125. }
  126. if (szModule) {
  127. StringCchCopyW(szModule, dwChars, L"?");
  128. }
  129. }
  130. return;
  131. }
  132. /*++
  133. Function Description:
  134. Initializes the globals holding this module's base address and size
  135. Return Value:
  136. none.
  137. History:
  138. 09/26/2001 dmunsil Created
  139. --*/
  140. void
  141. GetCurrentModuleInfo(void)
  142. {
  143. PPEB Peb = NtCurrentPeb();
  144. PLIST_ENTRY LdrHead;
  145. PLIST_ENTRY LdrNext;
  146. DWORD i;
  147. //
  148. // the base address is just the hInst
  149. //
  150. g_pDllBase = (LPVOID)g_hinstDll;
  151. //
  152. // now go find the size of the image by looking through the
  153. // loader's module list
  154. //
  155. LdrHead = &Peb->Ldr->InMemoryOrderModuleList;
  156. LdrNext = LdrHead->Flink;
  157. while (LdrNext != LdrHead) {
  158. PLDR_DATA_TABLE_ENTRY LdrEntry;
  159. LdrEntry = CONTAINING_RECORD(LdrNext, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
  160. //
  161. // Is this it?
  162. //
  163. if (LdrEntry->DllBase == g_pDllBase) {
  164. g_dwSizeOfImage = LdrEntry->SizeOfImage;
  165. g_pDllEnd = (PVOID)((PBYTE)g_pDllBase + g_dwSizeOfImage);
  166. break;
  167. }
  168. LdrNext = LdrEntry->InMemoryOrderLinks.Flink;
  169. }
  170. }
  171. /*++
  172. Function Description:
  173. Initializes the support for file logging.
  174. Return Value:
  175. TRUE if successful, FALSE if failed
  176. History:
  177. 04/26/2001 dmunsil Created
  178. 09/27/2001 rparsons Converted to use NT calls
  179. --*/
  180. BOOL
  181. InitVerifierLogSupport(void)
  182. {
  183. CString strProcessPath;
  184. CString strProcessName;
  185. CString strTemp;
  186. SYSTEMTIME LocalTime;
  187. CString strTime;
  188. CString strShared;
  189. char *szTemp;
  190. int nTemp;
  191. BOOL bAlreadyInited;
  192. BOOL bSuccess = FALSE;
  193. DWORD cchSize;
  194. DWORD dwID;
  195. DWORD dwErr;
  196. WCHAR wszVLogPath[MAX_PATH];
  197. NTSTATUS status;
  198. UNICODE_STRING strLogFile = {0};
  199. OBJECT_ATTRIBUTES ObjectAttributes;
  200. IO_STATUS_BLOCK IoStatusBlock;
  201. HANDLE hFile = INVALID_HANDLE_VALUE;
  202. //
  203. // if we've already been inited, get out
  204. //
  205. if (g_bVerifierLogInited) {
  206. return FALSE;
  207. }
  208. g_bVerifierLogInited = TRUE;
  209. CheckForDebuggerBreakIn();
  210. //
  211. // get the current module's base address and size
  212. //
  213. GetCurrentModuleInfo();
  214. //
  215. // first check for a shared memory block
  216. //
  217. dwID = GetCurrentProcessId();
  218. strShared.Format(L"VeriferLog_%08X", dwID);
  219. g_hMap = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, strShared.GetAnsi());
  220. if (g_hMap) {
  221. bAlreadyInited = TRUE;
  222. } else {
  223. bAlreadyInited = FALSE;
  224. g_hMap = CreateFileMapping(INVALID_HANDLE_VALUE,
  225. NULL,
  226. PAGE_READWRITE,
  227. 0,
  228. sizeof(VLOG_GLOBAL_DATA),
  229. strShared.GetAnsi());
  230. }
  231. if (!g_hMap) {
  232. DPF("VerifierLog", eDbgLevelError, "Cannot get shared global data.");
  233. g_bLoggingDisabled = TRUE;
  234. return FALSE;
  235. }
  236. g_pData = (PVLOG_GLOBAL_DATA)MapViewOfFile(g_hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  237. if (!g_pData) {
  238. DPF("VerifierLog", eDbgLevelError, "Cannot map shared global data.");
  239. g_bLoggingDisabled = TRUE;
  240. return FALSE;
  241. }
  242. if (bAlreadyInited) {
  243. if (g_pData->szProcessLog[0] == 0 || g_pData->szSessionLog[0] == 0) {
  244. g_bLoggingDisabled = TRUE;
  245. g_pData->bLoggingDisabled = TRUE;
  246. return FALSE;
  247. }
  248. g_bLoggingDisabled = g_pData->bLoggingDisabled;
  249. g_strSessionLog = g_pData->szSessionLog;
  250. g_strProcessLog = g_pData->szProcessLog;
  251. g_pcsLogging = g_pData->pcsLogging;
  252. return TRUE;
  253. } else {
  254. //
  255. // we need to init the file mapping, so temporarily disable logging, just in case.
  256. //
  257. g_pData->bLoggingDisabled = TRUE;
  258. //
  259. // Initialize the critical section. We allocate memory so that we'll point
  260. // to one CS for every shim. Note that we don't free this as there are
  261. // several places we can exit.
  262. //
  263. g_pcsLogging = (PRTL_CRITICAL_SECTION)ShimMalloc(sizeof(RTL_CRITICAL_SECTION));
  264. if (!g_pcsLogging) {
  265. DPF("VerifierLog", eDbgLevelError, "No memory for critical section.");
  266. return FALSE;
  267. }
  268. status = RtlInitializeCriticalSectionAndSpinCount(g_pcsLogging, 0x80000000 | 4000);
  269. if (!NT_SUCCESS(status)) {
  270. DPF("VerifierLog", eDbgLevelError, "Failed to init critical section.");
  271. return FALSE;
  272. }
  273. //
  274. // First, check that log directory exists; if not, we're not logging
  275. //
  276. cchSize = GetAppVerifierLogPath(wszVLogPath, ARRAYSIZE(wszVLogPath));
  277. if (cchSize > ARRAYSIZE(wszVLogPath) || cchSize == 0) {
  278. DPF("VerifierLog", eDbgLevelError, "Buffer for log path is too small.");
  279. g_bLoggingDisabled = TRUE;
  280. return FALSE;
  281. }
  282. if (GetFileAttributesW(wszVLogPath) == -1) {
  283. DPF("VerifierLog", eDbgLevelInfo, "No log directory %ls. Logging disabled.", wszVLogPath);
  284. g_bLoggingDisabled = TRUE;
  285. return FALSE;
  286. }
  287. //
  288. // Next, check for the existence of session.log. If it's not there,
  289. // we're not logging
  290. //
  291. g_strSessionLog = wszVLogPath;
  292. g_strSessionLog += L"\\session.log";
  293. if (GetFileAttributesW(g_strSessionLog.Get()) == -1) {
  294. DPF("VerifierLog", eDbgLevelInfo, "No session log file '%ls'. Logging disabled.", g_strSessionLog.Get());
  295. g_bLoggingDisabled = TRUE;
  296. return FALSE;
  297. }
  298. //
  299. // get the process log file name
  300. //
  301. if (strProcessPath.GetModuleFileNameW(NULL) == 0) {
  302. DPF("VerifierLog", eDbgLevelError, "Cannot get module file name.");
  303. g_bLoggingDisabled = TRUE;
  304. return FALSE;
  305. }
  306. //
  307. // strip out just the name minus path and extension
  308. //
  309. strProcessPath.SplitPath(NULL, NULL, &strProcessName, NULL);
  310. //
  311. // combine into log name, find first available
  312. //
  313. nTemp = 0;
  314. do {
  315. g_strProcessLog.Format(L"%ls\\%ls%d.%ls", wszVLogPath, strProcessName.Get(), nTemp, L"log");
  316. nTemp++;
  317. } while (GetFileAttributesW(g_strProcessLog.Get()) != -1);
  318. //
  319. // Convert the path to the log file from DOS to NT.
  320. //
  321. bSuccess = RtlDosPathNameToNtPathName_U(g_strProcessLog.Get(), &strLogFile, NULL, NULL);
  322. if (!bSuccess) {
  323. DPF("VerifierLog",
  324. eDbgLevelError,
  325. "Failed to convert log file '%ls' to NT path",
  326. g_strProcessLog.Get());
  327. return FALSE;
  328. }
  329. //
  330. // Attempt to get a handle to our log file.
  331. // Truncate the file if it already exists.
  332. //
  333. InitializeObjectAttributes(&ObjectAttributes,
  334. &strLogFile,
  335. OBJ_CASE_INSENSITIVE,
  336. NULL,
  337. NULL);
  338. status = NtCreateFile(&hFile,
  339. GENERIC_ALL | SYNCHRONIZE,
  340. &ObjectAttributes,
  341. &IoStatusBlock,
  342. NULL,
  343. FILE_ATTRIBUTE_NORMAL,
  344. 0,
  345. FILE_OPEN_IF,
  346. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  347. NULL,
  348. 0);
  349. RtlFreeUnicodeString(&strLogFile);
  350. if (!NT_SUCCESS(status)) {
  351. DPF("VerifierLog", eDbgLevelError, "0x%X Failed to open log file %ls",
  352. status, g_strProcessLog.Get());
  353. g_bLoggingDisabled = TRUE;
  354. return FALSE;
  355. }
  356. NtClose(hFile);
  357. //
  358. // put the info in the session log and the process log
  359. //
  360. g_pData->bLoggingDisabled = FALSE;
  361. g_bLoggingDisabled = FALSE;
  362. //
  363. // I realize these pointers point to process-specific memory, but since
  364. // this mapping is only shared by this process, it seems safe.
  365. //
  366. StringCchCopyW(g_pData->szProcessLog, ARRAYSIZE(g_pData->szProcessLog), g_strProcessLog);
  367. StringCchCopyW(g_pData->szSessionLog, ARRAYSIZE(g_pData->szSessionLog), g_strSessionLog);
  368. GetLocalTime(&LocalTime);
  369. strTime.Format(L"%d/%d/%d %d:%02d:%02d",
  370. LocalTime.wMonth,
  371. LocalTime.wDay,
  372. LocalTime.wYear,
  373. LocalTime.wHour,
  374. LocalTime.wMinute,
  375. LocalTime.wSecond
  376. );
  377. strTemp.Format(L"# LOG_BEGIN %ls '%ls' '%ls'", strTime.Get(),
  378. strProcessPath.Get(), g_strProcessLog.Get());
  379. szTemp = strTemp.GetAnsi();
  380. WriteToProcessLog(szTemp);
  381. WriteToSessionLog(szTemp);
  382. }
  383. return TRUE;
  384. }
  385. /*++
  386. Function Description:
  387. clean up all our shared file resources
  388. History:
  389. 04/26/2001 dmunsil Created
  390. --*/
  391. void
  392. ReleaseVerifierLogSupport(void)
  393. {
  394. g_bLoggingDisabled = TRUE;
  395. if (g_pData) {
  396. UnmapViewOfFile(g_pData);
  397. g_pData = NULL;
  398. if (g_hMap) {
  399. CloseHandle(g_hMap);
  400. g_hMap = NULL;
  401. }
  402. }
  403. }
  404. /*++
  405. Function Description:
  406. Logs a problem that the verifier has found
  407. History:
  408. 04/26/2001 dmunsil Created
  409. --*/
  410. void
  411. CVerifierLog::VLog(
  412. VLOG_LEVEL eLevel,
  413. DWORD dwLogNum,
  414. LPCSTR pszFmt,
  415. ...
  416. )
  417. {
  418. char szT[1024];
  419. char *szTemp;
  420. int nLen;
  421. int nRemain;
  422. va_list arglist;
  423. DWORD dwOffset = 0;
  424. WCHAR szModule[256];
  425. if (g_bLoggingDisabled) {
  426. return;
  427. }
  428. GetCallingModule(szModule, 256, &dwOffset);
  429. StringCchPrintfA(szT,
  430. ARRAYSIZE(szT),
  431. "| %ls %d | %d %ls %X'",
  432. m_strShimName.Get(),
  433. dwLogNum,
  434. eLevel,
  435. szModule,
  436. dwOffset);
  437. nLen = lstrlen(szT);
  438. szTemp = szT + nLen;
  439. nRemain = 1024 - nLen;
  440. if (nRemain > 0) {
  441. va_start(arglist, pszFmt);
  442. StringCchVPrintfA(szTemp, nRemain, pszFmt, arglist);
  443. va_end(arglist);
  444. }
  445. WriteToProcessLog(szT);
  446. if (g_bLogBreakIn) {
  447. OutputDebugString(szT);
  448. DbgBreakPoint();
  449. }
  450. }
  451. /*++
  452. Function Description:
  453. Dumps the header for a shim that tells how many log entries it has.
  454. History:
  455. 04/26/2001 dmunsil Created
  456. --*/
  457. void
  458. CVerifierLog::DumpShimHeader(void)
  459. {
  460. char szT[1024];
  461. if (m_bHeaderDumped) {
  462. return;
  463. }
  464. StringCchPrintfA(szT, ARRAYSIZE(szT), "# SHIM_BEGIN %ls %d", m_strShimName.Get(), m_dwEntries);
  465. WriteToProcessLog(szT);
  466. m_bHeaderDumped = TRUE;
  467. }
  468. /*++
  469. Function Description:
  470. Dumps into the log the text string associated with
  471. each log entry. These are dumped before logging begins, just to
  472. provide the strings necessary for the verifier UI to display them
  473. Return Value:
  474. History:
  475. 04/26/2001 dmunsil Created
  476. --*/
  477. void
  478. CVerifierLog::DumpLogEntry(
  479. DWORD dwLogNum,
  480. UINT unResTitle,
  481. UINT unResDescription,
  482. UINT unResURL
  483. )
  484. {
  485. WCHAR szRes[1024];
  486. char szLine[4096];
  487. if (g_bLoggingDisabled) {
  488. return;
  489. }
  490. //
  491. // dump the header, if necessary
  492. //
  493. DumpShimHeader();
  494. if (!VLogLoadString(g_hinstDll, unResTitle, szRes, 1024)) {
  495. DPF("VerifierLog", eDbgLevelError, "No string resource found for title.");
  496. szRes[0] = 0;
  497. }
  498. StringCchPrintfA(szLine, ARRAYSIZE(szLine), "# LOGENTRY %ls %d '%ls", m_strShimName.Get(), dwLogNum, szRes);
  499. WriteToProcessLog(szLine);
  500. if (!VLogLoadString(g_hinstDll, unResDescription, szRes, 1024)) {
  501. DPF("VerifierLog", eDbgLevelWarning, "No string resource found for description.");
  502. szRes[0] = 0;
  503. }
  504. if (szRes[0]) {
  505. WriteToProcessLog("# DESCRIPTION BEGIN");
  506. StringCchPrintfA(szLine, ARRAYSIZE(szLine), "%ls", szRes);
  507. WriteToProcessLog(szLine);
  508. WriteToProcessLog("# DESCRIPTION END");
  509. }
  510. if (!VLogLoadString(g_hinstDll, unResURL, szRes, 1024)) {
  511. DPF("VerifierLog", eDbgLevelWarning, "No string resource found for URL.");
  512. szRes[0] = 0;
  513. }
  514. if (szRes[0]) {
  515. StringCchPrintfA(szLine, ARRAYSIZE(szLine), "# URL '%ls", szRes);
  516. WriteToProcessLog(szLine);
  517. }
  518. }
  519. /*++
  520. Function Description:
  521. Writes a line of text to the process log file
  522. Return Value:
  523. History:
  524. 04/26/2001 dmunsil Created
  525. 09/21/2001 rparsons Converted to NT calls
  526. --*/
  527. void
  528. WriteToProcessLog(
  529. LPCSTR szLine
  530. )
  531. {
  532. int nLen = 0;
  533. OBJECT_ATTRIBUTES ObjectAttributes;
  534. IO_STATUS_BLOCK IoStatusBlock;
  535. LARGE_INTEGER liOffset;
  536. UNICODE_STRING strLogFile = {0};
  537. NTSTATUS status;
  538. char szNewLine[] = "\r\n";
  539. HANDLE hFile = INVALID_HANDLE_VALUE;
  540. BOOL bSuccess = FALSE;
  541. if (g_bLoggingDisabled) {
  542. return;
  543. }
  544. //
  545. // Convert the path to the log file from DOS to NT.
  546. //
  547. bSuccess = RtlDosPathNameToNtPathName_U(g_strProcessLog.Get(), &strLogFile, NULL, NULL);
  548. if (!bSuccess) {
  549. DPF("VerifierLog",
  550. eDbgLevelError,
  551. "[WriteToProcessLog] Failed to convert log file '%ls' to NT path",
  552. g_strProcessLog.Get());
  553. return;
  554. }
  555. //
  556. // Attempt to get a handle to our log file.
  557. //
  558. InitializeObjectAttributes(&ObjectAttributes,
  559. &strLogFile,
  560. OBJ_CASE_INSENSITIVE,
  561. NULL,
  562. NULL);
  563. status = NtCreateFile(&hFile,
  564. FILE_APPEND_DATA | SYNCHRONIZE,
  565. &ObjectAttributes,
  566. &IoStatusBlock,
  567. NULL,
  568. FILE_ATTRIBUTE_NORMAL,
  569. 0,
  570. FILE_OPEN,
  571. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  572. NULL,
  573. 0);
  574. RtlFreeUnicodeString(&strLogFile);
  575. if (!NT_SUCCESS(status)) {
  576. DPF("VerifierLog", eDbgLevelError, "[WriteToProcessLog] 0x%X Failed to open log file %ls",
  577. status, g_strProcessLog.Get());
  578. return;
  579. }
  580. //
  581. // Make sure we have no '\n' or '\r' at the end of the string.
  582. //
  583. nLen = lstrlen(szLine);
  584. while (nLen && (szLine[nLen - 1] == '\n' || szLine[nLen - 1] == '\r')) {
  585. nLen--;
  586. }
  587. //
  588. // Write the data out to the file.
  589. //
  590. IoStatusBlock.Status = 0;
  591. IoStatusBlock.Information = 0;
  592. liOffset.LowPart = 0;
  593. liOffset.HighPart = 0;
  594. //
  595. // Enter a critical section to ensure that log entries are in the proper order.
  596. //
  597. RtlEnterCriticalSection(g_pcsLogging);
  598. status = NtWriteFile(hFile,
  599. NULL,
  600. NULL,
  601. NULL,
  602. &IoStatusBlock,
  603. (PVOID)szLine,
  604. (ULONG)nLen,
  605. &liOffset,
  606. NULL);
  607. if (!NT_SUCCESS(status)) {
  608. DPF("VerifierLog", eDbgLevelError, "[WriteToProcessLog] 0x%X Failed to make entry in log file",
  609. status);
  610. goto exit;
  611. }
  612. //
  613. // Now write a new line to the log file.
  614. //
  615. IoStatusBlock.Status = 0;
  616. IoStatusBlock.Information = 0;
  617. liOffset.LowPart = 0;
  618. liOffset.HighPart = 0;
  619. nLen = lstrlen(szNewLine);
  620. status = NtWriteFile(hFile,
  621. NULL,
  622. NULL,
  623. NULL,
  624. &IoStatusBlock,
  625. (PVOID)szNewLine,
  626. (ULONG)nLen,
  627. &liOffset,
  628. NULL);
  629. if (!NT_SUCCESS(status)) {
  630. DPF("VerifierLog", eDbgLevelError, "[WriteToProcessLog] 0x%X Failed to write new line to log file",
  631. status);
  632. goto exit;
  633. }
  634. //
  635. // Dump it out to the debugger on checked builds.
  636. //
  637. #if DBG
  638. DebugPrintf("VerifierLog", eDbgLevelInfo, szLine);
  639. DebugPrintf("VerifierLog", eDbgLevelInfo, szNewLine);
  640. #endif // DBG
  641. exit:
  642. if (INVALID_HANDLE_VALUE != hFile) {
  643. NtClose(hFile);
  644. hFile = INVALID_HANDLE_VALUE;
  645. }
  646. RtlLeaveCriticalSection(g_pcsLogging);
  647. }
  648. /*++
  649. Function Description:
  650. Writes a line of text to the session log file
  651. Return Value:
  652. History:
  653. 04/26/2001 dmunsil Created
  654. 09/21/2001 rparsons Converted to NT calls
  655. --*/
  656. void
  657. WriteToSessionLog(
  658. LPCSTR szLine
  659. )
  660. {
  661. int nLen = 0;
  662. OBJECT_ATTRIBUTES ObjectAttributes;
  663. IO_STATUS_BLOCK IoStatusBlock;
  664. LARGE_INTEGER liOffset;
  665. UNICODE_STRING strLogFile = {0};
  666. NTSTATUS status;
  667. char szNewLine[] = "\r\n";
  668. HANDLE hFile = INVALID_HANDLE_VALUE;
  669. BOOL bSuccess = FALSE;
  670. if (g_bLoggingDisabled) {
  671. return;
  672. }
  673. //
  674. // Convert the path to the log file from DOS to NT.
  675. //
  676. bSuccess = RtlDosPathNameToNtPathName_U(g_strSessionLog.Get(), &strLogFile, NULL, NULL);
  677. if (!bSuccess) {
  678. DPF("VerifierLog",
  679. eDbgLevelError,
  680. "[WriteToSessionLog] Failed to convert log file '%ls' to NT path",
  681. g_strSessionLog.Get());
  682. return;
  683. }
  684. //
  685. // Attempt to get a handle to our log file.
  686. //
  687. InitializeObjectAttributes(&ObjectAttributes,
  688. &strLogFile,
  689. OBJ_CASE_INSENSITIVE,
  690. NULL,
  691. NULL);
  692. status = NtCreateFile(&hFile,
  693. FILE_APPEND_DATA | SYNCHRONIZE,
  694. &ObjectAttributes,
  695. &IoStatusBlock,
  696. NULL,
  697. FILE_ATTRIBUTE_NORMAL,
  698. 0,
  699. FILE_OPEN,
  700. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  701. NULL,
  702. 0);
  703. RtlFreeUnicodeString(&strLogFile);
  704. if (!NT_SUCCESS(status)) {
  705. DPF("VerifierLog", eDbgLevelError, "[WriteToSessionLog] 0x%X Failed to open log file %ls",
  706. status, g_strProcessLog.Get());
  707. return;
  708. }
  709. //
  710. // Make sure we have no '\n' or '\r' at the end of the string.
  711. //
  712. nLen = lstrlen(szLine);
  713. while (nLen && (szLine[nLen - 1] == '\n' || szLine[nLen - 1] == '\r')) {
  714. nLen--;
  715. }
  716. //
  717. // Write the data out to the file.
  718. //
  719. IoStatusBlock.Status = 0;
  720. IoStatusBlock.Information = 0;
  721. liOffset.LowPart = 0;
  722. liOffset.HighPart = 0;
  723. //
  724. // Enter a critical section to ensure that log entries are in the proper order.
  725. //
  726. RtlEnterCriticalSection(g_pcsLogging);
  727. status = NtWriteFile(hFile,
  728. NULL,
  729. NULL,
  730. NULL,
  731. &IoStatusBlock,
  732. (PVOID)szLine,
  733. (ULONG)nLen,
  734. &liOffset,
  735. NULL);
  736. if (!NT_SUCCESS(status)) {
  737. DPF("VerifierLog", eDbgLevelError, "[WriteToSessionLog] 0x%X Failed to make entry in log file",
  738. status);
  739. goto exit;
  740. }
  741. //
  742. // Now write a new line to the log file.
  743. //
  744. IoStatusBlock.Status = 0;
  745. IoStatusBlock.Information = 0;
  746. liOffset.LowPart = 0;
  747. liOffset.HighPart = 0;
  748. nLen = lstrlen(szNewLine);
  749. status = NtWriteFile(hFile,
  750. NULL,
  751. NULL,
  752. NULL,
  753. &IoStatusBlock,
  754. (PVOID)szNewLine,
  755. (ULONG)nLen,
  756. &liOffset,
  757. NULL);
  758. if (!NT_SUCCESS(status)) {
  759. DPF("VerifierLog", eDbgLevelError, "[WriteToSessionLog] 0x%X Failed to write new line to log file",
  760. status);
  761. goto exit;
  762. }
  763. //
  764. // Dump it out to the debugger on checked builds.
  765. //
  766. #if DBG
  767. DebugPrintf("VerifierLog", eDbgLevelInfo, szLine);
  768. DebugPrintf("VerifierLog", eDbgLevelInfo, szNewLine);
  769. #endif // DBG
  770. exit:
  771. if (INVALID_HANDLE_VALUE != hFile) {
  772. NtClose(hFile);
  773. hFile = INVALID_HANDLE_VALUE;
  774. }
  775. RtlLeaveCriticalSection(g_pcsLogging);
  776. }
  777. int VLogLoadString(
  778. HMODULE hModule,
  779. UINT wID,
  780. LPWSTR lpBuffer, // Unicode buffer
  781. int cchBufferMax)
  782. {
  783. HRSRC hResInfo;
  784. HANDLE hStringSeg;
  785. LPWSTR lpsz;
  786. int cch;
  787. /*
  788. * Make sure the parms are valid.
  789. */
  790. if (lpBuffer == NULL) {
  791. DPF("VLogLoadString", eDbgLevelWarning, "LoadStringOrError: lpBuffer == NULL");
  792. return 0;
  793. }
  794. cch = 0;
  795. /*
  796. * String Tables are broken up into 16 string segments. Find the segment
  797. * containing the string we are interested in.
  798. */
  799. if (hResInfo = FindResourceW(hModule, (LPWSTR)ULongToPtr( ((LONG)(((USHORT)wID >> 4) + 1)) ), (LPWSTR)RT_STRING)) {
  800. /*
  801. * Load that segment.
  802. */
  803. hStringSeg = LoadResource(hModule, hResInfo);
  804. /*
  805. * Lock the resource.
  806. */
  807. if (lpsz = (LPWSTR)LockResource(hStringSeg)) {
  808. /*
  809. * Move past the other strings in this segment.
  810. * (16 strings in a segment -> & 0x0F)
  811. */
  812. wID &= 0x0F;
  813. while (TRUE) {
  814. cch = *((WCHAR *)lpsz++); // PASCAL like string count
  815. // first WCHAR is count of WCHARs
  816. if (wID-- == 0) break;
  817. lpsz += cch; // Step to start if next string
  818. }
  819. /*
  820. * chhBufferMax == 0 means return a pointer to the read-only resource buffer.
  821. */
  822. if (cchBufferMax == 0) {
  823. *(LPWSTR *)lpBuffer = lpsz;
  824. } else {
  825. /*
  826. * Account for the NULL
  827. */
  828. cchBufferMax--;
  829. /*
  830. * Don't copy more than the max allowed.
  831. */
  832. if (cch > cchBufferMax)
  833. cch = cchBufferMax;
  834. /*
  835. * Copy the string into the buffer.
  836. */
  837. RtlCopyMemory(lpBuffer, lpsz, cch*sizeof(WCHAR));
  838. }
  839. /*
  840. * Unlock resource, but don't free it - better performance this
  841. * way.
  842. */
  843. UnlockResource(hStringSeg);
  844. }
  845. }
  846. /*
  847. * Append a NULL.
  848. */
  849. if (cchBufferMax != 0) {
  850. lpBuffer[cch] = 0;
  851. }
  852. return cch;
  853. }
  854. }; // end of namespace ShimLib