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.

1244 lines
31 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. smcrash.c
  5. Abstract:
  6. Routines related to crashdump creation.
  7. Author:
  8. Matthew D Hendel (math) 28-Aug-2000
  9. Revision History:
  10. --*/
  11. #include "smsrvp.h"
  12. #include <ntiodump.h>
  13. #include <stdio.h>
  14. #include <string.h>
  15. #define REVIEW KdBreakPoint
  16. #define CRASHDUMP_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\CrashControl"
  17. typedef struct _CRASH_PARAMETERS {
  18. UNICODE_STRING DumpFileName;
  19. UNICODE_STRING MiniDumpDir;
  20. ULONG Overwrite;
  21. ULONG TempDestination;
  22. } CRASH_PARAMETERS, *PCRASH_PARAMETERS;
  23. //
  24. // Forward declarations
  25. //
  26. BOOLEAN
  27. SmpQueryFileExists(
  28. IN PUNICODE_STRING FileName
  29. );
  30. NTSTATUS
  31. SmpCanCopyCrashDump(
  32. IN PDUMP_HEADER DumpHeader,
  33. IN PCRASH_PARAMETERS Parameters,
  34. IN PUNICODE_STRING PageFileName,
  35. IN ULONGLONG PageFileSize,
  36. OUT PUNICODE_STRING DumpFile
  37. );
  38. NTSTATUS
  39. SmpGetCrashParameters(
  40. IN PDUMP_HEADER DumpHeader,
  41. OUT PCRASH_PARAMETERS CrashParameters
  42. );
  43. NTSTATUS
  44. SmpCopyDumpFile(
  45. IN PDUMP_HEADER MemoryDump,
  46. IN HANDLE PageFile,
  47. IN PUNICODE_STRING DumpFileName
  48. );
  49. //
  50. // Functions
  51. //
  52. PVOID
  53. SmpAllocateString(
  54. IN SIZE_T Length
  55. )
  56. {
  57. return RtlAllocateHeap (RtlProcessHeap(),
  58. MAKE_TAG( INIT_TAG ),
  59. Length);
  60. }
  61. VOID
  62. SmpFreeString(
  63. IN PVOID Pointer
  64. )
  65. {
  66. RtlFreeHeap (RtlProcessHeap(),
  67. 0,
  68. Pointer);
  69. }
  70. NTSTATUS
  71. SmpSetDumpSecurity(
  72. IN HANDLE File
  73. )
  74. {
  75. NTSTATUS Status;
  76. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY ;
  77. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY ;
  78. PSID EveryoneSid = NULL;
  79. PSID LocalSystemSid = NULL;
  80. PSID AdminSid = NULL;
  81. UCHAR DescriptorBuffer[SECURITY_DESCRIPTOR_MIN_LENGTH];
  82. UCHAR AclBuffer[1024];
  83. PACL Acl;
  84. PSECURITY_DESCRIPTOR SecurityDescriptor;
  85. Acl = (PACL)&AclBuffer;
  86. SecurityDescriptor = (PSECURITY_DESCRIPTOR)DescriptorBuffer;
  87. RtlAllocateAndInitializeSid( &WorldAuthority, 1, SECURITY_WORLD_RID,
  88. 0, 0, 0, 0, 0, 0, 0, &EveryoneSid );
  89. RtlAllocateAndInitializeSid( &NtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID,
  90. 0, 0, 0, 0, 0, 0, 0, &LocalSystemSid );
  91. RtlAllocateAndInitializeSid( &NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
  92. DOMAIN_ALIAS_RID_ADMINS,
  93. 0, 0, 0, 0, 0, 0, &AdminSid );
  94. //
  95. // You can be fancy and compute the exact size, but since the
  96. // security descriptor capture code has to do that anyway, why
  97. // do it twice?
  98. //
  99. RtlCreateSecurityDescriptor (SecurityDescriptor,
  100. SECURITY_DESCRIPTOR_REVISION);
  101. RtlCreateAcl (Acl, 1024, ACL_REVISION);
  102. #if 0
  103. //
  104. // anybody can delete it
  105. //
  106. RtlAddAccessAllowedAce (Acl,
  107. ACL_REVISION,
  108. DELETE,
  109. EveryoneSid);
  110. #endif
  111. //
  112. // Administrator and system have full control
  113. //
  114. RtlAddAccessAllowedAce (Acl,
  115. ACL_REVISION,
  116. GENERIC_ALL | DELETE | WRITE_DAC | WRITE_OWNER,
  117. AdminSid);
  118. RtlAddAccessAllowedAce (Acl,
  119. ACL_REVISION,
  120. GENERIC_ALL | DELETE | WRITE_DAC | WRITE_OWNER,
  121. LocalSystemSid);
  122. RtlSetDaclSecurityDescriptor (SecurityDescriptor, TRUE, Acl, FALSE);
  123. RtlSetOwnerSecurityDescriptor (SecurityDescriptor, AdminSid, FALSE);
  124. Status = NtSetSecurityObject (File,
  125. DACL_SECURITY_INFORMATION,
  126. SecurityDescriptor);
  127. RtlFreeHeap (RtlProcessHeap(), 0, EveryoneSid);
  128. RtlFreeHeap (RtlProcessHeap(), 0, LocalSystemSid);
  129. RtlFreeHeap (RtlProcessHeap(), 0, AdminSid);
  130. return Status;
  131. }
  132. VOID
  133. SmpInitializeVolumePath(
  134. IN PUNICODE_STRING FileOnVolume,
  135. OUT PUNICODE_STRING VolumePath
  136. )
  137. {
  138. ULONG n;
  139. PWSTR s;
  140. *VolumePath = *FileOnVolume;
  141. n = VolumePath->Length;
  142. VolumePath->Length = 0;
  143. s = VolumePath->Buffer;
  144. while (n) {
  145. if (*s++ == L':' && *s == OBJ_NAME_PATH_SEPARATOR) {
  146. s++;
  147. break;
  148. }
  149. else {
  150. n -= sizeof( WCHAR );
  151. }
  152. }
  153. VolumePath->Length = (USHORT)((PCHAR)s - (PCHAR)VolumePath->Buffer);
  154. }
  155. NTSTATUS
  156. SmpQueryPathFromRegistry(
  157. IN HANDLE Key,
  158. IN PWSTR Value,
  159. IN PWSTR DefaultValue,
  160. OUT PUNICODE_STRING Path
  161. )
  162. {
  163. NTSTATUS Status;
  164. UNICODE_STRING ValueName;
  165. ULONG KeyValueLength;
  166. UCHAR KeyValueBuffer [VALUE_BUFFER_SIZE];
  167. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  168. WCHAR Buffer[258];
  169. UNICODE_STRING TempString;
  170. UNICODE_STRING ExpandedString;
  171. PWSTR DosPathName;
  172. BOOLEAN Succ;
  173. DosPathName = NULL;
  174. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyValueBuffer;
  175. RtlInitUnicodeString (&ValueName, Value);
  176. KeyValueLength = sizeof (KeyValueBuffer);
  177. Status = NtQueryValueKey (Key,
  178. &ValueName,
  179. KeyValuePartialInformation,
  180. KeyValueInfo,
  181. KeyValueLength,
  182. &KeyValueLength);
  183. if (NT_SUCCESS (Status)) {
  184. if (KeyValueInfo->Type == REG_EXPAND_SZ) {
  185. TempString.Length = (USHORT)KeyValueLength;
  186. TempString.MaximumLength = (USHORT)KeyValueLength;
  187. TempString.Buffer = (PWSTR)KeyValueInfo->Data;
  188. ExpandedString.Length = 0;
  189. ExpandedString.MaximumLength = sizeof (Buffer);
  190. ExpandedString.Buffer = Buffer;
  191. Status = RtlExpandEnvironmentStrings_U (NULL,
  192. &TempString,
  193. &ExpandedString,
  194. NULL);
  195. if (NT_SUCCESS (Status)) {
  196. DosPathName = ExpandedString.Buffer;
  197. }
  198. } else if (KeyValueInfo->Type == REG_SZ) {
  199. DosPathName = (PWSTR)KeyValueInfo->Data;
  200. }
  201. }
  202. if (!DosPathName) {
  203. DosPathName = DefaultValue;
  204. }
  205. Succ = RtlDosPathNameToNtPathName_U (DosPathName, Path, NULL, NULL);
  206. return (Succ ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL);
  207. }
  208. NTSTATUS
  209. SmpQueryDwordFromRegistry(
  210. IN HANDLE Key,
  211. IN PWSTR Value,
  212. IN ULONG DefaultValue,
  213. OUT PULONG Dword
  214. )
  215. {
  216. NTSTATUS Status;
  217. UNICODE_STRING ValueName;
  218. ULONG KeyValueLength;
  219. UCHAR KeyValueBuffer [VALUE_BUFFER_SIZE];
  220. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  221. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)&KeyValueBuffer;
  222. RtlInitUnicodeString (&ValueName, L"Overwrite");
  223. KeyValueLength = sizeof (KeyValueBuffer);
  224. Status = NtQueryValueKey (Key,
  225. &ValueName,
  226. KeyValuePartialInformation,
  227. KeyValueInfo,
  228. KeyValueLength,
  229. &KeyValueLength);
  230. if (NT_SUCCESS (Status) && KeyValueInfo->Type == REG_DWORD) {
  231. *Dword = *(PULONG)KeyValueInfo->Data;
  232. } else {
  233. *Dword = DefaultValue;
  234. }
  235. return STATUS_SUCCESS;
  236. }
  237. NTSTATUS
  238. SmpCreateUnicodeString(
  239. IN PUNICODE_STRING String,
  240. IN PWSTR InitString,
  241. IN ULONG MaximumLength
  242. )
  243. {
  244. if (MaximumLength == -1) {
  245. MaximumLength = (wcslen (InitString) + 1) * 2;
  246. }
  247. if (MaximumLength >= UNICODE_STRING_MAX_CHARS) {
  248. return STATUS_NO_MEMORY;
  249. }
  250. String->Buffer = RtlAllocateStringRoutine (MaximumLength + 1);
  251. if (String->Buffer == NULL) {
  252. return STATUS_NO_MEMORY;
  253. }
  254. String->MaximumLength = (USHORT)MaximumLength;
  255. if (InitString) {
  256. wcscpy (String->Buffer, InitString);
  257. String->Length = (USHORT)wcslen (String->Buffer) * sizeof (WCHAR);
  258. } else {
  259. String->Length = 0;
  260. }
  261. return STATUS_SUCCESS;
  262. }
  263. NTSTATUS
  264. SmpCreateTempFile(
  265. IN PUNICODE_STRING Directory,
  266. IN PWSTR Prefix,
  267. OUT PUNICODE_STRING TempFileName
  268. )
  269. {
  270. ULONG i;
  271. ULONG Tick;
  272. WCHAR Buffer [260];
  273. UNICODE_STRING FileName;
  274. NTSTATUS Status;
  275. Tick = NtGetTickCount ();
  276. for (i = 0; i < 100; i++) {
  277. swprintf (Buffer,
  278. L"%s\\%s%4.4x.tmp",
  279. Directory->Buffer,
  280. Prefix,
  281. (Tick + i) & 0xFFFF);
  282. Status = RtlDosPathNameToNtPathName_U (Buffer,
  283. &FileName,
  284. NULL,
  285. NULL);
  286. if (!NT_SUCCESS (Status)) {
  287. return Status;
  288. }
  289. if (!SmpQueryFileExists (&FileName)) {
  290. *TempFileName = FileName;
  291. return STATUS_SUCCESS;
  292. }
  293. }
  294. return STATUS_UNSUCCESSFUL;
  295. }
  296. NTSTATUS
  297. SmpQueryVolumeFreeSpace(
  298. IN PUNICODE_STRING FileOnVolume,
  299. OUT PULONGLONG VolumeFreeSpace
  300. )
  301. {
  302. NTSTATUS Status;
  303. UNICODE_STRING VolumePath;
  304. PWCHAR s;
  305. ULONG n;
  306. HANDLE Handle;
  307. IO_STATUS_BLOCK IoStatusBlock;
  308. FILE_FS_SIZE_INFORMATION SizeInfo;
  309. OBJECT_ATTRIBUTES ObjectAttributes;
  310. ULONGLONG AvailableBytes;
  311. //
  312. // Create an unicode string (VolumePath) containing only the
  313. // volume path from the pagefile name description (e.g. we get
  314. // "C:\" from "C:\pagefile.sys".
  315. //
  316. VolumePath = *FileOnVolume;
  317. n = VolumePath.Length;
  318. VolumePath.Length = 0;
  319. s = VolumePath.Buffer;
  320. while (n) {
  321. if (*s++ == L':' && *s == OBJ_NAME_PATH_SEPARATOR) {
  322. s++;
  323. break;
  324. }
  325. else {
  326. n -= sizeof( WCHAR );
  327. }
  328. }
  329. VolumePath.Length = (USHORT)((PCHAR)s - (PCHAR)VolumePath.Buffer);
  330. InitializeObjectAttributes( &ObjectAttributes,
  331. &VolumePath,
  332. OBJ_CASE_INSENSITIVE,
  333. NULL,
  334. NULL
  335. );
  336. Status = NtOpenFile( &Handle,
  337. (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
  338. &ObjectAttributes,
  339. &IoStatusBlock,
  340. FILE_SHARE_READ | FILE_SHARE_WRITE,
  341. FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
  342. );
  343. if (!NT_SUCCESS( Status )) {
  344. return Status;
  345. }
  346. //
  347. // Determine the size parameters of the volume.
  348. //
  349. Status = NtQueryVolumeInformationFile( Handle,
  350. &IoStatusBlock,
  351. &SizeInfo,
  352. sizeof( SizeInfo ),
  353. FileFsSizeInformation
  354. );
  355. NtClose( Handle );
  356. if (!NT_SUCCESS( Status )) {
  357. return Status;
  358. }
  359. //
  360. // Compute the AvailableBytes on the volume.
  361. // Deal with 64 bit sizes.
  362. //
  363. AvailableBytes = SizeInfo.AvailableAllocationUnits.QuadPart *
  364. SizeInfo.SectorsPerAllocationUnit *
  365. SizeInfo.BytesPerSector;
  366. *VolumeFreeSpace = AvailableBytes;
  367. return STATUS_SUCCESS;
  368. }
  369. BOOLEAN
  370. SmpQuerySameVolume(
  371. IN PUNICODE_STRING FileName1,
  372. IN PUNICODE_STRING FileName2
  373. )
  374. {
  375. HANDLE Handle;
  376. NTSTATUS Status;
  377. ULONG SerialNumber;
  378. struct {
  379. FILE_FS_VOLUME_INFORMATION Volume;
  380. WCHAR Buffer [100];
  381. } VolumeInfo;
  382. OBJECT_ATTRIBUTES ObjectAttributes;
  383. IO_STATUS_BLOCK IoStatusBlock;
  384. UNICODE_STRING VolumePath;
  385. SmpInitializeVolumePath (FileName1, &VolumePath);
  386. InitializeObjectAttributes (&ObjectAttributes,
  387. &VolumePath,
  388. OBJ_CASE_INSENSITIVE,
  389. NULL,
  390. NULL);
  391. Status = NtOpenFile (&Handle,
  392. (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  393. &ObjectAttributes,
  394. &IoStatusBlock,
  395. FILE_SHARE_READ | FILE_SHARE_WRITE,
  396. FILE_SYNCHRONOUS_IO_NONALERT);
  397. if (!NT_SUCCESS (Status)) {
  398. return FALSE;
  399. }
  400. Status = NtQueryVolumeInformationFile (Handle,
  401. &IoStatusBlock,
  402. &VolumeInfo,
  403. sizeof (VolumeInfo),
  404. FileFsVolumeInformation);
  405. if (!NT_SUCCESS (Status)) {
  406. NtClose (Handle);
  407. return FALSE;
  408. }
  409. SerialNumber = VolumeInfo.Volume.VolumeSerialNumber;
  410. NtClose (Handle);
  411. SmpInitializeVolumePath (FileName2, &VolumePath);
  412. InitializeObjectAttributes (&ObjectAttributes,
  413. &VolumePath,
  414. OBJ_CASE_INSENSITIVE,
  415. NULL,
  416. NULL);
  417. Status = NtOpenFile (&Handle,
  418. (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  419. &ObjectAttributes,
  420. &IoStatusBlock,
  421. FILE_SHARE_READ | FILE_SHARE_WRITE,
  422. FILE_SYNCHRONOUS_IO_NONALERT);
  423. if (!NT_SUCCESS (Status)) {
  424. return FALSE;
  425. }
  426. Status = NtQueryVolumeInformationFile (Handle,
  427. &IoStatusBlock,
  428. &VolumeInfo,
  429. sizeof (VolumeInfo),
  430. FileFsVolumeInformation);
  431. NtClose (Handle);
  432. if (!NT_SUCCESS (Status)) {
  433. return FALSE;
  434. }
  435. return ((SerialNumber == VolumeInfo.Volume.VolumeSerialNumber) ? TRUE : FALSE);
  436. }
  437. NTSTATUS
  438. SmpSetEndOfFile(
  439. IN HANDLE File,
  440. IN ULONGLONG EndOfFile
  441. )
  442. /*++
  443. Routine Description:
  444. Expand or truncate a file to a specific size.
  445. Arguments:
  446. File - Supplies the file handle of the file to be expanded
  447. or truncated.
  448. EndOfFile - Supplies the final size of the file.
  449. Return Value:
  450. NTSTATUS code.
  451. --*/
  452. {
  453. NTSTATUS Status;
  454. FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
  455. FILE_ALLOCATION_INFORMATION AllocationInfo;
  456. IO_STATUS_BLOCK IoStatusBlock;
  457. EndOfFileInfo.EndOfFile.QuadPart = EndOfFile;
  458. Status = NtSetInformationFile (File,
  459. &IoStatusBlock,
  460. &EndOfFileInfo,
  461. sizeof (EndOfFileInfo),
  462. FileEndOfFileInformation);
  463. if (!NT_SUCCESS( Status )) {
  464. return Status;
  465. }
  466. AllocationInfo.AllocationSize.QuadPart = EndOfFile;
  467. Status = NtSetInformationFile (File,
  468. &IoStatusBlock,
  469. &AllocationInfo,
  470. sizeof (AllocationInfo),
  471. FileAllocationInformation);
  472. return Status;
  473. }
  474. NTSTATUS
  475. SmpQueryFileSize(
  476. IN HANDLE FileHandle,
  477. OUT PULONGLONG FileSize
  478. )
  479. /*++
  480. Routine Description:
  481. Query the size of the specified file.x
  482. Arguments:
  483. FileHandle - Supplies a handle to the file whose size is
  484. to be querried.
  485. FileSize - Supplies a pointer to a buffer where the size is
  486. copied.
  487. Return Value:
  488. NTSTATUS code.
  489. --*/
  490. {
  491. NTSTATUS Status;
  492. IO_STATUS_BLOCK IoStatusBlock;
  493. FILE_STANDARD_INFORMATION StandardInfo;
  494. Status = NtQueryInformationFile (FileHandle,
  495. &IoStatusBlock,
  496. &StandardInfo,
  497. sizeof (StandardInfo),
  498. FileStandardInformation);
  499. if (NT_SUCCESS (Status)) {
  500. *FileSize = StandardInfo.AllocationSize.QuadPart;
  501. }
  502. return Status;
  503. }
  504. BOOLEAN
  505. SmpQueryFileExists(
  506. IN PUNICODE_STRING FileName
  507. )
  508. {
  509. NTSTATUS Status;
  510. HANDLE Handle;
  511. OBJECT_ATTRIBUTES ObjectAttributes;
  512. IO_STATUS_BLOCK IoStatusBlock;
  513. InitializeObjectAttributes (&ObjectAttributes,
  514. FileName,
  515. OBJ_CASE_INSENSITIVE,
  516. NULL,
  517. NULL);
  518. Status = NtOpenFile (&Handle,
  519. (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  520. &ObjectAttributes,
  521. &IoStatusBlock,
  522. FILE_SHARE_READ | FILE_SHARE_WRITE,
  523. FILE_SYNCHRONOUS_IO_NONALERT);
  524. if (!NT_SUCCESS (Status)) {
  525. return FALSE;
  526. }
  527. NtClose (Handle);
  528. return TRUE;
  529. }
  530. BOOLEAN
  531. SmpCheckForCrashDump(
  532. IN PUNICODE_STRING PageFileName
  533. )
  534. /*++
  535. Routine Description:
  536. Check the paging file to see if there is a valid crashdump
  537. in it. This can only be done before we call NtOpenPagingFile.
  538. Arguments:
  539. PageFileName - Name of the paging file we are about to create.
  540. Return Value:
  541. TRUE - If the paging file contains a valid crashdump.
  542. FALSE - If the paging file does not contain a valid crashdump.
  543. --*/
  544. {
  545. NTSTATUS Status;
  546. HANDLE PageFile;
  547. HANDLE Key;
  548. BOOLEAN Copied;
  549. DUMP_HEADER DumpHeader;
  550. OBJECT_ATTRIBUTES ObjectAttributes;
  551. IO_STATUS_BLOCK IoStatusBlock;
  552. ULONGLONG PageFileSize;
  553. UNICODE_STRING String;
  554. CRASH_PARAMETERS CrashParameters;
  555. UNICODE_STRING DumpFileName;
  556. BOOLEAN ClosePageFile;
  557. BOOLEAN CloseKey;
  558. RtlZeroMemory (&CrashParameters, sizeof (CRASH_PARAMETERS));
  559. RtlZeroMemory (&DumpFileName, sizeof (UNICODE_STRING));
  560. PageFile = (HANDLE)-1;
  561. ClosePageFile = FALSE;
  562. Key = (HANDLE)-1;
  563. CloseKey = FALSE;
  564. Copied = FALSE;
  565. InitializeObjectAttributes (&ObjectAttributes,
  566. PageFileName,
  567. OBJ_CASE_INSENSITIVE,
  568. NULL,
  569. NULL);
  570. Status = NtOpenFile (&PageFile,
  571. GENERIC_READ | GENERIC_WRITE |
  572. DELETE | WRITE_DAC | SYNCHRONIZE,
  573. &ObjectAttributes,
  574. &IoStatusBlock,
  575. FILE_SHARE_READ | FILE_SHARE_WRITE,
  576. FILE_SYNCHRONOUS_IO_NONALERT |
  577. FILE_NO_INTERMEDIATE_BUFFERING);
  578. if (!NT_SUCCESS (Status)) {
  579. Copied = FALSE;
  580. goto done;
  581. } else {
  582. ClosePageFile = TRUE;
  583. }
  584. Status = SmpQueryFileSize (PageFile, &PageFileSize);
  585. if (!NT_SUCCESS (Status)) {
  586. PageFileSize = 0;
  587. }
  588. Status = NtReadFile (PageFile,
  589. NULL,
  590. NULL,
  591. NULL,
  592. &IoStatusBlock,
  593. &DumpHeader,
  594. sizeof (DUMP_HEADER),
  595. NULL,
  596. NULL);
  597. if (NT_SUCCESS (Status) &&
  598. DumpHeader.Signature == DUMP_SIGNATURE &&
  599. DumpHeader.ValidDump == DUMP_VALID_DUMP) {
  600. Status = SmpGetCrashParameters (&DumpHeader, &CrashParameters);
  601. if (NT_SUCCESS (Status)) {
  602. Status = SmpCanCopyCrashDump (&DumpHeader,
  603. &CrashParameters,
  604. PageFileName,
  605. PageFileSize,
  606. &DumpFileName);
  607. if (NT_SUCCESS (Status)) {
  608. Status = SmpCopyDumpFile (&DumpHeader,
  609. PageFile,
  610. &DumpFileName);
  611. if (NT_SUCCESS (Status)) {
  612. Copied = TRUE;
  613. }
  614. }
  615. }
  616. }
  617. NtClose (PageFile);
  618. PageFile = (HANDLE) -1;
  619. ClosePageFile = FALSE;
  620. if (Copied) {
  621. //
  622. // If we copied the pagefile, create a new pagefile the same size
  623. // as the old one.
  624. //
  625. InitializeObjectAttributes (&ObjectAttributes,
  626. PageFileName,
  627. OBJ_CASE_INSENSITIVE,
  628. NULL,
  629. NULL);
  630. Status = NtCreateFile (&PageFile,
  631. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  632. &ObjectAttributes,
  633. &IoStatusBlock,
  634. NULL,
  635. FILE_ATTRIBUTE_NORMAL,
  636. FILE_SHARE_READ | FILE_SHARE_WRITE,
  637. FILE_CREATE,
  638. FILE_SYNCHRONOUS_IO_NONALERT,
  639. NULL,
  640. 0);
  641. if (NT_SUCCESS (Status)) {
  642. Status = SmpSetEndOfFile (PageFile, PageFileSize);
  643. NtClose (PageFile);
  644. PageFile = (HANDLE) -1;
  645. ClosePageFile = FALSE;
  646. }
  647. //
  648. // If we successfully copied, we want to create
  649. // a volitile registry key that others can use
  650. // to locate the dump file.
  651. //
  652. RtlInitUnicodeString (&String, CRASHDUMP_KEY L"\\MachineCrash");
  653. InitializeObjectAttributes (&ObjectAttributes,
  654. &String,
  655. OBJ_CASE_INSENSITIVE,
  656. NULL,
  657. NULL);
  658. Status = NtCreateKey (&Key,
  659. KEY_READ | KEY_WRITE,
  660. &ObjectAttributes,
  661. 0,
  662. NULL,
  663. REG_OPTION_VOLATILE,
  664. NULL);
  665. if (NT_SUCCESS (Status)) {
  666. CloseKey = TRUE;
  667. //
  668. // We are setting volatile key CrashControl\MachineCrash\DumpFile
  669. // to the name of the dump file.
  670. //
  671. RtlInitUnicodeString (&String, L"DumpFile");
  672. Status = NtSetValueKey (Key,
  673. &String,
  674. 0,
  675. REG_SZ,
  676. &DumpFileName.Buffer[4],
  677. DumpFileName.Length - (3 * sizeof (WCHAR)));
  678. RtlInitUnicodeString (&String, L"TempDestination");
  679. Status = NtSetValueKey (Key,
  680. &String,
  681. 0,
  682. REG_DWORD,
  683. &CrashParameters.TempDestination,
  684. sizeof (CrashParameters.TempDestination));
  685. NtClose (Key);
  686. Key = (HANDLE) -1;
  687. CloseKey = FALSE;
  688. }
  689. }
  690. done:
  691. //
  692. // Cleanup and return
  693. //
  694. if (CrashParameters.DumpFileName.Length != 0) {
  695. RtlFreeUnicodeString (&CrashParameters.DumpFileName);
  696. }
  697. if (CrashParameters.MiniDumpDir.Length != 0) {
  698. RtlFreeUnicodeString (&CrashParameters.MiniDumpDir);
  699. }
  700. if (ClosePageFile) {
  701. NtClose (PageFile);
  702. }
  703. if (CloseKey) {
  704. NtClose (Key);
  705. }
  706. return Copied;
  707. }
  708. NTSTATUS
  709. SmpGetCrashParameters(
  710. IN PDUMP_HEADER DumpHeader,
  711. OUT PCRASH_PARAMETERS CrashParameters
  712. )
  713. /*++
  714. Routine Description:
  715. Get the parameters for the crashdump from
  716. the registry.
  717. Arguments:
  718. DumpHeader -
  719. CrashParameters -
  720. Return Value:
  721. NTSTATUS code.
  722. --*/
  723. {
  724. NTSTATUS Status;
  725. HANDLE Key;
  726. BOOLEAN CloseKey;
  727. UNICODE_STRING KeyName;
  728. OBJECT_ATTRIBUTES ObjectAttributes;
  729. WCHAR DefaultPath[260];
  730. Key = (HANDLE) -1;
  731. CloseKey = FALSE;
  732. RtlInitUnicodeString (&KeyName, CRASHDUMP_KEY);
  733. InitializeObjectAttributes (&ObjectAttributes,
  734. &KeyName,
  735. OBJ_CASE_INSENSITIVE,
  736. NULL,
  737. NULL);
  738. Status = NtOpenKey (&Key, KEY_READ, &ObjectAttributes);
  739. if (NT_SUCCESS (Status)) {
  740. CloseKey = TRUE;
  741. } else {
  742. goto done;
  743. }
  744. swprintf (DefaultPath, L"%s\\MEMORY.DMP", SmpSystemRoot.Buffer);
  745. Status = SmpQueryPathFromRegistry (Key,
  746. L"DumpFile",
  747. DefaultPath,
  748. &CrashParameters->DumpFileName);
  749. if (!NT_SUCCESS (Status)) {
  750. goto done;
  751. }
  752. swprintf (DefaultPath, L"%s\\Minidump", SmpSystemRoot.Buffer);
  753. Status = SmpQueryPathFromRegistry (Key,
  754. L"MiniDumpDir",
  755. DefaultPath,
  756. &CrashParameters->MiniDumpDir);
  757. if (!NT_SUCCESS (Status)) {
  758. goto done;
  759. }
  760. Status = SmpQueryDwordFromRegistry (Key,
  761. L"Overwrite",
  762. 1,
  763. &CrashParameters->Overwrite);
  764. if (!NT_SUCCESS (Status)) {
  765. goto done;
  766. }
  767. //
  768. // This value is initialized by SmpCanCopyCrashDump.
  769. //
  770. CrashParameters->TempDestination = FALSE;
  771. Status = STATUS_SUCCESS;
  772. done:
  773. if (CloseKey) {
  774. NtClose (Key);
  775. }
  776. return Status;
  777. }
  778. NTSTATUS
  779. SmpCopyDumpFile(
  780. IN PDUMP_HEADER MemoryDump,
  781. IN HANDLE PageFile,
  782. IN PUNICODE_STRING DumpFileName
  783. )
  784. /*++
  785. Routine Description:
  786. Copy the dump file from the pagefile to the crash
  787. dump file.
  788. Arguments:
  789. DumpHeader -
  790. PageFile -
  791. DumpFileName -
  792. Return Value:
  793. NTSTATUS code.
  794. --*/
  795. {
  796. NTSTATUS Status;
  797. ULONGLONG DumpFileSize;
  798. struct {
  799. FILE_RENAME_INFORMATION Rename;
  800. WCHAR Buffer[255];
  801. } RenameInfoBuffer;
  802. PFILE_RENAME_INFORMATION RenameInfo;
  803. ULONG RenameInfoSize;
  804. IO_STATUS_BLOCK IoStatusBlock;
  805. FILE_BASIC_INFORMATION BasicInformation;
  806. RenameInfo = &RenameInfoBuffer.Rename;
  807. DumpFileSize = MemoryDump->RequiredDumpSpace.QuadPart;
  808. Status = SmpSetEndOfFile (PageFile, DumpFileSize);
  809. if (!NT_SUCCESS (Status)) {
  810. return Status;
  811. }
  812. RenameInfoSize = sizeof (FILE_RENAME_INFORMATION) + DumpFileName->Length;
  813. RenameInfo->ReplaceIfExists = TRUE;
  814. RenameInfo->RootDirectory = NULL;
  815. RenameInfo->FileNameLength = DumpFileName->Length;
  816. wcscpy (RenameInfo->FileName, DumpFileName->Buffer);
  817. Status = NtSetInformationFile (PageFile,
  818. &IoStatusBlock,
  819. RenameInfo,
  820. RenameInfoSize,
  821. FileRenameInformation);
  822. if (!NT_SUCCESS (Status)) {
  823. return Status;
  824. }
  825. //
  826. // Reset the file SYSTEM and HIDDEN attributes.
  827. //
  828. Status = NtQueryInformationFile (PageFile,
  829. &IoStatusBlock,
  830. &BasicInformation,
  831. sizeof (BasicInformation),
  832. FileBasicInformation);
  833. if (!NT_SUCCESS (Status)) {
  834. return Status;
  835. }
  836. BasicInformation.FileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
  837. BasicInformation.FileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;
  838. Status = NtSetInformationFile (PageFile,
  839. &IoStatusBlock,
  840. &BasicInformation,
  841. sizeof (BasicInformation),
  842. FileBasicInformation);
  843. //
  844. // Reset the file security.
  845. //
  846. Status = SmpSetDumpSecurity (PageFile);
  847. return Status;
  848. }
  849. NTSTATUS
  850. SmpCanCopyCrashDump(
  851. IN PDUMP_HEADER DumpHeader,
  852. IN PCRASH_PARAMETERS CrashParameters,
  853. IN PUNICODE_STRING PageFileName,
  854. IN ULONGLONG PageFileSize,
  855. OUT PUNICODE_STRING DumpFileName
  856. )
  857. /*++
  858. Routine Description:
  859. Figure out whether it's ok to copy the dump file or not.
  860. Arguments:
  861. DumpHeader - Supplies the header to the dump file.
  862. CrashParameters - Supplies the parameters required to copy the file.
  863. DumpFileName - Supplies a unicode string buffer that the crashdump
  864. will be copied to.
  865. Return Value:
  866. NTSTATUS code.
  867. --*/
  868. {
  869. NTSTATUS Status;
  870. BOOLEAN SameVolume;
  871. BOOLEAN UseTempFile;
  872. ULONGLONG CrashFileSize;
  873. ULONGLONG VolumeFreeSpace;
  874. UseTempFile = FALSE;
  875. if (DumpHeader->DumpType == DUMP_TYPE_TRIAGE) {
  876. UseTempFile = TRUE;
  877. } else {
  878. SameVolume = SmpQuerySameVolume (PageFileName,
  879. &CrashParameters->DumpFileName);
  880. if (SameVolume) {
  881. //
  882. // If we're on the same volume and there is an existing dump file
  883. // then :
  884. // if overwrite flag was not set, fail.
  885. // otherwise, reclaim the space for this file.
  886. //
  887. if (SmpQueryFileExists (&CrashParameters->DumpFileName)) {
  888. if (CrashParameters->Overwrite) {
  889. SmpDeleteFile (&CrashParameters->DumpFileName);
  890. } else {
  891. return STATUS_UNSUCCESSFUL;
  892. }
  893. }
  894. } else {
  895. //
  896. // We're not on the same volume, so we'll need to create a temp
  897. // file.
  898. //
  899. UseTempFile = TRUE;
  900. }
  901. }
  902. CrashFileSize = DumpHeader->RequiredDumpSpace.QuadPart;
  903. Status = SmpQueryVolumeFreeSpace (&CrashParameters->DumpFileName,
  904. &VolumeFreeSpace);
  905. if (!NT_SUCCESS (Status)) {
  906. return Status;
  907. }
  908. //
  909. // The space reserved by the pagefile is already taken into account here.
  910. // Do not add it in (a second time) here.
  911. //
  912. if (CrashFileSize < VolumeFreeSpace) {
  913. if (!UseTempFile) {
  914. Status = SmpCreateUnicodeString (DumpFileName,
  915. CrashParameters->DumpFileName.Buffer,
  916. -1);
  917. } else {
  918. Status = SmpCreateTempFile (&SmpSystemRoot, L"DUMP", DumpFileName);
  919. }
  920. } else {
  921. Status = STATUS_INSUFFICIENT_RESOURCES;
  922. }
  923. CrashParameters->TempDestination = UseTempFile;
  924. if (!NT_SUCCESS (Status)) {
  925. //
  926. // NB: Log an error saying we were unable
  927. // to copy the crashdump for some reason.
  928. //
  929. }
  930. return Status;
  931. }
  932. const PRTL_ALLOCATE_STRING_ROUTINE RtlAllocateStringRoutine = SmpAllocateString;
  933. const PRTL_FREE_STRING_ROUTINE RtlFreeStringRoutine = SmpFreeString;
  934. #if 0
  935. __cdecl
  936. main(
  937. )
  938. {
  939. BOOLEAN CopiedDump;
  940. UNICODE_STRING PageFile;
  941. RtlInitUnicodeString (&SmpSystemRoot,
  942. L"C:\\WINNT");
  943. RtlDosPathNameToNtPathName_U (L"C:\\Public\\crashdmp.teo\\memory.dmp",
  944. &PageFile,
  945. NULL,
  946. NULL);
  947. CopiedDump = SmpCheckForCrashDump (&PageFile);
  948. }
  949. #endif // TEST