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.

1391 lines
38 KiB

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