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.

1309 lines
36 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. sprestrt.c
  5. Abstract:
  6. This program is used to help make GUI Setup restartable,
  7. if setup was started in restartable mode.
  8. Text mode setup will create a system hive containing the value
  9. HKLM\System\Setup:RestartSpSetup = REG_DWORD FALSE
  10. and a system.sav with RestartSpSetup set to TRUE. In both hives
  11. the session manager key will be written such that this program
  12. runs at autochk time.
  13. When this program starts, it checks the RestartSpSetup flag.
  14. If FALSE, then this is the first boot into GUI Setup, and we change it
  15. to TRUE and we're done here. If TRUE, then GUI setup needs to be
  16. restarted, and we clean out the config directory, copying *.sav to *.
  17. and erase everything else in there. System.sav has RestartSpSetup = TRUE,
  18. so GUI setup will be restarted over and over again until it succeeds.
  19. At the end of GUI Setup, sprestrt.exe is removed from the list of
  20. autochk programs and RestartSpSetup is set to FALSE.
  21. The boot loader looks at RestartSpSetup to see whether it needs to unload
  22. system and load system.sav instead. On the first boot into gui setup,
  23. we don't want to do this but on subsequent boots we do. The logic above
  24. makes this work correctly.
  25. Author:
  26. Ted Miller (tedm) Feb 1996
  27. --*/
  28. #include <nt.h>
  29. #include <ntrtl.h>
  30. #include <nturtl.h>
  31. #include "msg.h"
  32. #include "psp.h"
  33. //
  34. // Define result codes.
  35. //
  36. #define SUCCESS 0
  37. #define FAILURE 1
  38. #define SIZEOFARRAY(a) (sizeof(a)/sizeof(a[0]))
  39. #define BACKUP_EXTENSION L".sav"
  40. #define BACKUP_EXTENSION_LEN 4
  41. #define SPS_EXTENSION L".sps"
  42. #define SPS_EXTENSION_LEN 4
  43. PCWSTR g_RestartHiveNames[] = {
  44. L"default",
  45. L"security",
  46. L"software",
  47. L"system",
  48. };
  49. //
  50. // Define helper macro to deal with subtleties of NT-level programming.
  51. //
  52. #define INIT_OBJA(Obja,UnicodeString,UnicodeText) \
  53. \
  54. RtlInitUnicodeString((UnicodeString),(UnicodeText)); \
  55. \
  56. InitializeObjectAttributes( \
  57. (Obja), \
  58. (UnicodeString), \
  59. OBJ_CASE_INSENSITIVE, \
  60. NULL, \
  61. NULL \
  62. )
  63. //
  64. // Relevent registry key and values.
  65. //
  66. const PCWSTR SetupRegistryKeyName = L"\\Registry\\Machine\\SYSTEM\\Setup";
  67. const PCWSTR RestartSpSetupValueName = L"RestartSpSetup";
  68. const PCWSTR ConfigDirectory =L"\\SystemRoot\\System32\\Config";
  69. const PCWSTR ProgressIndicator = L".";
  70. //
  71. // Copy buffer. What the heck, it doesn't take up any space in the image.
  72. //
  73. #define COPYBUF_SIZE 65536
  74. UCHAR CopyBuffer[COPYBUF_SIZE];
  75. //
  76. // Tristate value, where a boolean just won't do.
  77. //
  78. typedef enum {
  79. xFALSE,
  80. xTRUE,
  81. xUNKNOWN
  82. } TriState;
  83. //
  84. // Define structure for keeping a linked list of unicode strings.
  85. //
  86. typedef struct _COPY_LIST_NODE {
  87. LONGLONG FileSize;
  88. UNICODE_STRING UnicodeString;
  89. struct _COPY_LIST_NODE *Next;
  90. } COPY_LIST_NODE, *PCOPY_LIST_NODE;
  91. //
  92. // Memory routines
  93. //
  94. #define MALLOC(size) RtlAllocateHeap(RtlProcessHeap(),0,(size))
  95. #define FREE(block) RtlFreeHeap(RtlProcessHeap(),0,(block))
  96. //
  97. // Forward references
  98. //
  99. TriState
  100. CheckRestartValue(
  101. VOID
  102. );
  103. BOOLEAN
  104. SetRestartValue(
  105. VOID
  106. );
  107. BOOLEAN
  108. SaveConfigForSpSetupRestart (
  109. VOID
  110. );
  111. BOOLEAN
  112. RestoreConfigForSpSetupRestart(
  113. VOID
  114. );
  115. BOOLEAN
  116. RestoreConfigDirectory(
  117. VOID
  118. );
  119. NTSTATUS
  120. CopyAFile(
  121. IN HANDLE DirectoryHandle,
  122. IN LONGLONG FileSize,
  123. IN PCWSTR ExistingFile,
  124. IN PCWSTR NewFile,
  125. IN BOOLEAN BackupTargetIfExists
  126. );
  127. BOOLEAN
  128. AreStringsEqual(
  129. IN PCWSTR String1,
  130. IN PCWSTR String2
  131. );
  132. BOOLEAN
  133. Message(
  134. IN ULONG MessageId,
  135. IN ULONG DotCount,
  136. ...
  137. );
  138. BOOLEAN
  139. pIsRestartHive (
  140. IN PCWSTR HiveName
  141. )
  142. {
  143. int i;
  144. for (i = 0; i < SIZEOFARRAY(g_RestartHiveNames); i++) {
  145. if (AreStringsEqual (g_RestartHiveNames[i], HiveName)) {
  146. return TRUE;
  147. }
  148. }
  149. return FALSE;
  150. }
  151. int
  152. __cdecl
  153. main(
  154. VOID
  155. )
  156. {
  157. int Result = FAILURE;
  158. //
  159. // Check the status of the RestartSpSetup flag.
  160. // If not present, do nothing.
  161. // If FALSE, set to TRUE.
  162. // If TRUE, clean up config directory.
  163. //
  164. switch(CheckRestartValue()) {
  165. case xFALSE:
  166. if (SaveConfigForSpSetupRestart () && SetRestartValue()) {
  167. Result = SUCCESS;
  168. } else {
  169. Message(MSG_WARNING_CANT_SET_RESTART,0);
  170. }
  171. break;
  172. case xTRUE:
  173. Result = RestoreConfigForSpSetupRestart();
  174. Message(MSG_CRLF,0);
  175. if(!Result) {
  176. Message(MSG_WARNING_CANT_CLEAN_UP,0);
  177. }
  178. break;
  179. default:
  180. break;
  181. }
  182. return(Result);
  183. }
  184. TriState
  185. CheckRestartValue(
  186. VOID
  187. )
  188. /*++
  189. Routine Description:
  190. Check if HKLM\System\Setup:RestartSpSetup is present as a REG_DWORD
  191. and if so get its value.
  192. Arguments:
  193. None.
  194. Return Value:
  195. Value indicating whether the flag is set (xTrue), not set (xFalse),
  196. or in an unknown state (ie, not present or not REG_DWORD, etc; xUnknown).
  197. --*/
  198. {
  199. UNICODE_STRING UnicodeString;
  200. NTSTATUS Status;
  201. OBJECT_ATTRIBUTES ObjectAttributes;
  202. HANDLE KeyHandle;
  203. ULONG DataLength;
  204. UCHAR Buffer[1024];
  205. PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
  206. TriState b;
  207. //
  208. // Assume not present.
  209. //
  210. b = xUNKNOWN;
  211. //
  212. // Attempt to open the key.
  213. //
  214. INIT_OBJA(&ObjectAttributes,&UnicodeString,SetupRegistryKeyName);
  215. Status = NtOpenKey(
  216. &KeyHandle,
  217. READ_CONTROL | KEY_QUERY_VALUE,
  218. &ObjectAttributes
  219. );
  220. if(!NT_SUCCESS(Status)) {
  221. KdPrintEx((DPFLTR_SETUP_ID,
  222. DPFLTR_WARNING_LEVEL,
  223. "RestartSpSetup: Unable to open %ws (%lx)\n",
  224. SetupRegistryKeyName,
  225. Status));
  226. goto c0;
  227. }
  228. //
  229. // Attempt to get the value of "RestartSpSetup"
  230. //
  231. RtlInitUnicodeString(&UnicodeString,RestartSpSetupValueName);
  232. Status = NtQueryValueKey(
  233. KeyHandle,
  234. &UnicodeString,
  235. KeyValuePartialInformation,
  236. Buffer,
  237. sizeof(Buffer),
  238. &DataLength
  239. );
  240. if(!NT_SUCCESS(Status)) {
  241. KdPrintEx((DPFLTR_SETUP_ID,
  242. DPFLTR_WARNING_LEVEL,
  243. "RestartSpSetup: Unable to get value of %ws (%lx)\n",
  244. RestartSpSetupValueName,
  245. Status));
  246. goto c1;
  247. }
  248. //
  249. // Check for a REG_DWORD value and fetch.
  250. //
  251. KeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer;
  252. if((KeyInfo->Type == REG_DWORD) && (KeyInfo->DataLength == sizeof(ULONG))) {
  253. b = *(PULONG)KeyInfo->Data ? xTRUE : xFALSE;
  254. KdPrintEx((DPFLTR_SETUP_ID,
  255. DPFLTR_INFO_LEVEL,
  256. "RestartSpSetup: Restart value is %u\n",
  257. b));
  258. } else {
  259. KdPrintEx((DPFLTR_SETUP_ID,
  260. DPFLTR_WARNING_LEVEL,
  261. "RestartSpSetup: %ws is corrupt!\n",
  262. RestartSpSetupValueName));
  263. }
  264. c1:
  265. NtClose(KeyHandle);
  266. c0:
  267. return(b);
  268. }
  269. BOOLEAN
  270. SetRestartValue(
  271. VOID
  272. )
  273. /*++
  274. Routine Description:
  275. Set HKLM\System\Setup:RestartSpSetup to REG_DWORD 1.
  276. Arguments:
  277. None.
  278. Return Value:
  279. Boolean value indicating whether the operation was successful.
  280. --*/
  281. {
  282. UNICODE_STRING UnicodeString;
  283. NTSTATUS Status;
  284. OBJECT_ATTRIBUTES ObjectAttributes;
  285. HANDLE KeyHandle;
  286. BOOLEAN b;
  287. ULONG One;
  288. //
  289. // Assume failure.
  290. //
  291. b = FALSE;
  292. //
  293. // Attempt to open the key, which must already be present.
  294. //
  295. INIT_OBJA(&ObjectAttributes,&UnicodeString,SetupRegistryKeyName);
  296. Status = NtOpenKey(
  297. &KeyHandle,
  298. READ_CONTROL | KEY_SET_VALUE,
  299. &ObjectAttributes
  300. );
  301. if(!NT_SUCCESS(Status)) {
  302. KdPrintEx((DPFLTR_SETUP_ID,
  303. DPFLTR_WARNING_LEVEL,
  304. "RestartSpSetup: Unable to open %ws (%lx)\n",
  305. SetupRegistryKeyName,
  306. Status));
  307. goto c0;
  308. }
  309. //
  310. // Attempt to set the value of "RestartSpSetup" to REG_DWORD 1.
  311. //
  312. RtlInitUnicodeString(&UnicodeString,RestartSpSetupValueName);
  313. One = 1;
  314. Status = NtSetValueKey(
  315. KeyHandle,
  316. &UnicodeString,
  317. 0,
  318. REG_DWORD,
  319. &One,
  320. sizeof(ULONG)
  321. );
  322. if(!NT_SUCCESS(Status)) {
  323. KdPrintEx((DPFLTR_SETUP_ID,
  324. DPFLTR_WARNING_LEVEL,
  325. "RestartSpSetup: Unable to set value of %ws (%lx)\n",
  326. RestartSpSetupValueName,
  327. Status));
  328. goto c1;
  329. }
  330. //
  331. // Success.
  332. //
  333. KdPrintEx((DPFLTR_SETUP_ID,
  334. DPFLTR_INFO_LEVEL,
  335. "RestartSpSetup: Value of %ws set to 1\n",
  336. RestartSpSetupValueName));
  337. b = TRUE;
  338. c1:
  339. NtClose(KeyHandle);
  340. c0:
  341. return(b);
  342. }
  343. BOOLEAN
  344. SaveConfigForSpSetupRestart (
  345. VOID
  346. )
  347. /*++
  348. Routine Description:
  349. Prepares the system for restartability
  350. Arguments:
  351. None.
  352. Return Value:
  353. Boolean value indicating whether we were successful.
  354. --*/
  355. {
  356. NTSTATUS Status;
  357. HANDLE DirectoryHandle;
  358. HANDLE FileHandle;
  359. UNICODE_STRING UnicodeString;
  360. OBJECT_ATTRIBUTES ObjectAttributes;
  361. IO_STATUS_BLOCK IoStatusBlock;
  362. LONGLONG Buffer[2048/8];
  363. BOOLEAN FirstQuery;
  364. PFILE_DIRECTORY_INFORMATION FileInfo;
  365. USHORT LengthChars;
  366. BOOLEAN b;
  367. FILE_DISPOSITION_INFORMATION Disposition;
  368. BOOLEAN AnyErrors;
  369. PCOPY_LIST_NODE CopyList,CopyNode,NextNode;
  370. //
  371. // Open \SystemRoot\system32\config for list access.
  372. //
  373. INIT_OBJA(&ObjectAttributes,&UnicodeString,ConfigDirectory);
  374. Status = NtOpenFile(
  375. &DirectoryHandle,
  376. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  377. &ObjectAttributes,
  378. &IoStatusBlock,
  379. FILE_SHARE_READ | FILE_SHARE_WRITE,
  380. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
  381. );
  382. if(!NT_SUCCESS(Status)) {
  383. KdPrintEx((DPFLTR_SETUP_ID,
  384. DPFLTR_WARNING_LEVEL,
  385. "RestartSpSetup: unable to open system32\\config for list access (%lx)\n",
  386. Status));
  387. return(FALSE);
  388. }
  389. FirstQuery = TRUE;
  390. FileInfo = (PFILE_DIRECTORY_INFORMATION)Buffer;
  391. AnyErrors = FALSE;
  392. CopyList = NULL;
  393. do {
  394. Status = NtQueryDirectoryFile(
  395. DirectoryHandle,
  396. NULL, // no event to signal
  397. NULL, // no apc routine
  398. NULL, // no apc context
  399. &IoStatusBlock,
  400. Buffer,
  401. sizeof(Buffer)-sizeof(WCHAR), // leave room for terminating nul
  402. FileDirectoryInformation,
  403. TRUE, // want single entry
  404. NULL, // get 'em all
  405. FirstQuery
  406. );
  407. if(NT_SUCCESS(Status)) {
  408. if(!(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  409. LengthChars = (USHORT)FileInfo->FileNameLength / sizeof(WCHAR);
  410. if (FileInfo->FileName[LengthChars]) {
  411. FileInfo->FileName[LengthChars] = 0;
  412. }
  413. if (pIsRestartHive (FileInfo->FileName)) {
  414. //
  415. // remember .sav files for later.
  416. //
  417. if(CopyNode = MALLOC(sizeof(COPY_LIST_NODE))) {
  418. if(RtlCreateUnicodeString(&CopyNode->UnicodeString,FileInfo->FileName)) {
  419. CopyNode->FileSize = FileInfo->EndOfFile.QuadPart;
  420. CopyNode->Next = CopyList;
  421. CopyList = CopyNode;
  422. } else {
  423. Status = STATUS_NO_MEMORY;
  424. FREE(CopyNode);
  425. }
  426. } else {
  427. Status = STATUS_NO_MEMORY;
  428. }
  429. }
  430. }
  431. FirstQuery = FALSE;
  432. }
  433. } while(NT_SUCCESS(Status));
  434. //
  435. // Check for normal loop termination.
  436. //
  437. if(Status == STATUS_NO_MORE_FILES) {
  438. Status = STATUS_SUCCESS;
  439. }
  440. //
  441. // Even if we got errors, try to keep going.
  442. //
  443. if(!NT_SUCCESS(Status)) {
  444. AnyErrors = TRUE;
  445. KdPrintEx((DPFLTR_SETUP_ID,
  446. DPFLTR_WARNING_LEVEL,
  447. "RestartSpSetup: Status %lx enumerating files\n",
  448. Status));
  449. }
  450. //
  451. // Now run down our list of *.sav and copy to *.
  452. //
  453. for(CopyNode=CopyList; CopyNode; CopyNode=NextNode) {
  454. //
  455. // Remember next node, because we're going to free this one.
  456. //
  457. NextNode = CopyNode->Next;
  458. //
  459. // Create the target name, which is the same as the source name
  460. // with the .sav appended.
  461. //
  462. LengthChars = wcslen (CopyNode->UnicodeString.Buffer) + 1 + BACKUP_EXTENSION_LEN;
  463. UnicodeString.Buffer = MALLOC(LengthChars * sizeof(WCHAR));
  464. if(UnicodeString.Buffer) {
  465. UnicodeString.Length = UnicodeString.MaximumLength = LengthChars * sizeof(WCHAR);
  466. RtlCopyMemory (UnicodeString.Buffer, CopyNode->UnicodeString.Buffer, CopyNode->UnicodeString.Length);
  467. RtlCopyMemory (UnicodeString.Buffer + CopyNode->UnicodeString.Length, BACKUP_EXTENSION, BACKUP_EXTENSION_LEN * sizeof(WCHAR));
  468. UnicodeString.Buffer[LengthChars] = 0;
  469. Status = CopyAFile(
  470. DirectoryHandle,
  471. CopyNode->FileSize,
  472. CopyNode->UnicodeString.Buffer,
  473. UnicodeString.Buffer,
  474. TRUE
  475. );
  476. } else {
  477. Status = STATUS_NO_MEMORY;
  478. }
  479. if(!NT_SUCCESS(Status)) {
  480. AnyErrors = TRUE;
  481. KdPrintEx((DPFLTR_SETUP_ID,
  482. DPFLTR_WARNING_LEVEL,
  483. "RestartSpSetup: Unable to copy %ws (%lx)\n",
  484. CopyNode->UnicodeString.Buffer,Status));
  485. }
  486. FREE(CopyNode->UnicodeString.Buffer);
  487. FREE(CopyNode);
  488. }
  489. NtClose(DirectoryHandle);
  490. return((BOOLEAN)!AnyErrors);
  491. }
  492. BOOLEAN
  493. RestoreConfigForSpSetupRestart(
  494. VOID
  495. )
  496. /*++
  497. Routine Description:
  498. Prepares the system for restarting gui mode setup.
  499. Currently this consists of erasing %sysroot%\system32\config\*,
  500. except *.sav, then copying *.sav to *.
  501. Arguments:
  502. None.
  503. Return Value:
  504. Boolean value indicating whether we were successful.
  505. --*/
  506. {
  507. BOOLEAN b;
  508. //
  509. // Display a message indicating that we are rolling back to the
  510. // start of gui mode setup.
  511. //
  512. Message(MSG_CRLF,0);
  513. Message(MSG_RESTARTING_SETUP,0);
  514. b = RestoreConfigDirectory();
  515. return b;
  516. }
  517. BOOLEAN
  518. RestoreConfigDirectory(
  519. VOID
  520. )
  521. /*++
  522. Routine Description:
  523. Erase %sysroot%\system32\config\*, except *.sav, and userdiff,
  524. then copy *.sav to *.
  525. Arguments:
  526. None.
  527. Return Value:
  528. Boolean value indicating whether we were successful.
  529. --*/
  530. {
  531. NTSTATUS Status;
  532. HANDLE DirectoryHandle;
  533. HANDLE FileHandle;
  534. UNICODE_STRING UnicodeString;
  535. OBJECT_ATTRIBUTES ObjectAttributes;
  536. IO_STATUS_BLOCK IoStatusBlock;
  537. LONGLONG Buffer[2048/8];
  538. BOOLEAN FirstQuery;
  539. PFILE_DIRECTORY_INFORMATION FileInfo;
  540. ULONG LengthChars;
  541. BOOLEAN b;
  542. FILE_DISPOSITION_INFORMATION Disposition;
  543. BOOLEAN AnyErrors;
  544. PCOPY_LIST_NODE CopyList,CopyNode,NextNode;
  545. ULONG DotCount;
  546. //
  547. // Open \SystemRoot\system32\config for list access.
  548. //
  549. INIT_OBJA(&ObjectAttributes,&UnicodeString,ConfigDirectory);
  550. Status = NtOpenFile(
  551. &DirectoryHandle,
  552. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  553. &ObjectAttributes,
  554. &IoStatusBlock,
  555. FILE_SHARE_READ | FILE_SHARE_WRITE,
  556. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
  557. );
  558. DotCount = 0;
  559. Message(MSG_RESTARTING_SETUP,++DotCount);
  560. if(!NT_SUCCESS(Status)) {
  561. KdPrintEx((DPFLTR_SETUP_ID,
  562. DPFLTR_WARNING_LEVEL,
  563. "RestartSpSetup: unable to open system32\\config for list access (%lx)\n",
  564. Status));
  565. return(FALSE);
  566. }
  567. FirstQuery = TRUE;
  568. FileInfo = (PFILE_DIRECTORY_INFORMATION)Buffer;
  569. AnyErrors = FALSE;
  570. CopyList = NULL;
  571. do {
  572. Status = NtQueryDirectoryFile(
  573. DirectoryHandle,
  574. NULL, // no event to signal
  575. NULL, // no apc routine
  576. NULL, // no apc context
  577. &IoStatusBlock,
  578. Buffer,
  579. sizeof(Buffer)-sizeof(WCHAR), // leave room for terminating nul
  580. FileDirectoryInformation,
  581. TRUE, // want single entry
  582. NULL, // get 'em all
  583. FirstQuery
  584. );
  585. if(NT_SUCCESS(Status)) {
  586. if(!(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  587. LengthChars = FileInfo->FileNameLength / sizeof(WCHAR);
  588. if (FileInfo->FileName[LengthChars]) {
  589. FileInfo->FileName[LengthChars] = 0;
  590. }
  591. if (LengthChars > BACKUP_EXTENSION_LEN &&
  592. AreStringsEqual (FileInfo->FileName + LengthChars - BACKUP_EXTENSION_LEN, BACKUP_EXTENSION)
  593. ) {
  594. FileInfo->FileName[LengthChars - BACKUP_EXTENSION_LEN] = 0;
  595. b = pIsRestartHive (FileInfo->FileName);
  596. FileInfo->FileName[LengthChars - BACKUP_EXTENSION_LEN] = L'.';
  597. if (b) {
  598. //
  599. // remember .sav files for later.
  600. //
  601. if(CopyNode = MALLOC(sizeof(COPY_LIST_NODE))) {
  602. if(RtlCreateUnicodeString(&CopyNode->UnicodeString,FileInfo->FileName)) {
  603. CopyNode->FileSize = FileInfo->EndOfFile.QuadPart;
  604. CopyNode->Next = CopyList;
  605. CopyList = CopyNode;
  606. } else {
  607. Status = STATUS_NO_MEMORY;
  608. FREE(CopyNode);
  609. }
  610. } else {
  611. Status = STATUS_NO_MEMORY;
  612. }
  613. }
  614. }
  615. }
  616. FirstQuery = FALSE;
  617. }
  618. } while(NT_SUCCESS(Status));
  619. //
  620. // Check for normal loop termination.
  621. //
  622. if(Status == STATUS_NO_MORE_FILES) {
  623. Status = STATUS_SUCCESS;
  624. }
  625. //
  626. // Even if we got errors, try to keep going.
  627. //
  628. if(!NT_SUCCESS(Status)) {
  629. AnyErrors = TRUE;
  630. KdPrintEx((DPFLTR_SETUP_ID,
  631. DPFLTR_WARNING_LEVEL,
  632. "RestartSpSetup: Status %lx enumerating files\n",
  633. Status));
  634. }
  635. //
  636. // Now run down our list of *.sav and copy to *.
  637. //
  638. for(CopyNode=CopyList; CopyNode; CopyNode=NextNode) {
  639. Message(MSG_RESTARTING_SETUP,++DotCount);
  640. //
  641. // Remember next node, because we're going to free this one.
  642. //
  643. NextNode = CopyNode->Next;
  644. //
  645. // Create the target name, which is the same as the source name
  646. // with the .sav stripped off.
  647. //
  648. if(RtlCreateUnicodeString(&UnicodeString,CopyNode->UnicodeString.Buffer)) {
  649. UnicodeString.Buffer[(UnicodeString.Length/sizeof(WCHAR))-4] = 0;
  650. UnicodeString.Length -= 4*sizeof(WCHAR);
  651. Status = CopyAFile(
  652. DirectoryHandle,
  653. CopyNode->FileSize,
  654. CopyNode->UnicodeString.Buffer,
  655. UnicodeString.Buffer,
  656. FALSE
  657. );
  658. RtlFreeUnicodeString(&UnicodeString);
  659. } else {
  660. Status = STATUS_NO_MEMORY;
  661. }
  662. if(!NT_SUCCESS(Status)) {
  663. AnyErrors = TRUE;
  664. KdPrintEx((DPFLTR_SETUP_ID,
  665. DPFLTR_WARNING_LEVEL,
  666. "RestartSpSetup: Unable to copy %ws (%lx)\n",
  667. CopyNode->UnicodeString.Buffer,Status));
  668. }
  669. RtlFreeUnicodeString(&CopyNode->UnicodeString);
  670. FREE(CopyNode);
  671. }
  672. NtClose(DirectoryHandle);
  673. return((BOOLEAN)!AnyErrors);
  674. }
  675. NTSTATUS
  676. CopyAFile(
  677. IN HANDLE DirectoryHandle,
  678. IN LONGLONG FileSize,
  679. IN PCWSTR ExistingFile,
  680. IN PCWSTR NewFile,
  681. IN BOOLEAN BackupTargetIfExists
  682. )
  683. /*++
  684. Routine Description:
  685. Performs a simple file copy within a directory.
  686. The target file must either not exist or be writable.
  687. Only the default stream is copied.
  688. Arguments:
  689. DirectoryHandle - supplies handle to directory within which
  690. the file is to be copied. The handle must have appropriate
  691. access to allow this.
  692. FileSize - supplies size of file to be copied.
  693. ExistingFile - supplies filename of file within directory to
  694. be copied.
  695. NewFile - supplies name of file to be created as a copy of
  696. the existing file.
  697. BackupTargetIfExists - specifies if a backup of the target should
  698. be created (if target file exists) by appending ".sps"
  699. Return Value:
  700. NT Status code indicating outcome.
  701. --*/
  702. {
  703. UNICODE_STRING UnicodeString;
  704. OBJECT_ATTRIBUTES ObjectAttributes;
  705. IO_STATUS_BLOCK IoStatusBlock;
  706. NTSTATUS Status;
  707. HANDLE SourceHandle;
  708. HANDLE TargetHandle;
  709. HANDLE SetAttributesHandle;
  710. ULONG XFerSize;
  711. PCWSTR NewFileBackup;
  712. UNICODE_STRING NewFileString;
  713. USHORT Length;
  714. PFILE_RENAME_INFORMATION RenameInformation;
  715. FILE_INFORMATION_CLASS SetInfoClass;
  716. FILE_BASIC_INFORMATION BasicInfo;
  717. ULONG SetInfoLength;
  718. PVOID SetInfoBuffer;
  719. KdPrintEx((DPFLTR_SETUP_ID,
  720. DPFLTR_INFO_LEVEL,
  721. "RestartSpSetup: Copying %ws to %ws\n",
  722. ExistingFile,
  723. NewFile));
  724. //
  725. // backup the target fisrt, if it exists and the caller wanted that
  726. //
  727. if (BackupTargetIfExists) {
  728. INIT_OBJA(&ObjectAttributes,&UnicodeString,NewFile);
  729. ObjectAttributes.RootDirectory = DirectoryHandle;
  730. Status = NtOpenFile(&TargetHandle,
  731. (ACCESS_MASK)DELETE | SYNCHRONIZE,
  732. &ObjectAttributes,
  733. &IoStatusBlock,
  734. FILE_SHARE_READ | FILE_SHARE_WRITE,
  735. FILE_SYNCHRONOUS_IO_NONALERT
  736. );
  737. if(NT_SUCCESS(Status)) {
  738. //
  739. // the *.sav file does exist; NewFileString is *.sav.psp
  740. //
  741. Length = UnicodeString.Length + (SPS_EXTENSION_LEN + 1) * sizeof(WCHAR);
  742. NewFileString.Buffer = MALLOC(Length);
  743. if(!NewFileString.Buffer) {
  744. return STATUS_NO_MEMORY;
  745. }
  746. NewFileString.Length = NewFileString.MaximumLength = Length;
  747. RtlCopyMemory (NewFileString.Buffer, UnicodeString.Buffer, UnicodeString.Length);
  748. RtlCopyMemory (NewFileString.Buffer + UnicodeString.Length / sizeof(WCHAR), SPS_EXTENSION, SPS_EXTENSION_LEN * sizeof(WCHAR));
  749. NewFileString.Buffer[Length / sizeof(WCHAR)] = 0;
  750. KdPrintEx((DPFLTR_SETUP_ID,
  751. DPFLTR_INFO_LEVEL,
  752. "RestartSpSetup: Backing up %ws to %ws\n",
  753. NewFile,
  754. NewFileString.Buffer
  755. ));
  756. SetInfoClass = FileRenameInformation;
  757. SetInfoLength = NewFileString.Length + sizeof(*RenameInformation);
  758. SetInfoBuffer = MALLOC(SetInfoLength);
  759. if (!SetInfoBuffer) {
  760. FREE(NewFileString.Buffer);
  761. return STATUS_NO_MEMORY;
  762. }
  763. RenameInformation = (PFILE_RENAME_INFORMATION)SetInfoBuffer;
  764. RenameInformation->ReplaceIfExists = TRUE;
  765. RenameInformation->RootDirectory = DirectoryHandle;
  766. RenameInformation->FileNameLength = NewFileString.Length;
  767. RtlMoveMemory(RenameInformation->FileName,
  768. NewFileString.Buffer,
  769. NewFileString.Length);
  770. Status = NtSetInformationFile(TargetHandle,
  771. &IoStatusBlock,
  772. SetInfoBuffer,
  773. SetInfoLength,
  774. SetInfoClass);
  775. if (Status == STATUS_OBJECT_NAME_COLLISION) {
  776. //
  777. // oops, the *.sav.sps file does exist and it's read-only;
  778. // we must force the rename
  779. //
  780. KdPrintEx((DPFLTR_SETUP_ID,
  781. DPFLTR_INFO_LEVEL,
  782. "RestartSpSetup: %ws exists and is read-only; resetting attribs\n",
  783. NewFileString.Buffer
  784. ));
  785. //
  786. // Open the file for Write Attributes access
  787. //
  788. InitializeObjectAttributes(
  789. &ObjectAttributes,
  790. &NewFileString,
  791. OBJ_CASE_INSENSITIVE,
  792. DirectoryHandle,
  793. NULL
  794. );
  795. Status = NtOpenFile(&SetAttributesHandle,
  796. (ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  797. &ObjectAttributes,
  798. &IoStatusBlock,
  799. FILE_SHARE_READ | FILE_SHARE_WRITE,
  800. FILE_SYNCHRONOUS_IO_NONALERT);
  801. if(NT_SUCCESS(Status)){
  802. RtlZeroMemory(&BasicInfo,sizeof(BasicInfo));
  803. BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  804. Status = NtSetInformationFile(SetAttributesHandle,
  805. &IoStatusBlock,
  806. &BasicInfo,
  807. sizeof(BasicInfo),
  808. FileBasicInformation);
  809. NtClose(SetAttributesHandle);
  810. if(NT_SUCCESS(Status)){
  811. Status = NtSetInformationFile(TargetHandle,
  812. &IoStatusBlock,
  813. SetInfoBuffer,
  814. SetInfoLength,
  815. SetInfoClass);
  816. if(NT_SUCCESS(Status)){
  817. KdPrintEx((DPFLTR_SETUP_ID,
  818. DPFLTR_INFO_LEVEL,
  819. "RestartSpSetup: Re-Rename Worked OK\n"));
  820. }
  821. else {
  822. KdPrintEx((DPFLTR_SETUP_ID,
  823. DPFLTR_WARNING_LEVEL,
  824. "RestartSpSetup: Re-Rename Failed - Status == %x\n",
  825. Status));
  826. }
  827. }
  828. else {
  829. KdPrintEx((DPFLTR_SETUP_ID,
  830. DPFLTR_WARNING_LEVEL,
  831. "RestartSpSetup: Set To NORMAL Failed - Status == %x\n",
  832. Status));
  833. }
  834. }
  835. else {
  836. KdPrintEx((DPFLTR_SETUP_ID,
  837. DPFLTR_WARNING_LEVEL,
  838. "RestartSpSetup: Open Existing file %ws Failed - Status == %x\n",
  839. NewFileString.Buffer,
  840. Status));
  841. }
  842. }
  843. NtClose(TargetHandle);
  844. }
  845. if (!NT_SUCCESS(Status)) {
  846. return Status;
  847. }
  848. }
  849. //
  850. // Open the source for reading. The source must exist.
  851. //
  852. INIT_OBJA(&ObjectAttributes,&UnicodeString,ExistingFile);
  853. ObjectAttributes.RootDirectory = DirectoryHandle;
  854. Status = NtOpenFile(
  855. &SourceHandle,
  856. FILE_READ_DATA | SYNCHRONIZE,
  857. &ObjectAttributes,
  858. &IoStatusBlock,
  859. FILE_SHARE_READ,
  860. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
  861. );
  862. if(!NT_SUCCESS(Status)) {
  863. goto c0;
  864. }
  865. //
  866. // Open/create the target for writing.
  867. //
  868. INIT_OBJA(&ObjectAttributes,&UnicodeString,NewFile);
  869. ObjectAttributes.RootDirectory = DirectoryHandle;
  870. Status = NtCreateFile(
  871. &TargetHandle,
  872. FILE_WRITE_DATA | SYNCHRONIZE,
  873. &ObjectAttributes,
  874. &IoStatusBlock,
  875. NULL,
  876. FILE_ATTRIBUTE_NORMAL,
  877. 0,
  878. FILE_OVERWRITE_IF,
  879. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  880. NULL,
  881. 0
  882. );
  883. if(!NT_SUCCESS(Status)) {
  884. goto c1;
  885. }
  886. //
  887. // Read/write buffers while there's still data to copy.
  888. //
  889. while(NT_SUCCESS(Status) && FileSize) {
  890. XFerSize = (FileSize < COPYBUF_SIZE) ? (ULONG)FileSize : COPYBUF_SIZE;
  891. Status = NtReadFile(
  892. SourceHandle,
  893. NULL,
  894. NULL,
  895. NULL,
  896. &IoStatusBlock,
  897. CopyBuffer,
  898. XFerSize,
  899. NULL,
  900. NULL
  901. );
  902. if(NT_SUCCESS(Status)) {
  903. Status = NtWriteFile(
  904. TargetHandle,
  905. NULL,
  906. NULL,
  907. NULL,
  908. &IoStatusBlock,
  909. CopyBuffer,
  910. XFerSize,
  911. NULL,
  912. NULL
  913. );
  914. FileSize -= XFerSize;
  915. }
  916. }
  917. NtClose(TargetHandle);
  918. c1:
  919. NtClose(SourceHandle);
  920. c0:
  921. return(Status);
  922. }
  923. BOOLEAN
  924. AreStringsEqual(
  925. IN PCWSTR String1,
  926. IN PCWSTR String2
  927. )
  928. /*++
  929. Routine Description:
  930. Compare 2 0-terminated unicode strings, case insensitively.
  931. Arguments:
  932. String1 - supplies first string for comparison
  933. String2 - supplies second string for comparison
  934. Return Value:
  935. Boolean value indicating whether strings are equal.
  936. TRUE = yes; FALSE = no.
  937. --*/
  938. {
  939. UNICODE_STRING u1;
  940. UNICODE_STRING u2;
  941. RtlInitUnicodeString(&u1,String1);
  942. RtlInitUnicodeString(&u2,String2);
  943. return((BOOLEAN)(RtlCompareUnicodeString(&u1,&u2,TRUE) == 0));
  944. }
  945. BOOLEAN
  946. Message(
  947. IN ULONG MessageId,
  948. IN ULONG DotCount,
  949. ...
  950. )
  951. /*++
  952. Routine Description:
  953. Format and display a message, which is retreived from
  954. the image's message resources.
  955. Arguments:
  956. MessageId - Supplies the message id of the message resource.
  957. DotCount - Supplies number of trailing dots to be appended to
  958. the message text prior to display. If this value is non-0,
  959. then the message shouldn't have a trailing cr/lf!
  960. Additional arguments specify message-specific inserts.
  961. Return Value:
  962. Boolean value indicating whether the message was displayed.
  963. --*/
  964. {
  965. PVOID ImageBase;
  966. NTSTATUS Status;
  967. PMESSAGE_RESOURCE_ENTRY MessageEntry;
  968. ANSI_STRING AnsiString;
  969. UNICODE_STRING UnicodeString;
  970. va_list arglist;
  971. WCHAR Buffer[1024];
  972. ULONG u;
  973. //
  974. // Get our image base address
  975. //
  976. ImageBase = NtCurrentPeb()->ImageBaseAddress;
  977. if(!ImageBase) {
  978. return(FALSE);
  979. }
  980. //
  981. // Find the message.
  982. // For DBCS codepages we will use English resources instead of
  983. // default resource because we can only display ASCII characters onto
  984. // blue Screen via HalDisplayString()
  985. //
  986. Status = RtlFindMessage(
  987. ImageBase,
  988. 11,
  989. NLS_MB_CODE_PAGE_TAG ? MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US) : 0,
  990. MessageId,
  991. &MessageEntry
  992. );
  993. if(!NT_SUCCESS(Status)) {
  994. return(FALSE);
  995. }
  996. //
  997. // If the message is not unicode, convert to unicode.
  998. // Let the conversion routine allocate the buffer.
  999. //
  1000. if(!(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE)) {
  1001. RtlInitAnsiString(&AnsiString,MessageEntry->Text);
  1002. Status = RtlAnsiStringToUnicodeString(&UnicodeString,&AnsiString,TRUE);
  1003. if(!NT_SUCCESS(Status)) {
  1004. return(FALSE);
  1005. }
  1006. } else {
  1007. //
  1008. // Message is already unicode. Make a copy.
  1009. //
  1010. if(!RtlCreateUnicodeString(&UnicodeString,(PWSTR)MessageEntry->Text)) {
  1011. return(FALSE);
  1012. }
  1013. }
  1014. //
  1015. // Format the message.
  1016. //
  1017. va_start(arglist,DotCount);
  1018. Status = RtlFormatMessage(
  1019. UnicodeString.Buffer,
  1020. 0, // max width
  1021. FALSE, // don't ignore inserts
  1022. FALSE, // args are not ansi
  1023. FALSE, // args are not an array
  1024. &arglist,
  1025. Buffer,
  1026. sizeof(Buffer)/sizeof(Buffer[0]),
  1027. NULL
  1028. );
  1029. va_end(arglist);
  1030. //
  1031. // We don't need the message source any more. Free it.
  1032. //
  1033. RtlFreeUnicodeString(&UnicodeString);
  1034. //
  1035. // Add dots and cr.
  1036. //
  1037. for(u=0; u<DotCount; u++) {
  1038. wcscat(Buffer,L".");
  1039. }
  1040. wcscat(Buffer,L"\r");
  1041. //
  1042. // Print out the message
  1043. //
  1044. RtlInitUnicodeString(&UnicodeString,Buffer);
  1045. Status = NtDisplayString(&UnicodeString);
  1046. return(NT_SUCCESS(Status));
  1047. }