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.

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