Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1333 lines
34 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. recovery.c
  5. Abstract:
  6. A number of utilities for safe/recovery mode
  7. Author:
  8. Calin Negreanu (calinn) 6-Aug-1999
  9. Revisions:
  10. --*/
  11. #include "pch.h"
  12. BOOL g_SafeModeInitialized = FALSE;
  13. BOOL g_SafeModeActive = FALSE;
  14. PCSTR g_SafeModeFileA = NULL;
  15. PCWSTR g_SafeModeFileW = NULL;
  16. HANDLE g_SafeModeFileHandle = INVALID_HANDLE_VALUE;
  17. HASHTABLE g_SafeModeCrashTable = NULL;
  18. BOOL g_ExceptionOccured = FALSE;
  19. typedef struct {
  20. ULONG Signature;
  21. ULONG NumCrashes;
  22. } SAFEMODE_HEADER, *PSAFEMODE_HEADER;
  23. typedef struct {
  24. ULONG CrashId;
  25. ULONG CrashStrSize;
  26. } CRASHDATA_HEADER, *PCRASHDATA_HEADER;
  27. typedef struct _SAFEMODE_NODE {
  28. DWORD FilePtr;
  29. struct _SAFEMODE_NODE *Next;
  30. } SAFEMODE_NODE, *PSAFEMODE_NODE;
  31. PSAFEMODE_NODE g_SafeModeLastNode = NULL;
  32. PSAFEMODE_NODE g_SafeModeCurrentNode = NULL;
  33. POOLHANDLE g_SafeModePool = NULL;
  34. #define SAFE_MODE_SIGNATURE 0x45464153
  35. /*++
  36. Routine Description:
  37. pGenerateCrashString generates a crash string given an identifier and a string
  38. The generated string will look like <Id>-<String>
  39. Arguments:
  40. Id - Safe mode identifier
  41. String - Safe mode string
  42. Return Value:
  43. A pointer to a crash string allocated from g_SafeModePool
  44. The caller must free the memory by calling PoolMemReleaseMemory
  45. --*/
  46. PCSTR
  47. pGenerateCrashStringA (
  48. IN ULONG Id,
  49. IN PCSTR String
  50. )
  51. {
  52. CHAR idStr [sizeof (ULONG) * 2 + 1];
  53. _ultoa (Id, idStr, 16);
  54. return JoinTextExA (g_SafeModePool, idStr, String, "-", 0, NULL);
  55. }
  56. PCWSTR
  57. pGenerateCrashStringW (
  58. IN ULONG Id,
  59. IN PCWSTR String
  60. )
  61. {
  62. WCHAR idStr [sizeof (ULONG) * 2 + 1];
  63. _ultow (Id, idStr, 16);
  64. return JoinTextExW (g_SafeModePool, idStr, String, L"-", 0, NULL);
  65. }
  66. /*++
  67. Routine Description:
  68. pSafeModeOpenAndResetFile opens the safe mode file looking for
  69. crash strings stored here. It will also reset the part that is
  70. dealing with nested calls by extracting the inner most crash string
  71. stored there.
  72. Arguments:
  73. None
  74. Return Value:
  75. TRUE if the function completed successfully, FALSE otherwise
  76. --*/
  77. BOOL
  78. pSafeModeOpenAndResetFileA (
  79. VOID
  80. )
  81. {
  82. SAFEMODE_HEADER header;
  83. CRASHDATA_HEADER crashData;
  84. DWORD lastFilePtr;
  85. DWORD noBytes;
  86. PSTR crashString = NULL;
  87. PSTR lastCrashString = NULL;
  88. ULONG lastCrashId;
  89. PCSTR completeCrashString;
  90. //
  91. // Open the existing safe mode file or create a
  92. // new one.
  93. //
  94. g_SafeModeFileHandle = CreateFileA (
  95. g_SafeModeFileA,
  96. GENERIC_READ | GENERIC_WRITE,
  97. 0,
  98. NULL,
  99. OPEN_ALWAYS,
  100. FILE_ATTRIBUTE_HIDDEN,
  101. NULL
  102. );
  103. if (g_SafeModeFileHandle != INVALID_HANDLE_VALUE) {
  104. //
  105. // Let's try to read our header. If signature does
  106. // match we will try to read extra data.
  107. //
  108. if (ReadFile (
  109. g_SafeModeFileHandle,
  110. &header,
  111. sizeof (SAFEMODE_HEADER),
  112. &noBytes,
  113. NULL
  114. ) &&
  115. (noBytes == sizeof (SAFEMODE_HEADER)) &&
  116. (header.Signature == SAFE_MODE_SIGNATURE)
  117. ) {
  118. //
  119. // we know now we had an valid safe mode file. Enter safe mode.
  120. //
  121. g_SafeModeActive = TRUE;
  122. LOGA ((LOG_ERROR, "Setup detected a crash on the previous upgrade attempt. Setup is running in safe mode."));
  123. LOGA ((LOG_WARNING, "Setup has run in safe mode %d time(s).", header.NumCrashes));
  124. //
  125. // we need to initialize safe mode crash table
  126. //
  127. g_SafeModeCrashTable = HtAllocA ();
  128. //
  129. // Now, let's read all crash data, a ULONG and a string at a time
  130. //
  131. lastFilePtr = SetFilePointer (
  132. g_SafeModeFileHandle,
  133. 0,
  134. NULL,
  135. FILE_CURRENT
  136. );
  137. while (TRUE) {
  138. if (!ReadFile (
  139. g_SafeModeFileHandle,
  140. &crashData,
  141. sizeof (CRASHDATA_HEADER),
  142. &noBytes,
  143. NULL
  144. ) ||
  145. (noBytes != sizeof (CRASHDATA_HEADER))
  146. ) {
  147. break;
  148. }
  149. if ((crashData.CrashId == 0) &&
  150. (crashData.CrashStrSize == 0)
  151. ) {
  152. //
  153. // we crashed inside a nested guard. We need to
  154. // extract the inner guard we crashed in.
  155. //
  156. lastCrashId = 0;
  157. lastCrashString = NULL;
  158. while (TRUE) {
  159. if (!ReadFile (
  160. g_SafeModeFileHandle,
  161. &crashData,
  162. sizeof (CRASHDATA_HEADER),
  163. &noBytes,
  164. NULL
  165. ) ||
  166. (noBytes != sizeof (CRASHDATA_HEADER))
  167. ) {
  168. crashData.CrashId = 0;
  169. break;
  170. }
  171. crashString = AllocPathStringA (crashData.CrashStrSize);
  172. if (!ReadFile (
  173. g_SafeModeFileHandle,
  174. crashString,
  175. crashData.CrashStrSize,
  176. &noBytes,
  177. NULL
  178. ) ||
  179. (noBytes != crashData.CrashStrSize)
  180. ) {
  181. crashData.CrashId = 0;
  182. FreePathStringA (crashString);
  183. break;
  184. }
  185. if (lastCrashString) {
  186. FreePathStringA (lastCrashString);
  187. }
  188. lastCrashId = crashData.CrashId;
  189. lastCrashString = crashString;
  190. }
  191. if (lastCrashId && lastCrashString) {
  192. //
  193. // we found the inner guard we crashed in. Let's put this into
  194. // the right place.
  195. //
  196. SetFilePointer (
  197. g_SafeModeFileHandle,
  198. lastFilePtr,
  199. NULL,
  200. FILE_BEGIN
  201. );
  202. crashData.CrashId = lastCrashId;
  203. crashData.CrashStrSize = SizeOfStringA (lastCrashString);
  204. WriteFile (
  205. g_SafeModeFileHandle,
  206. &crashData,
  207. sizeof (CRASHDATA_HEADER),
  208. &noBytes,
  209. NULL
  210. );
  211. WriteFile (
  212. g_SafeModeFileHandle,
  213. lastCrashString,
  214. crashData.CrashStrSize,
  215. &noBytes,
  216. NULL
  217. );
  218. //
  219. // store this information in Safe Mode crash table
  220. //
  221. completeCrashString = pGenerateCrashStringA (crashData.CrashId, crashString);
  222. HtAddStringA (g_SafeModeCrashTable, completeCrashString);
  223. PoolMemReleaseMemory (g_SafeModePool, (PVOID)completeCrashString);
  224. LOGA ((LOG_WARNING, "Safe mode information: 0x%08X, %s", crashData.CrashId, crashString));
  225. lastFilePtr = SetFilePointer (
  226. g_SafeModeFileHandle,
  227. 0,
  228. NULL,
  229. FILE_CURRENT
  230. );
  231. FreePathStringA (lastCrashString);
  232. }
  233. break;
  234. }
  235. crashString = AllocPathStringA (crashData.CrashStrSize);
  236. if (!ReadFile (
  237. g_SafeModeFileHandle,
  238. crashString,
  239. crashData.CrashStrSize,
  240. &noBytes,
  241. NULL
  242. ) ||
  243. (noBytes != crashData.CrashStrSize)
  244. ) {
  245. break;
  246. }
  247. //
  248. // store this information in Safe Mode crash table
  249. //
  250. completeCrashString = pGenerateCrashStringA (crashData.CrashId, crashString);
  251. HtAddStringA (g_SafeModeCrashTable, completeCrashString);
  252. PoolMemReleaseMemory (g_SafeModePool, (PVOID)completeCrashString);
  253. LOGA ((LOG_WARNING, "Safe mode information: 0x%08X, %s", crashData.CrashId, crashString));
  254. lastFilePtr = SetFilePointer (
  255. g_SafeModeFileHandle,
  256. 0,
  257. NULL,
  258. FILE_CURRENT
  259. );
  260. }
  261. //
  262. // Write how many times we ran in safe mode
  263. //
  264. SetFilePointer (
  265. g_SafeModeFileHandle,
  266. 0,
  267. NULL,
  268. FILE_BEGIN
  269. );
  270. header.Signature = SAFE_MODE_SIGNATURE;
  271. header.NumCrashes += 1;
  272. //
  273. // Write safe mode header
  274. //
  275. WriteFile (
  276. g_SafeModeFileHandle,
  277. &header,
  278. sizeof (SAFEMODE_HEADER),
  279. &noBytes,
  280. NULL
  281. );
  282. SetFilePointer (
  283. g_SafeModeFileHandle,
  284. lastFilePtr,
  285. NULL,
  286. FILE_BEGIN
  287. );
  288. SetEndOfFile (g_SafeModeFileHandle);
  289. //
  290. // Write a null crash data header as an indicator
  291. // that we start recording nested actions
  292. //
  293. crashData.CrashId = 0;
  294. crashData.CrashStrSize = 0;
  295. WriteFile (
  296. g_SafeModeFileHandle,
  297. &crashData,
  298. sizeof (CRASHDATA_HEADER),
  299. &noBytes,
  300. NULL
  301. );
  302. } else {
  303. //
  304. // Reset the file
  305. //
  306. SetFilePointer (
  307. g_SafeModeFileHandle,
  308. 0,
  309. NULL,
  310. FILE_BEGIN
  311. );
  312. SetEndOfFile (g_SafeModeFileHandle);
  313. header.Signature = SAFE_MODE_SIGNATURE;
  314. header.NumCrashes = 0;
  315. //
  316. // Write safe mode header
  317. //
  318. WriteFile (
  319. g_SafeModeFileHandle,
  320. &header,
  321. sizeof (SAFEMODE_HEADER),
  322. &noBytes,
  323. NULL
  324. );
  325. //
  326. // Write a null crash data header as an indicator
  327. // that we start recording nested actions
  328. //
  329. crashData.CrashId = 0;
  330. crashData.CrashStrSize = 0;
  331. WriteFile (
  332. g_SafeModeFileHandle,
  333. &crashData,
  334. sizeof (CRASHDATA_HEADER),
  335. &noBytes,
  336. NULL
  337. );
  338. }
  339. //
  340. // Flush the file
  341. //
  342. FlushFileBuffers (g_SafeModeFileHandle);
  343. //
  344. // initialize the nested list
  345. //
  346. g_SafeModeLastNode = (PSAFEMODE_NODE) PoolMemGetMemory (g_SafeModePool, sizeof (SAFEMODE_NODE));
  347. g_SafeModeCurrentNode = g_SafeModeLastNode->Next = g_SafeModeLastNode;
  348. g_SafeModeLastNode->FilePtr = SetFilePointer (
  349. g_SafeModeFileHandle,
  350. 0,
  351. NULL,
  352. FILE_CURRENT
  353. );
  354. return TRUE;
  355. }
  356. return FALSE;
  357. }
  358. BOOL
  359. pSafeModeOpenAndResetFileW (
  360. VOID
  361. )
  362. {
  363. SAFEMODE_HEADER header;
  364. CRASHDATA_HEADER crashData;
  365. DWORD lastFilePtr;
  366. DWORD noBytes;
  367. PWSTR crashString = NULL;
  368. PWSTR lastCrashString = NULL;
  369. ULONG lastCrashId;
  370. PCWSTR completeCrashString;
  371. //
  372. // Open the existing safe mode file or create a
  373. // new one.
  374. //
  375. g_SafeModeFileHandle = CreateFileW (
  376. g_SafeModeFileW,
  377. GENERIC_READ | GENERIC_WRITE,
  378. 0,
  379. NULL,
  380. OPEN_ALWAYS,
  381. FILE_ATTRIBUTE_HIDDEN,
  382. NULL
  383. );
  384. if (g_SafeModeFileHandle != INVALID_HANDLE_VALUE) {
  385. //
  386. // Let's try to read our header. If signature does
  387. // match we will try to read extra data.
  388. //
  389. if (ReadFile (
  390. g_SafeModeFileHandle,
  391. &header,
  392. sizeof (SAFEMODE_HEADER),
  393. &noBytes,
  394. NULL
  395. ) &&
  396. (noBytes == sizeof (SAFEMODE_HEADER)) &&
  397. (header.Signature == SAFE_MODE_SIGNATURE)
  398. ) {
  399. //
  400. // we know now we had an valid safe mode file. Enter safe mode.
  401. //
  402. g_SafeModeActive = TRUE;
  403. LOGW ((LOG_ERROR, "Setup detected a crash on the previous upgrade attempt. Setup is running in safe mode."));
  404. LOGW ((LOG_WARNING, "Setup has run in safe mode %d time(s).", header.NumCrashes));
  405. //
  406. // we need to initialize safe mode crash table
  407. //
  408. g_SafeModeCrashTable = HtAllocW ();
  409. //
  410. // Now, let's read all crash data, a ULONG and a string at a time
  411. //
  412. lastFilePtr = SetFilePointer (
  413. g_SafeModeFileHandle,
  414. 0,
  415. NULL,
  416. FILE_CURRENT
  417. );
  418. while (TRUE) {
  419. if (!ReadFile (
  420. g_SafeModeFileHandle,
  421. &crashData,
  422. sizeof (CRASHDATA_HEADER),
  423. &noBytes,
  424. NULL
  425. ) ||
  426. (noBytes != sizeof (CRASHDATA_HEADER))
  427. ) {
  428. break;
  429. }
  430. if ((crashData.CrashId == 0) &&
  431. (crashData.CrashStrSize == 0)
  432. ) {
  433. //
  434. // we crashed inside a nested guard. We need to
  435. // extract the inner guard we crashed in.
  436. //
  437. lastCrashId = 0;
  438. lastCrashString = NULL;
  439. while (TRUE) {
  440. if (!ReadFile (
  441. g_SafeModeFileHandle,
  442. &crashData,
  443. sizeof (CRASHDATA_HEADER),
  444. &noBytes,
  445. NULL
  446. ) ||
  447. (noBytes != sizeof (CRASHDATA_HEADER))
  448. ) {
  449. crashData.CrashId = 0;
  450. break;
  451. }
  452. crashString = AllocPathStringW (crashData.CrashStrSize);
  453. if (!ReadFile (
  454. g_SafeModeFileHandle,
  455. crashString,
  456. crashData.CrashStrSize,
  457. &noBytes,
  458. NULL
  459. ) ||
  460. (noBytes != crashData.CrashStrSize)
  461. ) {
  462. crashData.CrashId = 0;
  463. FreePathStringW (crashString);
  464. break;
  465. }
  466. if (lastCrashString) {
  467. FreePathStringW (lastCrashString);
  468. }
  469. lastCrashId = crashData.CrashId;
  470. lastCrashString = crashString;
  471. }
  472. if (lastCrashId && lastCrashString) {
  473. //
  474. // we found the inner guard we crashed in. Let's put this into
  475. // the right place.
  476. //
  477. SetFilePointer (
  478. g_SafeModeFileHandle,
  479. lastFilePtr,
  480. NULL,
  481. FILE_BEGIN
  482. );
  483. crashData.CrashId = lastCrashId;
  484. crashData.CrashStrSize = SizeOfStringW (lastCrashString);
  485. WriteFile (
  486. g_SafeModeFileHandle,
  487. &crashData,
  488. sizeof (CRASHDATA_HEADER),
  489. &noBytes,
  490. NULL
  491. );
  492. WriteFile (
  493. g_SafeModeFileHandle,
  494. lastCrashString,
  495. crashData.CrashStrSize,
  496. &noBytes,
  497. NULL
  498. );
  499. //
  500. // store this information in Safe Mode crash table
  501. //
  502. completeCrashString = pGenerateCrashStringW (crashData.CrashId, crashString);
  503. HtAddStringW (g_SafeModeCrashTable, completeCrashString);
  504. PoolMemReleaseMemory (g_SafeModePool, (PVOID)completeCrashString);
  505. LOGW ((LOG_WARNING, "Safe mode information: 0x%08X, %s", crashData.CrashId, crashString));
  506. lastFilePtr = SetFilePointer (
  507. g_SafeModeFileHandle,
  508. 0,
  509. NULL,
  510. FILE_CURRENT
  511. );
  512. FreePathStringW (lastCrashString);
  513. }
  514. break;
  515. }
  516. crashString = AllocPathStringW (crashData.CrashStrSize);
  517. if (!ReadFile (
  518. g_SafeModeFileHandle,
  519. crashString,
  520. crashData.CrashStrSize,
  521. &noBytes,
  522. NULL
  523. ) ||
  524. (noBytes != crashData.CrashStrSize)
  525. ) {
  526. break;
  527. }
  528. //
  529. // store this information in Safe Mode crash table
  530. //
  531. completeCrashString = pGenerateCrashStringW (crashData.CrashId, crashString);
  532. HtAddStringW (g_SafeModeCrashTable, completeCrashString);
  533. PoolMemReleaseMemory (g_SafeModePool, (PVOID)completeCrashString);
  534. LOGW ((LOG_WARNING, "Safe mode information: 0x%08X, %s", crashData.CrashId, crashString));
  535. lastFilePtr = SetFilePointer (
  536. g_SafeModeFileHandle,
  537. 0,
  538. NULL,
  539. FILE_CURRENT
  540. );
  541. }
  542. //
  543. // Write how many times we ran in safe mode
  544. //
  545. SetFilePointer (
  546. g_SafeModeFileHandle,
  547. 0,
  548. NULL,
  549. FILE_BEGIN
  550. );
  551. header.Signature = SAFE_MODE_SIGNATURE;
  552. header.NumCrashes += 1;
  553. //
  554. // Write safe mode header
  555. //
  556. WriteFile (
  557. g_SafeModeFileHandle,
  558. &header,
  559. sizeof (SAFEMODE_HEADER),
  560. &noBytes,
  561. NULL
  562. );
  563. SetFilePointer (
  564. g_SafeModeFileHandle,
  565. lastFilePtr,
  566. NULL,
  567. FILE_BEGIN
  568. );
  569. SetEndOfFile (g_SafeModeFileHandle);
  570. //
  571. // Write a null crash data header as an indicator
  572. // that we start recording nested actions
  573. //
  574. crashData.CrashId = 0;
  575. crashData.CrashStrSize = 0;
  576. WriteFile (
  577. g_SafeModeFileHandle,
  578. &crashData,
  579. sizeof (CRASHDATA_HEADER),
  580. &noBytes,
  581. NULL
  582. );
  583. } else {
  584. //
  585. // Reset the file
  586. //
  587. SetFilePointer (
  588. g_SafeModeFileHandle,
  589. 0,
  590. NULL,
  591. FILE_BEGIN
  592. );
  593. SetEndOfFile (g_SafeModeFileHandle);
  594. header.Signature = SAFE_MODE_SIGNATURE;
  595. header.NumCrashes = 0;
  596. //
  597. // Write safe mode header
  598. //
  599. WriteFile (
  600. g_SafeModeFileHandle,
  601. &header,
  602. sizeof (SAFEMODE_HEADER),
  603. &noBytes,
  604. NULL
  605. );
  606. //
  607. // Write a null crash data header as an indicator
  608. // that we start recording nested actions
  609. //
  610. crashData.CrashId = 0;
  611. crashData.CrashStrSize = 0;
  612. WriteFile (
  613. g_SafeModeFileHandle,
  614. &crashData,
  615. sizeof (CRASHDATA_HEADER),
  616. &noBytes,
  617. NULL
  618. );
  619. }
  620. //
  621. // Flush the file
  622. //
  623. FlushFileBuffers (g_SafeModeFileHandle);
  624. //
  625. // initialize the nested list
  626. //
  627. g_SafeModeLastNode = (PSAFEMODE_NODE) PoolMemGetMemory (g_SafeModePool, sizeof (SAFEMODE_NODE));
  628. g_SafeModeCurrentNode = g_SafeModeLastNode->Next = g_SafeModeLastNode;
  629. g_SafeModeLastNode->FilePtr = SetFilePointer (
  630. g_SafeModeFileHandle,
  631. 0,
  632. NULL,
  633. FILE_CURRENT
  634. );
  635. return TRUE;
  636. }
  637. return FALSE;
  638. }
  639. /*++
  640. Routine Description:
  641. SafeModeInitialize is called to initialize safe mode. The result of this
  642. function will be to either have safe mode active (if forced or if a crash
  643. was detected) or not. If safe mode is not active all other call are almost
  644. noop.
  645. Arguments:
  646. Forced - if this is TRUE, safe mode will be forced to be active
  647. Return Value:
  648. TRUE if the function completed successfully, FALSE otherwise
  649. --*/
  650. BOOL
  651. SafeModeInitializeA (
  652. BOOL Forced
  653. )
  654. {
  655. CHAR winDir[MAX_MBCHAR_PATH];
  656. g_ExceptionOccured = FALSE;
  657. if (GetWindowsDirectoryA (winDir, MAX_MBCHAR_PATH)) {
  658. g_SafeModePool = PoolMemInitNamedPool ("SafeMode Pool");
  659. g_SafeModeFileA = JoinPathsA (winDir, S_SAFE_MODE_FILEA);
  660. //
  661. // we are going to open the existing safe mode file
  662. // or to create a new one
  663. //
  664. if (pSafeModeOpenAndResetFileA ()) {
  665. if (Forced) {
  666. g_SafeModeActive = TRUE;
  667. if (g_SafeModeCrashTable == NULL) {
  668. //
  669. // we need to initialize safe mode crash table
  670. //
  671. g_SafeModeCrashTable = HtAllocA ();
  672. }
  673. }
  674. g_SafeModeInitialized = TRUE;
  675. return TRUE;
  676. }
  677. }
  678. return FALSE;
  679. }
  680. BOOL
  681. SafeModeInitializeW (
  682. BOOL Forced
  683. )
  684. {
  685. WCHAR winDir[MAX_WCHAR_PATH];
  686. g_ExceptionOccured = FALSE;
  687. if (GetWindowsDirectoryW (winDir, MAX_WCHAR_PATH)) {
  688. g_SafeModePool = PoolMemInitNamedPool ("SafeMode Pool");
  689. g_SafeModeFileW = JoinPathsW (winDir, S_SAFE_MODE_FILEW);
  690. //
  691. // we are going to open the existing safe mode file
  692. // or to create a new one
  693. //
  694. if (pSafeModeOpenAndResetFileW ()) {
  695. if (Forced) {
  696. g_SafeModeActive = TRUE;
  697. if (g_SafeModeCrashTable == NULL) {
  698. //
  699. // we need to initialize safe mode crash table
  700. //
  701. g_SafeModeCrashTable = HtAllocA ();
  702. }
  703. }
  704. g_SafeModeInitialized = TRUE;
  705. return TRUE;
  706. }
  707. }
  708. return FALSE;
  709. }
  710. /*++
  711. Routine Description:
  712. SafeModeShutDown is called to clean all data used by safe mode. It will remove
  713. safe mode file, release all used memory, reset all globals. Subsequent calls
  714. to safe mode functions after this will be noops.
  715. Arguments:
  716. NONE
  717. Return Value:
  718. TRUE if the function completed successfully, FALSE otherwise
  719. --*/
  720. BOOL
  721. SafeModeShutDownA (
  722. VOID
  723. )
  724. {
  725. if (g_SafeModeInitialized) {
  726. //
  727. // Close and delete safe mode file.
  728. // Reset all globals.
  729. //
  730. #ifdef DEBUG
  731. if (g_SafeModeLastNode != g_SafeModeCurrentNode) {
  732. DEBUGMSGA ((DBG_ERROR, "SafeMode: Unregistered action detected"));
  733. }
  734. #endif
  735. if (!g_ExceptionOccured) {
  736. CloseHandle (g_SafeModeFileHandle);
  737. g_SafeModeFileHandle = INVALID_HANDLE_VALUE;
  738. DeleteFileA (g_SafeModeFileA);
  739. }
  740. ELSE_DEBUGMSGA ((DBG_WARNING, "SafeModeShutDown called after exception. Files will not be cleaned up."));
  741. FreePathStringA (g_SafeModeFileA);
  742. g_SafeModeFileA = NULL;
  743. HtFree (g_SafeModeCrashTable);
  744. g_SafeModeCrashTable = NULL;
  745. g_SafeModeActive = FALSE;
  746. g_SafeModeInitialized = FALSE;
  747. }
  748. if (g_SafeModePool != NULL) {
  749. PoolMemDestroyPool (g_SafeModePool);
  750. g_SafeModePool = NULL;
  751. }
  752. return TRUE;
  753. }
  754. BOOL
  755. SafeModeShutDownW (
  756. VOID
  757. )
  758. {
  759. if (g_SafeModeInitialized) {
  760. //
  761. // Close and delete safe mode file.
  762. // Reset all globals.
  763. //
  764. #ifdef DEBUG
  765. if (g_SafeModeLastNode != g_SafeModeCurrentNode) {
  766. DEBUGMSGW ((DBG_ERROR, "SafeMode: Unregistered action detected"));
  767. }
  768. #endif
  769. if (!g_ExceptionOccured) {
  770. CloseHandle (g_SafeModeFileHandle);
  771. g_SafeModeFileHandle = INVALID_HANDLE_VALUE;
  772. DeleteFileW (g_SafeModeFileW);
  773. }
  774. ELSE_DEBUGMSGW ((DBG_WARNING, "SafeModeShutDown called after exception. Files will not be cleaned up."));
  775. FreePathStringW (g_SafeModeFileW);
  776. g_SafeModeFileW = NULL;
  777. HtFree (g_SafeModeCrashTable);
  778. g_SafeModeCrashTable = NULL;
  779. g_SafeModeActive = FALSE;
  780. g_SafeModeInitialized = FALSE;
  781. }
  782. if (g_SafeModePool != NULL) {
  783. PoolMemDestroyPool (g_SafeModePool);
  784. g_SafeModePool = NULL;
  785. }
  786. return TRUE;
  787. }
  788. /*++
  789. Routine Description:
  790. SafeModeRegisterAction is called when we want to guard a specific part of
  791. the code. The caller should pass an guard ID and a guard string (used to
  792. uniquely identify the portion of code beeing guarded.
  793. Arguments:
  794. Id - Safe mode identifier
  795. String - Safe mode string
  796. Return Value:
  797. TRUE if the function completed successfully, FALSE otherwise
  798. --*/
  799. BOOL
  800. SafeModeRegisterActionA (
  801. IN ULONG Id,
  802. IN PCSTR String
  803. )
  804. {
  805. DWORD noBytes;
  806. CRASHDATA_HEADER crashData;
  807. PSAFEMODE_NODE node;
  808. if (g_SafeModeInitialized && g_SafeModeActive) {
  809. SetFilePointer (
  810. g_SafeModeFileHandle,
  811. g_SafeModeCurrentNode->FilePtr,
  812. NULL,
  813. FILE_BEGIN
  814. );
  815. SetEndOfFile (g_SafeModeFileHandle);
  816. crashData.CrashId = Id;
  817. crashData.CrashStrSize = SizeOfStringA (String);
  818. WriteFile (
  819. g_SafeModeFileHandle,
  820. &crashData,
  821. sizeof (CRASHDATA_HEADER),
  822. &noBytes,
  823. NULL
  824. );
  825. WriteFile (
  826. g_SafeModeFileHandle,
  827. String,
  828. crashData.CrashStrSize,
  829. &noBytes,
  830. NULL
  831. );
  832. FlushFileBuffers (g_SafeModeFileHandle);
  833. node = (PSAFEMODE_NODE) PoolMemGetMemory (g_SafeModePool, sizeof (SAFEMODE_NODE));
  834. node->Next = g_SafeModeCurrentNode;
  835. node->FilePtr = SetFilePointer (
  836. g_SafeModeFileHandle,
  837. 0,
  838. NULL,
  839. FILE_CURRENT
  840. );
  841. g_SafeModeCurrentNode = node;
  842. }
  843. return TRUE;
  844. }
  845. BOOL
  846. SafeModeRegisterActionW (
  847. IN ULONG Id,
  848. IN PCWSTR String
  849. )
  850. {
  851. DWORD noBytes;
  852. CRASHDATA_HEADER crashData;
  853. PSAFEMODE_NODE node;
  854. if (g_SafeModeInitialized && g_SafeModeActive) {
  855. SetFilePointer (
  856. g_SafeModeFileHandle,
  857. g_SafeModeCurrentNode->FilePtr,
  858. NULL,
  859. FILE_BEGIN
  860. );
  861. SetEndOfFile (g_SafeModeFileHandle);
  862. crashData.CrashId = Id;
  863. crashData.CrashStrSize = SizeOfStringW (String);
  864. WriteFile (
  865. g_SafeModeFileHandle,
  866. &crashData,
  867. sizeof (CRASHDATA_HEADER),
  868. &noBytes,
  869. NULL
  870. );
  871. WriteFile (
  872. g_SafeModeFileHandle,
  873. String,
  874. crashData.CrashStrSize,
  875. &noBytes,
  876. NULL
  877. );
  878. FlushFileBuffers (g_SafeModeFileHandle);
  879. node = (PSAFEMODE_NODE) PoolMemGetMemory (g_SafeModePool, sizeof (SAFEMODE_NODE));
  880. node->Next = g_SafeModeCurrentNode;
  881. node->FilePtr = SetFilePointer (
  882. g_SafeModeFileHandle,
  883. 0,
  884. NULL,
  885. FILE_CURRENT
  886. );
  887. g_SafeModeCurrentNode = node;
  888. }
  889. return TRUE;
  890. }
  891. /*++
  892. Routine Description:
  893. SafeModeUnregisterAction is called when we want end the guard set for
  894. a specific part of the code. Since we allow nested guards, calling this
  895. function at the end of the guarded code is neccessary. The function will
  896. unregister the last registered guard.
  897. Arguments:
  898. NONE
  899. Return Value:
  900. TRUE if the function completed successfully, FALSE otherwise
  901. --*/
  902. BOOL
  903. SafeModeUnregisterActionA (
  904. VOID
  905. )
  906. {
  907. PSAFEMODE_NODE node;
  908. if (g_SafeModeInitialized && g_SafeModeActive) {
  909. if (g_SafeModeCurrentNode != g_SafeModeLastNode) {
  910. node = g_SafeModeCurrentNode;
  911. g_SafeModeCurrentNode = g_SafeModeCurrentNode->Next;
  912. PoolMemReleaseMemory (g_SafeModePool, node);
  913. SetFilePointer (
  914. g_SafeModeFileHandle,
  915. g_SafeModeCurrentNode->FilePtr,
  916. NULL,
  917. FILE_BEGIN
  918. );
  919. SetEndOfFile (g_SafeModeFileHandle);
  920. }
  921. #ifdef DEBUG
  922. else {
  923. DEBUGMSGA ((DBG_ERROR, "SafeMode: Too many actions unregistered."));
  924. }
  925. #endif
  926. }
  927. return TRUE;
  928. }
  929. BOOL
  930. SafeModeUnregisterActionW (
  931. VOID
  932. )
  933. {
  934. PSAFEMODE_NODE node;
  935. if (g_SafeModeInitialized && g_SafeModeActive) {
  936. if (g_SafeModeCurrentNode != g_SafeModeLastNode) {
  937. node = g_SafeModeCurrentNode;
  938. g_SafeModeCurrentNode = g_SafeModeCurrentNode->Next;
  939. PoolMemReleaseMemory (g_SafeModePool, node);
  940. SetFilePointer (
  941. g_SafeModeFileHandle,
  942. g_SafeModeCurrentNode->FilePtr,
  943. NULL,
  944. FILE_BEGIN
  945. );
  946. SetEndOfFile (g_SafeModeFileHandle);
  947. }
  948. #ifdef DEBUG
  949. else {
  950. DEBUGMSGW ((DBG_ERROR, "SafeMode: Too many actions unregistered."));
  951. }
  952. #endif
  953. }
  954. return TRUE;
  955. }
  956. /*++
  957. Routine Description:
  958. SafeModeActionCrashed will return TRUE if one of the previous crashes
  959. was detected in the code guarded by these arguments.
  960. Arguments:
  961. Id - Safe mode identifier
  962. String - Safe mode string
  963. Return Value:
  964. TRUE if one of the previous crashes occured in the code guarded by the
  965. arguments, FALSE otherwise
  966. --*/
  967. BOOL
  968. SafeModeActionCrashedA (
  969. IN ULONG Id,
  970. IN PCSTR String
  971. )
  972. {
  973. PCSTR crashString;
  974. BOOL result = FALSE;
  975. if (g_SafeModeInitialized && g_SafeModeActive) {
  976. crashString = pGenerateCrashStringA (Id, String);
  977. result = crashString && (HtFindStringA (g_SafeModeCrashTable, crashString));
  978. PoolMemReleaseMemory (g_SafeModePool, (PVOID)crashString);
  979. #ifdef DEBUG
  980. {
  981. UINT infId;
  982. infId = GetPrivateProfileIntA ("SafeMode", String, SAFEMODEID_FIRST, g_DebugInfPathA);
  983. result = result || (infId == Id);
  984. }
  985. #endif
  986. }
  987. return result;
  988. }
  989. BOOL
  990. SafeModeActionCrashedW (
  991. IN ULONG Id,
  992. IN PCWSTR String
  993. )
  994. {
  995. PCWSTR crashString;
  996. BOOL result = FALSE;
  997. if (g_SafeModeInitialized && g_SafeModeActive) {
  998. crashString = pGenerateCrashStringW (Id, String);
  999. result = crashString && (HtFindStringW (g_SafeModeCrashTable, crashString));
  1000. PoolMemReleaseMemory (g_SafeModePool, (PVOID)crashString);
  1001. #ifdef DEBUG
  1002. {
  1003. UINT infId;
  1004. infId = GetPrivateProfileIntW (L"SafeMode", String, SAFEMODEID_FIRST, g_DebugInfPathW);
  1005. result = result || (infId == Id);
  1006. }
  1007. #endif
  1008. }
  1009. return result;
  1010. }
  1011. /*++
  1012. Routine Description:
  1013. SafeModeExceptionOccured is called by exception handlers to let Safemode
  1014. know that something unexpected happened.
  1015. Arguments:
  1016. None.
  1017. Return Value:
  1018. --*/
  1019. VOID
  1020. SafeModeExceptionOccured (
  1021. VOID
  1022. )
  1023. {
  1024. g_ExceptionOccured = TRUE;
  1025. }