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.

5454 lines
148 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. sputil.c
  5. Abstract:
  6. Miscellaneous functions for text setup.
  7. Author:
  8. Ted Miller (tedm) 17-Sep-1993
  9. Revision History:
  10. --*/
  11. #include "spprecmp.h"
  12. #pragma hdrstop
  13. #include "bootvar.h"
  14. #include "bootstatus.h"
  15. #if !defined(SETUP_CAB_TEST_USERMODE)
  16. //
  17. // On x86, we want to clear the previous OS entry in boot.ini if
  18. // we reformat C:
  19. //
  20. #ifdef _X86_
  21. UCHAR OldSystemLine[MAX_PATH];
  22. BOOLEAN DiscardOldSystemLine = FALSE;
  23. #endif
  24. BOOLEAN Nec98RestoreBootFiles = TRUE; //NEC98
  25. extern PDISK_REGION TargetRegion_Nec98;
  26. #define REGKEY_SERVICES L"\\Registry\\Machine\\System\\CurrentControlSet\\Services"
  27. LIST_ENTRY SpServiceList;
  28. typedef struct _SERVICE_ENTRY {
  29. LIST_ENTRY Next;
  30. PWCHAR ServiceName;
  31. } SERVICE_ENTRY, *PSERVICE_ENTRY;
  32. //
  33. // Setup progress callback data
  34. //
  35. #define MAX_SETUP_PROGRESS_SUBSCRIBERS 8
  36. ULONG ProgressSubscribersCount = 0;
  37. TM_PROGRESS_SUBSCRIBER ProgressSubscribers[MAX_SETUP_PROGRESS_SUBSCRIBERS] = {0};
  38. //
  39. // NEC98
  40. //
  41. NTSTATUS
  42. SpDeleteAndBackupBootFiles(
  43. IN BOOLEAN RestoreBackupFiles,
  44. IN BOOLEAN DeleteBackupFiles,
  45. IN BOOLEAN DeleteRootFiles,
  46. IN BOOLEAN RestorePreviousOs,
  47. IN BOOLEAN ClearBootFlag
  48. );
  49. //
  50. // NEC98
  51. //
  52. VOID
  53. SpSetAutoBootFlag(
  54. IN PDISK_REGION TargetRegion,
  55. IN BOOLEAN SetBootPosision
  56. );
  57. //
  58. // NEC98
  59. //
  60. NTSTATUS
  61. SppRestoreBootCode(
  62. VOID
  63. );
  64. //
  65. // These symbols are the Chkdsk return codes given by autochk
  66. // when invoked with the '/s' switch. They were duplicated from
  67. // utils\ifsutil\inc\supera.hxx, and should be kept in sync with
  68. // the codes listed there.
  69. //
  70. #define CHKDSK_EXIT_SUCCESS 0
  71. #define CHKDSK_EXIT_ERRS_FIXED 1
  72. #define CHKDSK_EXIT_MINOR_ERRS 2 // whether or not "/f"
  73. #define CHKDSK_EXIT_COULD_NOT_CHK 3
  74. #define CHKDSK_EXIT_ERRS_NOT_FIXED 3
  75. #define CHKDSK_EXIT_COULD_NOT_FIX 3
  76. #define AUTOFMT_EXIT_SUCCESS 0
  77. #define AUTOFMT_EXIT_COULD_NOT_FORMAT 1
  78. //
  79. // Gauge used to display progress of autochk and autofmt
  80. //
  81. PVOID UserModeGauge = NULL;
  82. //
  83. // This variable is used when displaying the progress bar
  84. // during autochk and autofmt. It indicates the disk that
  85. // is being autochecked or formatted.
  86. //
  87. ULONG CurrentDiskIndex = 0;
  88. //
  89. // Seed used for generating random number for disk signature
  90. // and pseudo GUIDs
  91. //
  92. ULONG RandomSeed = 17;
  93. BOOLEAN
  94. SppPromptOptionalAutochk(
  95. IN PVOID SifHandle,
  96. IN PWSTR MediaShortname,
  97. IN PWSTR DiskDevicePath
  98. );
  99. extern BOOLEAN
  100. SpGenerateNTPathName(
  101. IN PDISK_REGION Region,
  102. IN PWSTR DefaultPath,
  103. OUT PWSTR TargetPath
  104. );
  105. VOID
  106. SpDone(
  107. IN DWORD MsgId,
  108. IN BOOLEAN Successful,
  109. IN BOOLEAN Wait
  110. )
  111. /*++
  112. Routine Description:
  113. Display a message indicating that we are done with setup,
  114. and text setup completed successfully, or that windows nt
  115. is not installed. Then reboot the machine.
  116. Arguments:
  117. Successful - if TRUE, then tell the user that pressing enter will
  118. restart the machine and continue setup. Otherwise, tell the user
  119. that Windows NT is not installed.
  120. Wait - if FALSE, do not display a screen, just reboot immediately.
  121. Otherwise, wait for the user to press enter before rebooting.
  122. Return Value:
  123. DOES NOT RETURN
  124. --*/
  125. {
  126. #define SECS_FOR_REBOOT 15
  127. ULONG MessageId;
  128. PWSTR p;
  129. LARGE_INTEGER DelayInterval;
  130. ULONG InputChar;
  131. ULONG Seconds;
  132. PVOID DelayGauge;
  133. if(Wait) {
  134. if (MsgId) {
  135. MessageId = MsgId;
  136. } else if(RepairWinnt) {
  137. MessageId = Successful ? SP_SCRN_REPAIR_SUCCESS : SP_SCRN_REPAIR_FAILURE;
  138. } else {
  139. MessageId = Successful ? SP_SCRN_TEXTSETUP_SUCCESS : SP_SCRN_TEXTSETUP_FAILURE;
  140. }
  141. SpStartScreen(MessageId,3,4,FALSE,FALSE,DEFAULT_ATTRIBUTE);
  142. #ifdef _X86_
  143. SpContinueScreen(SP_SCRN_REMOVE_FLOPPY,3,1,FALSE,DEFAULT_ATTRIBUTE);
  144. //
  145. // For machines with El-Torito boot we need to tell the user
  146. // to remove the CD-ROM also. There are a whole bunch of different
  147. // possibilities: user booted from floppy but is using the CD, etc.
  148. // We'll only tell the user to remove the CD if he actually booted
  149. // from it, since otherwise we assume the machine is set up to *not*
  150. // boot from CD-ROM and the presence of the CD is irrelevent.
  151. //
  152. // tedm: the above logic is nice but there are plenty of machines
  153. // out there with broken eltorito. Thus well always tell people to
  154. // remove the CD if they have a CD-ROM drive.
  155. //
  156. #if 0
  157. SpStringToLower(ArcBootDevicePath);
  158. if(wcsstr(ArcBootDevicePath,L")cdrom(")) {
  159. SpContinueScreen(SP_SCRN_ALSO_REMOVE_CD,3,0,FALSE,DEFAULT_ATTRIBUTE);
  160. }
  161. // #else
  162. if(IoGetConfigurationInformation()->CdRomCount) {
  163. SpContinueScreen(SP_SCRN_ALSO_REMOVE_CD,3,0,FALSE,DEFAULT_ATTRIBUTE);
  164. }
  165. #endif
  166. #endif
  167. SpContinueScreen(SP_SCRN_ENTER_TO_RESTART,3,1,FALSE,DEFAULT_ATTRIBUTE);
  168. if(!RepairWinnt && Successful) {
  169. SpContinueScreen(SP_SCRN_RESTART_EXPLAIN,3,0,FALSE,DEFAULT_ATTRIBUTE);
  170. }
  171. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_RESTART,0);
  172. DelayInterval.LowPart = -10000000;
  173. DelayInterval.HighPart = -1;
  174. Seconds = 0;
  175. SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_SETUP_REBOOT);
  176. DelayGauge = SpCreateAndDisplayGauge(
  177. SECS_FOR_REBOOT,
  178. 0,
  179. 15,
  180. L"",
  181. TemporaryBuffer,
  182. GF_ITEMS_REMAINING,
  183. ATT_BG_RED | ATT_BG_INTENSE
  184. );
  185. ASSERT( DelayGauge );
  186. SpInputDrain();
  187. while (Seconds < SECS_FOR_REBOOT) {
  188. KeDelayExecutionThread( ExGetPreviousMode(), FALSE, &DelayInterval );
  189. if (SpInputIsKeyWaiting()) {
  190. InputChar = SpInputGetKeypress();
  191. if (InputChar == ASCI_CR) {
  192. break;
  193. } else {
  194. SpInputDrain();
  195. break;
  196. }
  197. }
  198. SpTickGauge( DelayGauge );
  199. Seconds += 1;
  200. }
  201. SpDestroyGauge( DelayGauge );
  202. }
  203. #ifdef _X86_
  204. //
  205. // restore backed up boot files for other OS on NEC98.
  206. //
  207. if (IsNEC_98) { //NEC98
  208. if(Nec98RestoreBootFiles && (IsFloppylessBoot || UnattendedOperation)) {
  209. WCHAR DevicePath[MAX_PATH];
  210. WCHAR PartitionPath[MAX_PATH];
  211. BOOLEAN RestoreBackupFiles, DeleteBackupFiles, DeleteRootDirFiles, RestorePreviousOs, ClearBootFlag;
  212. if(TargetRegion_Nec98) {
  213. wcscpy(DevicePath,
  214. PartitionedDisks[TargetRegion_Nec98->DiskNumber].HardDisk->DevicePath
  215. );
  216. swprintf(PartitionPath,
  217. L"partition%lu",
  218. SpPtGetOrdinal(TargetRegion_Nec98,PartitionOrdinalCurrent)
  219. );
  220. SpConcatenatePaths(DevicePath,PartitionPath);
  221. }
  222. if(Successful){
  223. if(!_wcsicmp(NtBootDevicePath, DevicePath)) {
  224. //
  225. // case normal exit and same bootpath and targetpath.
  226. //
  227. RestoreBackupFiles = FALSE;
  228. DeleteBackupFiles = TRUE;
  229. DeleteRootDirFiles = FALSE;
  230. RestorePreviousOs = FALSE;
  231. ClearBootFlag = FALSE;
  232. //SpDeleteAndBackupBootFiles(FALSE,TRUE,FALSE,FALSE,FALSE);
  233. } else {
  234. //
  235. // case normal exit and different bootpath and targetpath.
  236. //
  237. RestoreBackupFiles = TRUE;
  238. DeleteBackupFiles = TRUE;
  239. DeleteRootDirFiles = TRUE;
  240. RestorePreviousOs = TRUE;
  241. ClearBootFlag = FALSE;
  242. //SpDeleteAndBackupBootFiles(TRUE,TRUE,TRUE,TRUE,FALSE);
  243. }
  244. } else {
  245. //
  246. // case abnormal exit
  247. //
  248. if(TargetRegion_Nec98) {
  249. //
  250. // after selecting target partition
  251. //
  252. if(!_wcsicmp(NtBootDevicePath, DevicePath)) {
  253. RestoreBackupFiles = FALSE;
  254. DeleteBackupFiles = TRUE;
  255. DeleteRootDirFiles = TRUE;
  256. RestorePreviousOs = FALSE;
  257. ClearBootFlag = TRUE;
  258. //SpDeleteAndBackupBootFiles(FALSE,TRUE,TRUE,FALSE,TRUE);
  259. }else{
  260. RestoreBackupFiles = TRUE;
  261. DeleteBackupFiles = TRUE;
  262. DeleteRootDirFiles = TRUE;
  263. RestorePreviousOs = TRUE;
  264. ClearBootFlag = TRUE;
  265. //SpDeleteAndBackupBootFiles(TRUE,TRUE,TRUE,TRUE,TRUE);
  266. }
  267. } else {
  268. RestoreBackupFiles = TRUE;
  269. DeleteBackupFiles = TRUE;
  270. DeleteRootDirFiles = TRUE;
  271. RestorePreviousOs = TRUE;
  272. ClearBootFlag = FALSE;
  273. //SpDeleteAndBackupBootFiles(TRUE,TRUE,TRUE,TRUE,FALSE);
  274. }
  275. //
  276. // In the case of, winnt32 from Win95 that have separated
  277. // system partition or winnt from DOS, Auto boot flag will
  278. // set system partition not booted partition..
  279. //
  280. if(IsFloppylessBoot){
  281. ClearBootFlag = TRUE;
  282. }
  283. }
  284. SpDeleteAndBackupBootFiles(RestoreBackupFiles,
  285. DeleteBackupFiles,
  286. DeleteRootDirFiles,
  287. RestorePreviousOs,
  288. ClearBootFlag);
  289. }
  290. } //NEC98
  291. #endif
  292. CLEAR_CLIENT_SCREEN();
  293. SpDisplayStatusText(SP_STAT_SHUTTING_DOWN,DEFAULT_STATUS_ATTRIBUTE);
  294. SpShutdownSystem();
  295. //
  296. // Shouldn't get here.
  297. //
  298. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: shutdown returned!\n"));
  299. HalReturnToFirmware(HalRebootRoutine);
  300. }
  301. VOID
  302. SpFatalSifError(
  303. IN PVOID SifHandle,
  304. IN PWSTR Section,
  305. IN PWSTR Key, OPTIONAL
  306. IN ULONG Line,
  307. IN ULONG ValueNumber
  308. )
  309. /*++
  310. Routine Description:
  311. Inform the user that a required value is missing or corrupt in
  312. a sif file. Display the section, line number or key, and value
  313. number.
  314. Then reboot the machine.
  315. Arguments:
  316. SifHandle - specifies the information file which is corrupt.
  317. Section - supplies the name of the section that is corrupt.
  318. Key - if specified, specifies the line in the section that is
  319. missing or corrupt.
  320. Line - if Key is not specified, then this is the line number
  321. within the section that is corrupt.
  322. ValueNumber - supplies the value number on the line that is
  323. missing or corrupt.
  324. Return Value:
  325. DOES NOT RETURN
  326. --*/
  327. {
  328. ULONG ValidKeys[2] = { KEY_F3,0 };
  329. //
  330. // Display a message indicating that there is a fatal
  331. // error in the sif file.
  332. //
  333. if(Key) {
  334. SpStartScreen(
  335. SP_SCRN_FATAL_SIF_ERROR_KEY,
  336. 3,
  337. HEADER_HEIGHT+3,
  338. FALSE,
  339. FALSE,
  340. DEFAULT_ATTRIBUTE,
  341. ValueNumber,
  342. Section,
  343. Key
  344. );
  345. } else {
  346. SpStartScreen(
  347. SP_SCRN_FATAL_SIF_ERROR_LINE,
  348. 3,
  349. HEADER_HEIGHT+3,
  350. FALSE,
  351. FALSE,
  352. DEFAULT_ATTRIBUTE,
  353. ValueNumber,
  354. Line,
  355. Section
  356. );
  357. }
  358. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
  359. SpWaitValidKey(ValidKeys,NULL,NULL);
  360. SpDone(0,FALSE,TRUE);
  361. }
  362. VOID
  363. SpNonFatalSifError(
  364. IN PVOID SifHandle,
  365. IN PWSTR Section,
  366. IN PWSTR Key, OPTIONAL
  367. IN ULONG Line,
  368. IN ULONG ValueNumber,
  369. IN PWSTR FileName
  370. )
  371. /*++
  372. Routine Description:
  373. Inform the user that a required value is missing or corrupt in
  374. a sif file. Display the section, line number or key, and value
  375. number, along with the file name that cannot be copied.
  376. Then ask the user if they want to skip the file or exit Setup.
  377. Arguments:
  378. SifHandle - specifies the information file which is corrupt.
  379. Section - supplies the name of the section that is corrupt.
  380. Key - if specified, specifies the line in the section that is
  381. missing or corrupt.
  382. Line - if Key is not specified, then this is the line number
  383. within the section that is corrupt.
  384. ValueNumber - supplies the value number on the line that is
  385. missing or corrupt.
  386. FileName - supplies the name of the file that cannot be copied.
  387. Return Value:
  388. none (may not return if user chooses to exit Setup)
  389. --*/
  390. {
  391. ULONG ValidKeys[3] = { ASCI_ESC, KEY_F3, 0 };
  392. //
  393. // Display a message indicating that there is a fatal
  394. // error in the sif file.
  395. //
  396. if(Key) {
  397. SpStartScreen(
  398. SP_SCRN_NONFATAL_SIF_ERROR_KEY,
  399. 3,
  400. HEADER_HEIGHT+3,
  401. FALSE,
  402. FALSE,
  403. DEFAULT_ATTRIBUTE,
  404. ValueNumber,
  405. Section,
  406. Key,
  407. FileName
  408. );
  409. } else {
  410. SpStartScreen(
  411. SP_SCRN_NONFATAL_SIF_ERROR_LINE,
  412. 3,
  413. HEADER_HEIGHT+3,
  414. FALSE,
  415. FALSE,
  416. DEFAULT_ATTRIBUTE,
  417. ValueNumber,
  418. Line,
  419. Section,
  420. FileName
  421. );
  422. }
  423. SpDisplayStatusOptions(
  424. DEFAULT_STATUS_ATTRIBUTE,
  425. SP_STAT_ESC_EQUALS_SKIP_FILE,
  426. SP_STAT_F3_EQUALS_EXIT,
  427. 0
  428. );
  429. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  430. case ASCI_ESC: // skip file
  431. break;
  432. case KEY_F3: // exit setup
  433. SpConfirmExit();
  434. }
  435. }
  436. VOID
  437. SpConfirmExit(
  438. VOID
  439. )
  440. /*++
  441. Routine Description:
  442. Confirm with the user that he really wants to exit.
  443. If he does, then exit, otherwise return.
  444. When this routine returns, the caller must repaint the entire
  445. client area and status area of the screen.
  446. Arguments:
  447. None.
  448. Return Value:
  449. MAY NOT RETURN
  450. --*/
  451. {
  452. ULONG ValidKeys[3] = { ASCI_CR, KEY_F3, 0 };
  453. WCHAR *p = (WCHAR *)TemporaryBuffer;
  454. BOOLEAN FirstLine,FirstCharOnLine;
  455. //
  456. // Don't erase the screen.
  457. //
  458. // We have to do something very funky here because the resources
  459. // are originally in ANSI, which doesn't have the line-draw chars.
  460. //
  461. vSpFormatMessage(
  462. TemporaryBuffer,
  463. sizeof(TemporaryBuffer),
  464. SP_SCRN_EXIT_CONFIRMATION,
  465. NULL,
  466. NULL
  467. );
  468. for(FirstCharOnLine=TRUE,FirstLine=TRUE; *p; p++) {
  469. switch(*p) {
  470. case L'+':
  471. if(FirstCharOnLine) {
  472. *p = SplangGetLineDrawChar(
  473. FirstLine ? LineCharDoubleUpperLeft : LineCharDoubleLowerLeft
  474. );
  475. FirstCharOnLine = FALSE;
  476. } else {
  477. *p = SplangGetLineDrawChar(
  478. FirstLine ? LineCharDoubleUpperRight : LineCharDoubleLowerRight
  479. );
  480. }
  481. break;
  482. case L'=':
  483. FirstCharOnLine = FALSE;
  484. *p = SplangGetLineDrawChar(LineCharDoubleHorizontal);
  485. break;
  486. case L'-':
  487. FirstCharOnLine = FALSE;
  488. *p = SplangGetLineDrawChar(LineCharSingleHorizontal);
  489. break;
  490. case L'|':
  491. FirstCharOnLine = FALSE;
  492. *p = SplangGetLineDrawChar(LineCharDoubleVertical);
  493. break;
  494. case L'*':
  495. *p = SplangGetLineDrawChar(
  496. FirstCharOnLine
  497. ? LineCharDoubleVerticalToSingleHorizontalRight
  498. : LineCharDoubleVerticalToSingleHorizontalLeft
  499. );
  500. FirstCharOnLine = FALSE;
  501. break;
  502. case L'\n':
  503. FirstCharOnLine = TRUE;
  504. FirstLine = FALSE;
  505. break;
  506. default:
  507. FirstCharOnLine = FALSE;
  508. break;
  509. }
  510. }
  511. SpDisplayText(
  512. TemporaryBuffer,
  513. wcslen(TemporaryBuffer)+1,
  514. TRUE,
  515. TRUE,
  516. ATT_FG_RED | ATT_BG_WHITE,
  517. 0,
  518. 0
  519. );
  520. SpvidClearScreenRegion(
  521. 0,
  522. VideoVars.ScreenHeight-STATUS_HEIGHT,
  523. VideoVars.ScreenWidth,
  524. STATUS_HEIGHT,
  525. DEFAULT_STATUS_BACKGROUND
  526. );
  527. if(SpWaitValidKey(ValidKeys,NULL,NULL) == KEY_F3) {
  528. SpDone(0,FALSE,TRUE);
  529. }
  530. //
  531. // User backed out of bailing, just return to caller.
  532. //
  533. }
  534. #endif
  535. PWSTR
  536. SpDupStringW(
  537. IN PCWSTR String
  538. )
  539. {
  540. PWSTR p;
  541. p = SpMemAlloc((wcslen(String)+1) * sizeof(WCHAR));
  542. ASSERT(p);
  543. wcscpy(p,String);
  544. return(p);
  545. }
  546. PSTR
  547. SpDupString(
  548. IN PCSTR String
  549. )
  550. {
  551. PUCHAR p;
  552. p = SpMemAlloc(strlen(String)+1);
  553. ASSERT(p);
  554. strcpy(p,String);
  555. return(p);
  556. }
  557. PWSTR
  558. SpToUnicode(
  559. IN PUCHAR OemString
  560. )
  561. {
  562. ULONG OemStringSize;
  563. ULONG MaxUnicodeStringSize;
  564. ULONG ActualUnicodeStringSize;
  565. PWSTR UnicodeString;
  566. //
  567. // Determine the maximum number of bytes in the oem string
  568. // and allocate a buffer to hold a string of that size.
  569. // The maximum length of the equivalent unicode string
  570. // is twice that number (this occurs when all oem chars
  571. // in the string are single-byte).
  572. //
  573. OemStringSize = strlen(OemString) + 1;
  574. MaxUnicodeStringSize = OemStringSize * sizeof(WCHAR);
  575. UnicodeString = SpMemAlloc(MaxUnicodeStringSize);
  576. ASSERT(UnicodeString);
  577. //
  578. // Call the conversion routine.
  579. //
  580. RtlOemToUnicodeN(
  581. UnicodeString,
  582. MaxUnicodeStringSize,
  583. &ActualUnicodeStringSize,
  584. OemString,
  585. OemStringSize
  586. );
  587. //
  588. // Reallocate the unicode string to its real size,
  589. // which depends on the number of doublebyte characters
  590. // OemString contained.
  591. //
  592. if(ActualUnicodeStringSize != MaxUnicodeStringSize) {
  593. UnicodeString = SpMemRealloc(UnicodeString,ActualUnicodeStringSize);
  594. ASSERT(UnicodeString);
  595. }
  596. return(UnicodeString);
  597. }
  598. PUCHAR
  599. SpToOem(
  600. IN PWSTR UnicodeString
  601. )
  602. {
  603. ULONG UnicodeStringSize;
  604. ULONG MaxOemStringSize;
  605. ULONG ActualOemStringSize;
  606. PUCHAR OemString;
  607. //
  608. // Allocate a buffer of maximum size to hold the oem string.
  609. // The maximum size would occur if all characters in the
  610. // unicode string being converted have doublebyte OEM equivalents.
  611. //
  612. UnicodeStringSize = (wcslen(UnicodeString)+1) * sizeof(WCHAR);
  613. MaxOemStringSize = UnicodeStringSize;
  614. OemString = SpMemAlloc(MaxOemStringSize);
  615. ASSERT(OemString);
  616. //
  617. // Call the conversion routine.
  618. //
  619. RtlUnicodeToOemN(
  620. OemString,
  621. MaxOemStringSize,
  622. &ActualOemStringSize,
  623. UnicodeString,
  624. UnicodeStringSize
  625. );
  626. //
  627. // Reallocate the oem string to reflect its true size,
  628. // which depends on the number of doublebyte characters it contains.
  629. //
  630. if(ActualOemStringSize != MaxOemStringSize) {
  631. OemString = SpMemRealloc(OemString,ActualOemStringSize);
  632. ASSERT(OemString);
  633. }
  634. return(OemString);
  635. }
  636. VOID
  637. SpConcatenatePaths(
  638. IN OUT PWSTR Path1, OPTIONAL
  639. IN PCWSTR Path2 OPTIONAL
  640. )
  641. {
  642. PWSTR end;
  643. if (!Path1) {
  644. return;
  645. }
  646. //
  647. // Compute the location to concatenate, and also check the base path for
  648. // an existing backslash.
  649. //
  650. end = Path1;
  651. if (*end) {
  652. do {
  653. end++;
  654. } while (*end);
  655. if (end[-1] == L'\\') {
  656. end--;
  657. }
  658. }
  659. //
  660. // If Path2 was specified, skip over an initial backslash
  661. //
  662. if (Path2 && Path2[0] == L'\\') {
  663. Path2++;
  664. }
  665. //
  666. // Append a backslash, then Path2 if it was specified
  667. //
  668. *end++ = L'\\';
  669. if (Path2) {
  670. wcscpy (end, Path2);
  671. } else {
  672. *end = 0;
  673. }
  674. return;
  675. }
  676. #if !defined(SETUP_CAB_TEST_USERMODE)
  677. VOID
  678. SpFetchDiskSpaceRequirements(
  679. IN PVOID SifHandle,
  680. IN ULONG BytesPerCluster,
  681. OUT PULONG FreeKBRequired, OPTIONAL
  682. OUT PULONG FreeKBRequiredSysPart OPTIONAL
  683. )
  684. {
  685. PWSTR p;
  686. if(FreeKBRequired) {
  687. WCHAR ClusterSizeString[64];
  688. if( BytesPerCluster <= 512 ) {
  689. //
  690. // We got some miniscule cluster size. Assume 512 byte.
  691. //
  692. wcscpy( ClusterSizeString, L"WinDirSpace512" );
  693. } else if( BytesPerCluster > (256 * 1024) ) {
  694. //
  695. // We got some huge cluster size. Must be garbage, assume 32K byte.
  696. //
  697. wcscpy( ClusterSizeString, L"WinDirSpace32K" );
  698. } else {
  699. swprintf( ClusterSizeString, L"WinDirSpace%uK", BytesPerCluster/1024 );
  700. }
  701. p = SpGetSectionKeyIndex( SifHandle,
  702. SIF_DISKSPACEREQUIREMENTS,
  703. ClusterSizeString,
  704. 0 );
  705. if(!p) {
  706. SpFatalSifError( SifHandle,
  707. SIF_DISKSPACEREQUIREMENTS,
  708. ClusterSizeString,
  709. 0,
  710. 0 );
  711. }
  712. *FreeKBRequired = (ULONG)SpStringToLong(p,NULL,10);
  713. }
  714. if(FreeKBRequiredSysPart) {
  715. p = SpGetSectionKeyIndex( SifHandle,
  716. SIF_DISKSPACEREQUIREMENTS,
  717. SIF_FREESYSPARTDISKSPACE,
  718. 0 );
  719. if(!p) {
  720. SpFatalSifError( SifHandle,
  721. SIF_DISKSPACEREQUIREMENTS,
  722. SIF_FREESYSPARTDISKSPACE,
  723. 0,
  724. 0 );
  725. }
  726. *FreeKBRequiredSysPart = (ULONG)SpStringToLong(p,NULL,10);
  727. }
  728. }
  729. VOID
  730. SpFetchTempDiskSpaceRequirements(
  731. IN PVOID SifHandle,
  732. IN ULONG BytesPerCluster,
  733. OUT PULONG LocalSourceKBRequired, OPTIONAL
  734. OUT PULONG BootKBRequired OPTIONAL
  735. )
  736. {
  737. PWSTR p;
  738. WCHAR ClusterSizeString[64];
  739. if( BytesPerCluster <= 512 ) {
  740. //
  741. // We got some miniscule cluster size. Assume 512 byte.
  742. //
  743. wcscpy( ClusterSizeString, L"TempDirSpace512" );
  744. } else if( BytesPerCluster > (256 * 1024) ) {
  745. //
  746. // We got some huge cluster size. Must be garbage, assume 32K byte.
  747. //
  748. wcscpy( ClusterSizeString, L"TempDirSpace32K" );
  749. } else {
  750. swprintf( ClusterSizeString, L"TempDirSpace%uK", BytesPerCluster/1024 );
  751. }
  752. if(LocalSourceKBRequired) {
  753. p = SpGetSectionKeyIndex( SifHandle,
  754. SIF_DISKSPACEREQUIREMENTS,
  755. ClusterSizeString,
  756. 0 );
  757. if(!p) {
  758. SpFatalSifError( SifHandle,
  759. SIF_DISKSPACEREQUIREMENTS,
  760. ClusterSizeString,
  761. 0,
  762. 0 );
  763. }
  764. *LocalSourceKBRequired = ((ULONG)SpStringToLong(p,NULL,10) + 1023) / 1024; // round up
  765. }
  766. if(BootKBRequired) {
  767. p = SpGetSectionKeyIndex( SifHandle,
  768. SIF_DISKSPACEREQUIREMENTS,
  769. ClusterSizeString,
  770. 1 );
  771. if(!p) {
  772. SpFatalSifError( SifHandle,
  773. SIF_DISKSPACEREQUIREMENTS,
  774. ClusterSizeString,
  775. 0,
  776. 1 );
  777. }
  778. *BootKBRequired = ((ULONG)SpStringToLong(p,NULL,10) + 1023) / 1024; // round up
  779. }
  780. }
  781. PDISK_REGION
  782. SpRegionFromArcName(
  783. IN PWSTR ArcName,
  784. IN PartitionOrdinalType OrdinalType,
  785. IN PDISK_REGION PreviousMatch
  786. )
  787. /*++
  788. Routine Description:
  789. Given an ARC name find the region descriptor which describes the drive
  790. this ARC name is on.
  791. Arguments:
  792. ArcName - supplies the arc name.
  793. OrdinalType - primary (multi) or secondary (scsi) type.
  794. PreviousMatch - specifies where we should begin looking.
  795. Return Value:
  796. Region descriptor if one found, otherwise NULL.
  797. --*/
  798. {
  799. PDISK_REGION Region = NULL;
  800. PWSTR NormalizedArcPath = NULL;
  801. ULONG disk;
  802. PWSTR ArcPath1,ArcPath2;
  803. BOOLEAN StartLooking = FALSE;
  804. #define BufferSize 2048
  805. ArcPath1 = SpMemAlloc(BufferSize);
  806. ArcPath2 = SpMemAlloc(BufferSize);
  807. if( ArcName && *ArcName ) {
  808. NormalizedArcPath = SpNormalizeArcPath( ArcName );
  809. if( NormalizedArcPath ) {
  810. if(!PreviousMatch) { // then we start from the beginning
  811. StartLooking = TRUE;
  812. }
  813. for( disk=0; disk<HardDiskCount; disk++ ) {
  814. Region = PartitionedDisks[disk].PrimaryDiskRegions;
  815. while( Region ) {
  816. if((!StartLooking) && (Region == PreviousMatch)) {
  817. StartLooking = TRUE;
  818. } else if(Region->PartitionedSpace && StartLooking) {
  819. SpArcNameFromRegion(Region,ArcPath1,BufferSize,OrdinalType,PrimaryArcPath);
  820. SpArcNameFromRegion(Region,ArcPath2,BufferSize,OrdinalType,SecondaryArcPath);
  821. if(!_wcsicmp(ArcPath1, NormalizedArcPath)
  822. || !_wcsicmp(ArcPath2, NormalizedArcPath)) {
  823. break;
  824. }
  825. }
  826. Region = Region->Next;
  827. }
  828. if ( Region ) {
  829. break;
  830. }
  831. Region = PartitionedDisks[disk].ExtendedDiskRegions;
  832. while( Region ) {
  833. if((!StartLooking) && (Region == PreviousMatch)) {
  834. StartLooking = TRUE;
  835. } else if(Region->PartitionedSpace && StartLooking) {
  836. SpArcNameFromRegion(Region,ArcPath1,BufferSize,OrdinalType,PrimaryArcPath);
  837. SpArcNameFromRegion(Region,ArcPath2,BufferSize,OrdinalType,SecondaryArcPath);
  838. if(!_wcsicmp(ArcPath1, NormalizedArcPath)
  839. || !_wcsicmp(ArcPath2, NormalizedArcPath)) {
  840. break;
  841. }
  842. }
  843. Region = Region->Next;
  844. }
  845. if ( Region ) {
  846. break;
  847. }
  848. }
  849. #if defined(REMOTE_BOOT)
  850. if ( (Region == NULL) && RemoteBootSetup && !RemoteInstallSetup &&
  851. (PreviousMatch == NULL) ) {
  852. if (_wcsicmp(L"net(0)", NormalizedArcPath) == 0) {
  853. Region = RemoteBootTargetRegion;
  854. }
  855. }
  856. #endif // defined(REMOTE_BOOT)
  857. }
  858. if( NormalizedArcPath ) {
  859. SpMemFree( NormalizedArcPath );
  860. }
  861. }
  862. SpMemFree(ArcPath1);
  863. SpMemFree(ArcPath2);
  864. return( Region );
  865. }
  866. PDISK_REGION
  867. SpRegionFromNtName(
  868. IN PWSTR NtName,
  869. IN PartitionOrdinalType OrdinalType
  870. )
  871. /*++
  872. Routine Description:
  873. Given an Nt name find the region descriptor which describes the drive
  874. this NT name is on.
  875. Arguments:
  876. NtName - supplies the Nt name of the desired region.
  877. PartitionOrdinalType - Specifies the ordinal type of the partition.
  878. Return Value:
  879. Region descriptor if one found, otherwise NULL.
  880. --*/
  881. {
  882. PDISK_REGION Region = NULL;
  883. PWSTR p;
  884. //
  885. // Convert to arc path.
  886. //
  887. if (p = SpNtToArc(NtName, PrimaryArcPath)) {
  888. Region = SpRegionFromArcName(p, PartitionOrdinalCurrent, NULL);
  889. SpMemFree(p);
  890. }
  891. return(Region);
  892. }
  893. PDISK_REGION
  894. SpRegionFromDosName(
  895. IN PCWSTR DosName
  896. )
  897. /*++
  898. Routine Description:
  899. Given a DOS name find the region descriptor which describes the drive
  900. this ARC name is on.
  901. Arguments:
  902. ArcName - supplies the arc name.
  903. Return Value:
  904. Region descriptor if one found, otherwise NULL.
  905. --*/
  906. {
  907. PDISK_REGION Region = NULL;
  908. ULONG disk;
  909. WCHAR DriveLetter;
  910. if( DosName && *DosName && *(DosName + 1) == L':' ) {
  911. DriveLetter = SpToUpper(*DosName);
  912. #if defined(REMOTE_BOOT)
  913. if ( RemoteBootSetup && !RemoteInstallSetup && (DriveLetter == L'C') ) {
  914. return RemoteBootTargetRegion;
  915. }
  916. #endif // defined(REMOTE_BOOT)
  917. for( disk=0; disk<HardDiskCount; disk++ ) {
  918. Region = PartitionedDisks[disk].PrimaryDiskRegions;
  919. while( Region ) {
  920. if(Region->PartitionedSpace && (Region->DriveLetter == DriveLetter)) {
  921. break;
  922. }
  923. Region = Region->Next;
  924. }
  925. if ( Region ) {
  926. break;
  927. }
  928. Region = PartitionedDisks[disk].ExtendedDiskRegions;
  929. while( Region ) {
  930. if(Region->PartitionedSpace && (Region->DriveLetter == DriveLetter)) {
  931. break;
  932. }
  933. Region = Region->Next;
  934. }
  935. if ( Region ) {
  936. break;
  937. }
  938. }
  939. }
  940. return( Region );
  941. }
  942. PDISK_REGION
  943. SpRegionFromArcOrDosName(
  944. IN PWSTR Name,
  945. IN PartitionOrdinalType OrdinalType,
  946. IN PDISK_REGION PreviousMatch
  947. )
  948. {
  949. PDISK_REGION Region;
  950. //
  951. // Determine if Name represents an ARC name or a DOS name and use
  952. // the appropriate routine to extract the region for this name. Check
  953. // for the ":" character at position 2 to see if it is a DOS name.
  954. // If not a DOS name then assume it is an ARC name.
  955. //
  956. if(Name) {
  957. if(Name[0] && (Name[1] == ':')) {
  958. if(PreviousMatch) {
  959. Region = NULL;
  960. } else {
  961. Region = SpRegionFromDosName(Name);
  962. }
  963. } else {
  964. Region = SpRegionFromArcName(Name, OrdinalType, PreviousMatch);
  965. }
  966. } else {
  967. Region = NULL;
  968. }
  969. return(Region);
  970. }
  971. VOID
  972. SpNtNameFromRegion(
  973. IN PDISK_REGION Region,
  974. OUT PWSTR NtPath,
  975. IN ULONG BufferSizeBytes,
  976. IN PartitionOrdinalType OrdinalType
  977. )
  978. /*++
  979. Routine Description:
  980. Generate a name in the NT name space for a region. This name can be
  981. in one of three forms. For partitions, the name is always of the form
  982. \device\harddisk<n>\partition<m>.
  983. If the region is actually a DoubleSpace drive, then the name is of the form
  984. \device\harddisk<n>\partition<m>.<xxx> where <xxx> is the filename of
  985. the CVF (ie, something like dblspace.001).
  986. If the region is on a redirected drive, the name is of the form
  987. \device\lanmanredirector\<server>\<share>
  988. Arguments:
  989. Region - supplies a pointer to the region descriptor for the region
  990. whose path is desired.
  991. NtPath - receives the path.
  992. BufferSizeBytes - specifies the size of the buffer pointed to by NtPath.
  993. The name will be truncated to fit in the buffer if necessary.
  994. OrdinalType - indicates which partition ordinal (original, on disk,
  995. current) to use when generating the name.
  996. Return Value:
  997. None.
  998. --*/
  999. {
  1000. ULONG MaxNameChars;
  1001. ULONG NeededChars;
  1002. WCHAR PartitionComponent[50];
  1003. #if defined(REMOTE_BOOT)
  1004. //
  1005. // Handle remote boot case where target is over the network.
  1006. //
  1007. if (Region->DiskNumber == 0xffffffff) {
  1008. wcscpy(NtPath,Region->TypeName);
  1009. return;
  1010. }
  1011. #endif // defined(REMOTE_BOOT)
  1012. //
  1013. // Calculate the maximum size of the name if unicode characters.
  1014. // Leave room for a terminating nul.
  1015. //
  1016. MaxNameChars = (BufferSizeBytes / sizeof(WCHAR)) - 1;
  1017. //
  1018. // Generate the partition component of the name.
  1019. // Note that the first letter of PartitionComponent must be upper case.
  1020. //
  1021. _snwprintf(
  1022. PartitionComponent,
  1023. (sizeof(PartitionComponent)/sizeof(WCHAR)) - 1,
  1024. L"\\Partition%u",
  1025. SpPtGetOrdinal(Region,OrdinalType)
  1026. );
  1027. //
  1028. // Calculate the amount of buffer space needed for the path.
  1029. //
  1030. NeededChars = wcslen(HardDisks[Region->DiskNumber].DevicePath)
  1031. + wcslen(PartitionComponent);
  1032. if(Region->Filesystem == FilesystemDoubleSpace) {
  1033. //
  1034. // Add the size taken up by the double space cvf name.
  1035. // This is the length of the name, plus one character
  1036. // for the dot.
  1037. //
  1038. NeededChars += 8+1+3+1; // Maximum size of a CVF file name
  1039. }
  1040. //
  1041. // Even though we do something reasonable in this case,
  1042. // really it should never happen. If the name is truncated,
  1043. // it won't be of any use anyway.
  1044. //
  1045. ASSERT(NeededChars <= MaxNameChars);
  1046. //
  1047. // Generate the name.
  1048. //
  1049. if(Region->Filesystem == FilesystemDoubleSpace) {
  1050. _snwprintf(
  1051. NtPath,
  1052. MaxNameChars,
  1053. L"%ws%ws.%ws.%03d",
  1054. HardDisks[Region->DiskNumber].DevicePath,
  1055. PartitionComponent,
  1056. L"DBLSPACE",
  1057. Region->SeqNumber
  1058. );
  1059. } else {
  1060. _snwprintf(
  1061. NtPath,
  1062. MaxNameChars,
  1063. L"%ws%ws",
  1064. HardDisks[Region->DiskNumber].DevicePath,
  1065. PartitionComponent
  1066. );
  1067. }
  1068. }
  1069. VOID
  1070. SpArcNameFromRegion(
  1071. IN PDISK_REGION Region,
  1072. OUT PWSTR ArcPath,
  1073. IN ULONG BufferSizeBytes,
  1074. IN PartitionOrdinalType OrdinalType,
  1075. IN ENUMARCPATHTYPE ArcPathType
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. Generate a name in the ARC name space for a region.
  1080. Arguments:
  1081. Region - supplies a pointer to the region descriptor for the region
  1082. whose path is desired.
  1083. ArcPath - receives the path.
  1084. BufferSizeBytes - specifies the size of the buffer pointed to by ArcPath.
  1085. The name will be truncated to fit in the buffer if necessary.
  1086. OrdinalType - indicates which partition ordinal (original, on disk,
  1087. current) to use when generating the name.
  1088. ArcPathType - Look for the primary or secondary arc path depending on this value.
  1089. This is meaningful for disks on x86 that are scsi but visible
  1090. through the bios. The multi() style name is the 'primary' arc
  1091. path; the scsi() style name is the 'secondary' one.
  1092. Return Value:
  1093. None.
  1094. --*/
  1095. {
  1096. PWSTR p;
  1097. //
  1098. // Get the nt name.
  1099. //
  1100. SpNtNameFromRegion(Region,ArcPath,BufferSizeBytes,OrdinalType);
  1101. //
  1102. // Convert to arc path.
  1103. //
  1104. if(p = SpNtToArc(ArcPath,ArcPathType)) {
  1105. wcsncpy(ArcPath,p,(BufferSizeBytes/sizeof(WCHAR))-1);
  1106. SpMemFree(p);
  1107. ArcPath[(BufferSizeBytes/sizeof(WCHAR))-1] = 0;
  1108. } else {
  1109. *ArcPath = 0;
  1110. }
  1111. }
  1112. BOOLEAN
  1113. SpNtNameFromDosPath (
  1114. IN PCWSTR DosPath,
  1115. OUT PWSTR NtPath,
  1116. IN UINT NtPathSizeInBytes,
  1117. IN PartitionOrdinalType OrdinalType
  1118. )
  1119. /*++
  1120. Routine Description:
  1121. SpNtNameFromDosPath converts a DOS path (in x:\foo\bar format) into an NT
  1122. name (such as \devices\harddisk0\parition1\foo\bar).
  1123. Arguments:
  1124. DosPath - Specifies the DOS path to convert
  1125. NtPath - Receives the NT object
  1126. NtPathSizeInBytes - Specifies the size of NtPath
  1127. OrdinalType - indicates which partition ordinal (original, on disk, current)
  1128. to use when generating the name.
  1129. Return Value:
  1130. TRUE if the path was converted, FALSE otherwise.
  1131. --*/
  1132. {
  1133. PDISK_REGION region;
  1134. //
  1135. // Get region on disk for the DOS path
  1136. //
  1137. region = SpRegionFromDosName (DosPath);
  1138. if (!region) {
  1139. KdPrintEx ((
  1140. DPFLTR_SETUP_ID,
  1141. DPFLTR_ERROR_LEVEL,
  1142. "SETUP: SpNtPathFromDosPath failed to get region for %ws\n",
  1143. DosPath
  1144. ));
  1145. return FALSE;
  1146. }
  1147. //
  1148. // Convert region struct into an NT path.
  1149. //
  1150. SpNtNameFromRegion(
  1151. region,
  1152. NtPath,
  1153. NtPathSizeInBytes - (wcslen (&DosPath[2]) * sizeof (WCHAR)),
  1154. OrdinalType
  1155. );
  1156. SpConcatenatePaths (NtPath, &DosPath[2]);
  1157. return TRUE;
  1158. }
  1159. BOOLEAN
  1160. SpPromptForDisk(
  1161. IN PWSTR DiskDescription,
  1162. IN OUT PWSTR DiskDevicePath,
  1163. IN PWSTR DiskTagFile,
  1164. IN BOOLEAN IgnoreDiskInDrive,
  1165. IN BOOLEAN AllowEscape,
  1166. IN BOOLEAN WarnMultiplePrompts,
  1167. OUT PBOOLEAN pRedrawFlag
  1168. )
  1169. /*++
  1170. Routine Description:
  1171. Prompt the user to insert a floppy disk or CD-ROM.
  1172. Arguments:
  1173. DiskDescription - supplies a descriptive name for the disk.
  1174. DiskDevicePath - supplies the device path for the device on
  1175. which we want the user to insert the disk. This should
  1176. be a real nt device object, as opposed to a symbolic link
  1177. (ie, use \device\floppy0, not \dosdevices\a:).
  1178. NOTE: This path will be modified only in case of prompting
  1179. for a CD-ROM 0 and the required disk existed on another
  1180. CD-ROM like CD-ROM 2.
  1181. DiskTagFile - supplies the full path (relative to the root)
  1182. of a file whose presence on the disk indicates the presence
  1183. of the disk we are prompting for.
  1184. IgnoreDiskInDrive - if TRUE, the Setup will always issue at least
  1185. one prompt. If FALSE, Setup checks the disk in the drive
  1186. and thus may issue 0 prompts.
  1187. AllowEscape - if TRUE, the user can press escape to indicate
  1188. that he wishes to cancel the operation. (This is meaningful
  1189. only to the caller).
  1190. WarnMultiplePrompts - if TRUE and DiskDevicePath desribes a
  1191. floppy disk drive, then put up a little note when displaying the
  1192. disk prompt, that we may prompt for some disks more than once.
  1193. Users get confused when we ask them to insert disks that they
  1194. already inserted once before.
  1195. pRedrawFlag - if non-NULL, receives a flag indicating whether the
  1196. screen was messed up with a disk prompt, requiring a redraw.
  1197. Return Value:
  1198. TRUE if the requested disk is in the drive. FALSE otherwise.
  1199. FALSE can only be returned if AllowEscape is TRUE.
  1200. --*/
  1201. {
  1202. WCHAR OpenPath[MAX_PATH];
  1203. NTSTATUS Status;
  1204. UNICODE_STRING UnicodeString;
  1205. OBJECT_ATTRIBUTES ObjectAttributes;
  1206. IO_STATUS_BLOCK IoStatusBlock;
  1207. HANDLE Handle;
  1208. BOOLEAN Done = FALSE;
  1209. BOOLEAN rc;
  1210. WCHAR DriveLetter;
  1211. ULONG PromptId;
  1212. ULONG ValidKeys[4] = { KEY_F3, ASCI_CR, 0, 0 };
  1213. BOOLEAN TryOpen;
  1214. //
  1215. // Initially, assume no redraw required
  1216. //
  1217. if(pRedrawFlag) {
  1218. *pRedrawFlag = FALSE;
  1219. }
  1220. //
  1221. // Need to get device characteristics to see whether
  1222. // the device is a cd, fixed disk or removable disk/floppy.
  1223. //
  1224. SpStringToLower(DiskDevicePath);
  1225. if( !_wcsnicmp(DiskDevicePath,L"\\device\\cdrom",13)) {
  1226. PromptId = SP_SCRN_CDROM_PROMPT;
  1227. WarnMultiplePrompts = FALSE;
  1228. } else if( !_wcsnicmp(DiskDevicePath,L"\\device\\floppy",14)) {
  1229. PromptId = SP_SCRN_FLOPPY_PROMPT;
  1230. DriveLetter = (WCHAR)SpStringToLong(wcsstr(DiskDevicePath,L"floppy")+6,NULL,10) + L'A';
  1231. } else {
  1232. //
  1233. // Assume hard disk
  1234. //
  1235. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPromptforDisk assuming %ws is hard disk, returning TRUE\n",DiskDevicePath));
  1236. return(TRUE);
  1237. }
  1238. //
  1239. // Form the complete NT pathname of the tagfile.
  1240. //
  1241. wcscpy(OpenPath,DiskDevicePath);
  1242. SpConcatenatePaths(OpenPath,DiskTagFile);
  1243. //
  1244. // Initialize object attributes.
  1245. //
  1246. INIT_OBJA(&ObjectAttributes,&UnicodeString,OpenPath);
  1247. //
  1248. // If we're looking for a cdrom0, and there are multiple CDROM
  1249. // drives in the machine, skip prompting the user the first time
  1250. // and look for our tag on all the CD drives first.
  1251. //
  1252. if( (PromptId == SP_SCRN_CDROM_PROMPT) &&
  1253. (IoGetConfigurationInformation()->CdRomCount > 1) &&
  1254. (wcsstr( OpenPath, L"cdrom0" ))) {
  1255. IgnoreDiskInDrive = FALSE;
  1256. }
  1257. do {
  1258. //
  1259. // Put up the prompt.
  1260. //
  1261. TryOpen = TRUE;
  1262. if(IgnoreDiskInDrive) {
  1263. //
  1264. // We going to put up a prompt screen, so a redraw will be required
  1265. //
  1266. if(pRedrawFlag) {
  1267. *pRedrawFlag = TRUE;
  1268. }
  1269. SpStartScreen(PromptId,0,0,TRUE,TRUE,DEFAULT_ATTRIBUTE,DiskDescription,DriveLetter);
  1270. //
  1271. // Display status options: exit, enter, and escape if specified.
  1272. //
  1273. SpDisplayStatusOptions(
  1274. DEFAULT_STATUS_ATTRIBUTE,
  1275. SP_STAT_F3_EQUALS_EXIT,
  1276. SP_STAT_ENTER_EQUALS_CONTINUE,
  1277. AllowEscape ? SP_STAT_ESC_EQUALS_CANCEL : 0,
  1278. 0
  1279. );
  1280. if(AllowEscape) {
  1281. ValidKeys[2] = ASCI_ESC;
  1282. }
  1283. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  1284. case ASCI_ESC:
  1285. rc = FALSE;
  1286. Done = TRUE;
  1287. TryOpen = FALSE;
  1288. break;
  1289. case KEY_F3:
  1290. TryOpen = FALSE;
  1291. SpConfirmExit();
  1292. break;
  1293. case ASCI_CR:
  1294. break;
  1295. }
  1296. }
  1297. //
  1298. // Attempt to open the tagfile.
  1299. //
  1300. if(TryOpen) {
  1301. //
  1302. // If this function was called during repair, do not clear the scree.
  1303. // This condition is necessary so that the screen will not
  1304. // blink when setup is repairing multiple files without asking the
  1305. // user to confirm each file.
  1306. //
  1307. if( !RepairWinnt ) {
  1308. CLEAR_CLIENT_SCREEN();
  1309. }
  1310. SpDisplayStatusText(SP_STAT_PLEASE_WAIT,DEFAULT_STATUS_ATTRIBUTE);
  1311. //
  1312. // If we're looking for a cdrom0, and there are multiple CDROM
  1313. // drives in the machine, check all of them.
  1314. //
  1315. if( (PromptId == SP_SCRN_CDROM_PROMPT) &&
  1316. (IoGetConfigurationInformation()->CdRomCount > 1) &&
  1317. (wcsstr( OpenPath, L"cdrom0" ))) {
  1318. WCHAR CdRomDevicePath[MAX_PATH];
  1319. ULONG i;
  1320. //
  1321. // We're looking for a CD. We've assumed we're looking for
  1322. // Cdrom0, but there are more than one on the system.
  1323. //
  1324. for( i = 0; i < IoGetConfigurationInformation()->CdRomCount; i++ ) {
  1325. //
  1326. // Modify our path, taking into account our new device. Let's
  1327. // leave OpenPath alone. Just in case we fail, we won't have to
  1328. // re-initialize him.
  1329. //
  1330. swprintf(CdRomDevicePath, L"\\device\\cdrom%u", i);
  1331. if(DiskTagFile)
  1332. SpConcatenatePaths(CdRomDevicePath, DiskTagFile);
  1333. //
  1334. // Initialize object attributes.
  1335. //
  1336. INIT_OBJA(&ObjectAttributes,&UnicodeString,CdRomDevicePath);
  1337. Status = ZwCreateFile(
  1338. &Handle,
  1339. FILE_GENERIC_READ,
  1340. &ObjectAttributes,
  1341. &IoStatusBlock,
  1342. NULL,
  1343. FILE_ATTRIBUTE_NORMAL,
  1344. FILE_SHARE_READ,
  1345. FILE_OPEN,
  1346. 0,
  1347. NULL,
  1348. 0
  1349. );
  1350. if(NT_SUCCESS(Status)) {
  1351. if( i > 0 ) {
  1352. //
  1353. // We found the tagfile on a different device than
  1354. // than where we were supposed to look. Modify the
  1355. // DiskDevicePath.
  1356. //
  1357. swprintf(DiskDevicePath, L"\\device\\cdrom%u", i);
  1358. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP:SpPromptForDisk: %ws has the requested %ws file.\n",
  1359. DiskDevicePath, DiskTagFile));
  1360. }
  1361. ZwClose(Handle);
  1362. return( TRUE );
  1363. }
  1364. }
  1365. //
  1366. // If we missed, we can fall through without any harm and use
  1367. // the prompt/error code below. But first, cover our tracks.
  1368. //
  1369. INIT_OBJA(&ObjectAttributes, &UnicodeString, OpenPath);
  1370. }
  1371. Status = ZwCreateFile(
  1372. &Handle,
  1373. FILE_GENERIC_READ,
  1374. &ObjectAttributes,
  1375. &IoStatusBlock,
  1376. NULL,
  1377. FILE_ATTRIBUTE_NORMAL,
  1378. FILE_SHARE_READ,
  1379. FILE_OPEN,
  1380. 0,
  1381. NULL,
  1382. 0
  1383. );
  1384. //
  1385. // If we got back success, then we're done.
  1386. //
  1387. if(NT_SUCCESS(Status)) {
  1388. ZwClose(Handle);
  1389. Done = TRUE;
  1390. rc = TRUE;
  1391. } else {
  1392. //
  1393. // Handle CD-ROM error code indicating that there is no media
  1394. // in the drive.
  1395. //
  1396. if((Status == STATUS_DEVICE_NOT_READY) && (PromptId == SP_SCRN_CDROM_PROMPT)) {
  1397. Status = STATUS_NO_MEDIA_IN_DEVICE;
  1398. }
  1399. //
  1400. // If we got back something other than file not found, path not found,
  1401. // or no media in drive, tell the user that the disk may be damaged.
  1402. //
  1403. if((Status != STATUS_NO_MEDIA_IN_DEVICE)
  1404. && (Status != STATUS_OBJECT_NAME_NOT_FOUND)
  1405. && (Status != STATUS_OBJECT_PATH_NOT_FOUND)
  1406. && (Status != STATUS_NO_SUCH_FILE))
  1407. {
  1408. SpDisplayScreen(SP_SCRN_DISK_DAMAGED,3,HEADER_HEIGHT+1);
  1409. SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE);
  1410. SpInputDrain();
  1411. while(SpInputGetKeypress() != ASCI_CR) ;
  1412. }
  1413. }
  1414. }
  1415. //
  1416. // Set this value to true to force us to put up the prompt.
  1417. //
  1418. IgnoreDiskInDrive = TRUE;
  1419. } while(!Done);
  1420. return(rc);
  1421. }
  1422. VOID
  1423. SpGetSourceMediaInfo(
  1424. IN PVOID SifHandle,
  1425. IN PWSTR MediaShortName,
  1426. OUT PWSTR *Description, OPTIONAL
  1427. OUT PWSTR *Tagfile, OPTIONAL
  1428. OUT PWSTR *Directory OPTIONAL
  1429. )
  1430. {
  1431. PWSTR description,tagfile,directory;
  1432. PWSTR SectionName;
  1433. //
  1434. // Look in the platform-specific section first.
  1435. //
  1436. SectionName = SpMakePlatformSpecificSectionName(SIF_SETUPMEDIA);
  1437. if(SectionName && !SpGetSectionKeyExists(SifHandle,SectionName,MediaShortName)) {
  1438. SpMemFree(SectionName);
  1439. SectionName = SIF_SETUPMEDIA;
  1440. }
  1441. if(Description) {
  1442. description = SpGetSectionKeyIndex(
  1443. SifHandle,
  1444. SectionName,
  1445. MediaShortName,
  1446. 0
  1447. );
  1448. if(description) {
  1449. *Description = description;
  1450. } else {
  1451. SpFatalSifError(SifHandle,SectionName,MediaShortName,0,0);
  1452. }
  1453. }
  1454. if(Tagfile) {
  1455. tagfile = SpGetSectionKeyIndex(
  1456. SifHandle,
  1457. SectionName,
  1458. MediaShortName,
  1459. 1
  1460. );
  1461. if(tagfile) {
  1462. *Tagfile = tagfile;
  1463. } else {
  1464. SpFatalSifError(SifHandle,SectionName,MediaShortName,0,1);
  1465. }
  1466. }
  1467. if(Directory) {
  1468. if (NoLs && !_wcsicmp (MediaShortName, L"1")) {
  1469. directory = L"";
  1470. }
  1471. else {
  1472. directory = SpGetSectionKeyIndex(
  1473. SifHandle,
  1474. SectionName,
  1475. MediaShortName,
  1476. 3
  1477. );
  1478. }
  1479. if(directory) {
  1480. *Directory = directory;
  1481. } else {
  1482. SpFatalSifError(SifHandle,SectionName,MediaShortName,0,3);
  1483. }
  1484. }
  1485. if(SectionName != SIF_SETUPMEDIA) {
  1486. SpMemFree(SectionName);
  1487. }
  1488. }
  1489. BOOLEAN
  1490. SpPromptForSetupMedia(
  1491. IN PVOID SifHandle,
  1492. IN PWSTR MediaShortname,
  1493. IN PWSTR DiskDevicePath
  1494. )
  1495. {
  1496. PWSTR Tagfile,Description;
  1497. BOOLEAN RedrawNeeded;
  1498. SpGetSourceMediaInfo(SifHandle,MediaShortname,&Description,&Tagfile,NULL);
  1499. //
  1500. // Prompt for the disk, based on the setup media type.
  1501. //
  1502. SpPromptForDisk(
  1503. Description,
  1504. DiskDevicePath,
  1505. Tagfile,
  1506. FALSE, // don't ignore disk in drive
  1507. FALSE, // don't allow escape
  1508. TRUE, // warn about multiple prompts for same disk
  1509. &RedrawNeeded
  1510. );
  1511. return(RedrawNeeded);
  1512. }
  1513. ULONG
  1514. SpFindStringInTable(
  1515. IN PWSTR *StringTable,
  1516. IN PWSTR StringToFind
  1517. )
  1518. {
  1519. ULONG i;
  1520. for(i=0; StringTable[i]; i++) {
  1521. if(!_wcsicmp(StringTable[i],StringToFind)) {
  1522. break;
  1523. }
  1524. }
  1525. return(i);
  1526. }
  1527. PWSTR
  1528. SpGenerateCompressedName(
  1529. IN PWSTR Filename
  1530. )
  1531. /*++
  1532. Routine Description:
  1533. Given a filename, generate the compressed form of the name.
  1534. The compressed form is generated as follows:
  1535. Look backwards for a dot. If there is no dot, append "._" to the name.
  1536. If there is a dot followed by 0, 1, or 2 charcaters, append "_".
  1537. Otherwise assume there is a 3-character extension and replace the
  1538. third character after the dot with "_".
  1539. Arguments:
  1540. Filename - supplies filename whose compressed form is desired.
  1541. Return Value:
  1542. Pointer to buffer containing nul-terminated compressed-form filename.
  1543. The caller must free this buffer via SpFree().
  1544. --*/
  1545. {
  1546. PWSTR CompressedName,p,q;
  1547. //
  1548. // The maximum length of the compressed filename is the length of the
  1549. // original name plus 2 (for ._).
  1550. //
  1551. CompressedName = SpMemAlloc((wcslen(Filename)+3)*sizeof(WCHAR));
  1552. wcscpy(CompressedName,Filename);
  1553. p = wcsrchr(CompressedName,L'.');
  1554. q = wcsrchr(CompressedName,L'\\');
  1555. if(q < p) {
  1556. //
  1557. // If there are 0, 1, or 2 characters after the dot, just append
  1558. // the underscore. p points to the dot so include that in the length.
  1559. //
  1560. if(wcslen(p) < 4) {
  1561. wcscat(CompressedName,L"_");
  1562. } else {
  1563. //
  1564. // Assume there are 3 characters in the extension. So replace
  1565. // the final one with an underscore.
  1566. //
  1567. p[3] = L'_';
  1568. }
  1569. } else {
  1570. //
  1571. // No dot, just add ._.
  1572. //
  1573. wcscat(CompressedName,L"._");
  1574. }
  1575. return(CompressedName);
  1576. }
  1577. BOOLEAN
  1578. SpNonCriticalError(
  1579. IN PVOID SifHandle,
  1580. IN ULONG MsgId,
  1581. IN PWSTR p1, OPTIONAL
  1582. IN PWSTR p2 OPTIONAL
  1583. )
  1584. /*++
  1585. Routine Description:
  1586. This routine lets Setup display a non critical error to the user
  1587. and ask the user whether he wants to retry the operation, skip the
  1588. operation or exit Setup.
  1589. Arguments:
  1590. SifHandle - supplies handle to loaded setup information file.
  1591. MsgId - message to display
  1592. p1 - optional replacement string
  1593. p2 - optional replacement string
  1594. Return Value:
  1595. TRUE if user wants to retry the operation, FALSE otherwise. Exit
  1596. Setup won't return from this routine
  1597. --*/
  1598. {
  1599. ULONG ValidKeys[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 };
  1600. CLEAR_CLIENT_SCREEN();
  1601. while(1) {
  1602. if(p1!=NULL && p2!=NULL ) {
  1603. SpStartScreen(
  1604. MsgId,
  1605. 3,
  1606. HEADER_HEIGHT+1,
  1607. FALSE,
  1608. FALSE,
  1609. DEFAULT_ATTRIBUTE,
  1610. p1,
  1611. p2
  1612. );
  1613. }
  1614. else if (p1!=NULL) {
  1615. SpStartScreen(
  1616. MsgId,
  1617. 3,
  1618. HEADER_HEIGHT+1,
  1619. FALSE,
  1620. FALSE,
  1621. DEFAULT_ATTRIBUTE,
  1622. p1
  1623. );
  1624. }
  1625. else{
  1626. SpStartScreen(
  1627. MsgId,
  1628. 3,
  1629. HEADER_HEIGHT+1,
  1630. FALSE,
  1631. FALSE,
  1632. DEFAULT_ATTRIBUTE
  1633. );
  1634. }
  1635. SpDisplayStatusOptions(
  1636. DEFAULT_STATUS_ATTRIBUTE,
  1637. SP_STAT_ENTER_EQUALS_RETRY,
  1638. SP_STAT_ESC_EQUALS_SKIP_OPERATION,
  1639. SP_STAT_F3_EQUALS_EXIT,
  1640. 0
  1641. );
  1642. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  1643. case ASCI_CR: // retry
  1644. return(TRUE);
  1645. case ASCI_ESC: // skip operation
  1646. return(FALSE);
  1647. case KEY_F3: // exit setup
  1648. SpConfirmExit();
  1649. break;
  1650. }
  1651. }
  1652. }
  1653. BOOLEAN
  1654. SpNonCriticalErrorWithContinue (
  1655. IN ULONG MsgId,
  1656. IN PWSTR p1, OPTIONAL
  1657. IN PWSTR p2 OPTIONAL
  1658. )
  1659. /*++
  1660. Routine Description:
  1661. This routine lets Setup display a non critical error to the user and ask
  1662. the user whether he wants to ignore the failure, skip the operation or
  1663. exit Setup.
  1664. Arguments:
  1665. MsgId - message to display
  1666. p1 - optional replacement string
  1667. p2 - optional replacement string
  1668. Return Value:
  1669. TRUE if user wants to ignore the failure, FALSE otherwise. Exit
  1670. Setup won't return from this routine
  1671. --*/
  1672. {
  1673. ULONG ValidKeys[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 };
  1674. CLEAR_CLIENT_SCREEN();
  1675. while(1) {
  1676. if(p1!=NULL && p2!=NULL ) {
  1677. SpStartScreen(
  1678. MsgId,
  1679. 3,
  1680. HEADER_HEIGHT+1,
  1681. FALSE,
  1682. FALSE,
  1683. DEFAULT_ATTRIBUTE,
  1684. p1,
  1685. p2
  1686. );
  1687. }
  1688. else if (p1!=NULL) {
  1689. SpStartScreen(
  1690. MsgId,
  1691. 3,
  1692. HEADER_HEIGHT+1,
  1693. FALSE,
  1694. FALSE,
  1695. DEFAULT_ATTRIBUTE,
  1696. p1
  1697. );
  1698. }
  1699. else{
  1700. SpStartScreen(
  1701. MsgId,
  1702. 3,
  1703. HEADER_HEIGHT+1,
  1704. FALSE,
  1705. FALSE,
  1706. DEFAULT_ATTRIBUTE
  1707. );
  1708. }
  1709. SpDisplayStatusOptions(
  1710. DEFAULT_STATUS_ATTRIBUTE,
  1711. SP_STAT_ENTER_EQUALS_CONTINUE,
  1712. SP_STAT_ESC_EQUALS_SKIP_OPERATION,
  1713. SP_STAT_F3_EQUALS_EXIT,
  1714. 0
  1715. );
  1716. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  1717. case ASCI_CR: // ignore failure
  1718. return(TRUE);
  1719. case ASCI_ESC: // skip operation
  1720. return(FALSE);
  1721. case KEY_F3: // exit setup
  1722. SpConfirmExit();
  1723. break;
  1724. }
  1725. }
  1726. }
  1727. VOID
  1728. SpNonCriticalErrorNoRetry (
  1729. IN ULONG MsgId,
  1730. IN PWSTR p1, OPTIONAL
  1731. IN PWSTR p2 OPTIONAL
  1732. )
  1733. /*++
  1734. Routine Description:
  1735. This routine lets Setup display a non critical error to the user and ask
  1736. the user whether he wants to continue exit Setup.
  1737. Arguments:
  1738. MsgId - message to display
  1739. p1 - optional replacement string
  1740. p2 - optional replacement string
  1741. Return Value:
  1742. None.
  1743. --*/
  1744. {
  1745. ULONG ValidKeys[3] = { ASCI_CR, KEY_F3, 0 };
  1746. CLEAR_CLIENT_SCREEN();
  1747. while(1) {
  1748. if(p1!=NULL && p2!=NULL ) {
  1749. SpStartScreen(
  1750. MsgId,
  1751. 3,
  1752. HEADER_HEIGHT+1,
  1753. FALSE,
  1754. FALSE,
  1755. DEFAULT_ATTRIBUTE,
  1756. p1,
  1757. p2
  1758. );
  1759. }
  1760. else if (p1!=NULL) {
  1761. SpStartScreen(
  1762. MsgId,
  1763. 3,
  1764. HEADER_HEIGHT+1,
  1765. FALSE,
  1766. FALSE,
  1767. DEFAULT_ATTRIBUTE,
  1768. p1
  1769. );
  1770. }
  1771. else{
  1772. SpStartScreen(
  1773. MsgId,
  1774. 3,
  1775. HEADER_HEIGHT+1,
  1776. FALSE,
  1777. FALSE,
  1778. DEFAULT_ATTRIBUTE
  1779. );
  1780. }
  1781. SpDisplayStatusOptions(
  1782. DEFAULT_STATUS_ATTRIBUTE,
  1783. SP_STAT_ENTER_EQUALS_CONTINUE,
  1784. SP_STAT_F3_EQUALS_EXIT,
  1785. 0
  1786. );
  1787. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  1788. case ASCI_CR: // continue
  1789. return;
  1790. case KEY_F3: // exit setup
  1791. SpConfirmExit();
  1792. break;
  1793. }
  1794. }
  1795. }
  1796. PWSTR
  1797. SpDetermineSystemPartitionDirectory(
  1798. IN PDISK_REGION SystemPartitionRegion,
  1799. IN PWSTR OriginalSystemPartitionDirectory OPTIONAL
  1800. )
  1801. /*++
  1802. Routine Description:
  1803. This routine figures out what directory to use for the hal and
  1804. osloader on the system partition. In the past we just used \os\nt
  1805. but consider the case where there is a Windows NT 3.1 installation
  1806. and a Windows NT 3.5 system sharing a system partition. The 3.5
  1807. installation overwrites the 3.1 hal with a 3.5 one, which won't work
  1808. with 3.1, and the 3.1 system is now hosed.
  1809. For now, we will use the existing directory (in the case of an upgrade),
  1810. or \os\winnt50.n (where 'n' is a unique digit from 0 to 999) for a
  1811. fresh install.
  1812. Arguments:
  1813. SystemPartitionRegion - supplies the disk region for the system partition
  1814. to be used for the windows nt we are installing.
  1815. OriginalSystemPartitionDirectory - if we are upgrading nt, then this
  1816. will be the directory on the system partition that is used by
  1817. the system we are upgrading.
  1818. Return Value:
  1819. Directory to be used on the system partition.
  1820. --*/
  1821. {
  1822. WCHAR ReturnPath[512];
  1823. #if defined(EFI_NVRAM_ENABLED)
  1824. #define OS_DIRECTORY_PREFIX L"\\EFI\\Microsoft\\WINNT50"
  1825. #else
  1826. #define OS_DIRECTORY_PREFIX L"\\OS\\WINNT50"
  1827. #endif
  1828. if(ARGUMENT_PRESENT(OriginalSystemPartitionDirectory)) {
  1829. //
  1830. // Note that we're about to break an install under
  1831. // certain conditions. For example, say the user has
  1832. // two NT4 installs, both sharing the same \os\winnt40
  1833. // directory. Now the user has decided to upgrade one
  1834. // of those. We're about to upgrade the hal, osloader, ...
  1835. // in that winnt40 directory, which will break the
  1836. // users secondary install that's sharing this directory.
  1837. // This should be a rare case though, and this is
  1838. // exactly how we behaved in NT40 and NT3.51.
  1839. //
  1840. wcscpy( ReturnPath, OriginalSystemPartitionDirectory );
  1841. } else {
  1842. //
  1843. // We want to return os\winnt50, but we also want
  1844. // to make sure that whatever directory we select, it's
  1845. // unique (since this is a clean install). Note that
  1846. // this allows the user to have multiple NT installs,
  1847. // with no shared files (which fixes the upgrade problem
  1848. // described above.
  1849. //
  1850. if( !SpGenerateNTPathName( SystemPartitionRegion,
  1851. #if DBG
  1852. OS_DIRECTORY_PREFIX L"C", // C - for Checked
  1853. #else
  1854. OS_DIRECTORY_PREFIX,
  1855. #endif
  1856. ReturnPath ) ) {
  1857. //
  1858. // Odd... Just default to using
  1859. // the base directory name.
  1860. //
  1861. wcscpy( ReturnPath,
  1862. #if DBG
  1863. OS_DIRECTORY_PREFIX L"C" // C - for Checked
  1864. #else
  1865. OS_DIRECTORY_PREFIX
  1866. #endif
  1867. );
  1868. }
  1869. }
  1870. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpDetermineSystemPartitionDirectory - Generated directory name: %ws\n", ReturnPath ));
  1871. return SpDupStringW( ReturnPath );
  1872. }
  1873. VOID
  1874. SpFindSizeOfFilesInOsWinnt(
  1875. IN PVOID MasterSifHandle,
  1876. IN PDISK_REGION SystemPartition,
  1877. IN PULONG TotalSize
  1878. )
  1879. /*++
  1880. Routine Description:
  1881. This routine computes the size of of the files present on os\winnt.
  1882. Currently these files are osloader.exe and hal.dll.
  1883. The size computed by this function can be used to adjust the total
  1884. required free space on the system partition.
  1885. Arguments:
  1886. Region - supplies the disk region for the system partition.
  1887. TotalSize - Variable that will contain the total size of the files
  1888. in os\winnt, in number of bytes.
  1889. Return Value:
  1890. None.
  1891. --*/
  1892. {
  1893. ULONG FileSize;
  1894. ULONG i, Count;
  1895. PWSTR FileName;
  1896. NTSTATUS Status;
  1897. PWSTR SystemPartitionDirectory;
  1898. PWSTR SystemPartitionDevice;
  1899. *TotalSize = 0;
  1900. SystemPartitionDirectory = SpDetermineSystemPartitionDirectory( SystemPartition,
  1901. NULL );
  1902. if( SystemPartitionDirectory == NULL ) {
  1903. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to determine system partition directory \n"));
  1904. return;
  1905. }
  1906. //
  1907. // Get the device path of the system partition.
  1908. //
  1909. SpNtNameFromRegion(
  1910. SystemPartition,
  1911. TemporaryBuffer,
  1912. sizeof(TemporaryBuffer),
  1913. PartitionOrdinalCurrent
  1914. );
  1915. SystemPartitionDevice = SpDupStringW(TemporaryBuffer);
  1916. //
  1917. // Compute the size of the files that are always copied to the system
  1918. // partition directory. These files are listed on SIF_SYSPARTCOPYALWAYS
  1919. //
  1920. Count = SpCountLinesInSection(MasterSifHandle, SIF_SYSPARTCOPYALWAYS);
  1921. for (i = 0; i < Count; i++) {
  1922. FileName = SpGetSectionLineIndex(MasterSifHandle,SIF_SYSPARTCOPYALWAYS,i,0);
  1923. if( FileName == NULL ) {
  1924. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to get file name from txtsetup.sif, Section = %ls \n", SIF_SYSPARTCOPYALWAYS ));
  1925. continue;
  1926. }
  1927. Status = SpGetFileSizeByName( SystemPartitionDevice,
  1928. SystemPartitionDirectory,
  1929. FileName,
  1930. &FileSize );
  1931. if( !NT_SUCCESS( Status ) ) {
  1932. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpGetFileSizeByName() failed. File = %ls, Status = %x\n",FileName, Status ) );
  1933. continue;
  1934. }
  1935. *TotalSize += FileSize;
  1936. }
  1937. //
  1938. // Now compute the size of hal.dll
  1939. //
  1940. FileName = L"hal.dll";
  1941. Status = SpGetFileSizeByName( SystemPartitionDevice,
  1942. SystemPartitionDirectory,
  1943. FileName,
  1944. &FileSize );
  1945. if( !NT_SUCCESS( Status ) ) {
  1946. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: SpGetFileSizeByName() failed. File = %ls, Status = %x\n",FileName, Status ) );
  1947. return;
  1948. }
  1949. *TotalSize += FileSize;
  1950. }
  1951. ENUMFILESRESULT
  1952. SpEnumFiles(
  1953. IN PCWSTR DirName,
  1954. IN ENUMFILESPROC EnumFilesProc,
  1955. OUT PULONG ReturnData,
  1956. IN PVOID p1 OPTIONAL
  1957. )
  1958. /*++
  1959. Routine Description:
  1960. This routine processes every file (and subdirectory) in the directory
  1961. specified by 'DirName'. Each entry is sent to the callback function
  1962. 'EnumFilesProc' for processing. If the callback returns TRUE, processing
  1963. continues, otherwise processing terminates.
  1964. Arguments:
  1965. DirName - Supplies the directory name containing the files/subdirectories
  1966. to be processed.
  1967. EnumFilesProc - Callback function to be called for each file/subdirectory.
  1968. The function must have the following prototype:
  1969. BOOLEAN EnumFilesProc(
  1970. IN PWSTR,
  1971. IN PFILE_BOTH_DIR_INFORMATION,
  1972. OUT PULONG
  1973. );
  1974. ReturnData - Pointer to the returned data. The contents stored here
  1975. depend on the reason for termination (See below).
  1976. p1 - Optional pointer, to be passed to the callback function.
  1977. Return Value:
  1978. This function can return one of three values. The data stored in
  1979. 'ReturnData' depends upon which value is returned:
  1980. NormalReturn - if the whole process completes uninterrupted
  1981. (ReturnData is not used)
  1982. EnumFileError - if an error occurs while enumerating files
  1983. (ReturnData contains the error code)
  1984. CallbackReturn - if the callback returns FALSE, causing termination
  1985. (ReturnData contains data defined by the callback)
  1986. --*/
  1987. {
  1988. HANDLE hFindFile;
  1989. NTSTATUS Status;
  1990. UNICODE_STRING PathName;
  1991. OBJECT_ATTRIBUTES Obja;
  1992. IO_STATUS_BLOCK IoStatusBlock;
  1993. PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
  1994. BOOLEAN bStartScan;
  1995. ENUMFILESRESULT ret;
  1996. //
  1997. // Prepare to open the directory
  1998. //
  1999. INIT_OBJA(&Obja, &PathName, DirName);
  2000. //
  2001. // Open the specified directory for list access
  2002. //
  2003. Status = ZwOpenFile(
  2004. &hFindFile,
  2005. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  2006. &Obja,
  2007. &IoStatusBlock,
  2008. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2009. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
  2010. );
  2011. if(!NT_SUCCESS(Status)) {
  2012. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  2013. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open directory %ws for list (%lx)\n", DirName, Status));
  2014. }
  2015. *ReturnData = Status;
  2016. return EnumFileError;
  2017. }
  2018. DirectoryInfo = SpMemAlloc(ACTUAL_MAX_PATH * sizeof(WCHAR) + sizeof(FILE_BOTH_DIR_INFORMATION));
  2019. if(!DirectoryInfo) {
  2020. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Unable to allocate memory for SpEnumFiles()\n"));
  2021. *ReturnData = STATUS_NO_MEMORY;
  2022. return EnumFileError;
  2023. }
  2024. bStartScan = TRUE;
  2025. while(TRUE) {
  2026. Status = ZwQueryDirectoryFile(
  2027. hFindFile,
  2028. NULL,
  2029. NULL,
  2030. NULL,
  2031. &IoStatusBlock,
  2032. DirectoryInfo,
  2033. (ACTUAL_MAX_PATH * sizeof(WCHAR) + sizeof(FILE_BOTH_DIR_INFORMATION)),
  2034. FileBothDirectoryInformation,
  2035. TRUE,
  2036. NULL,
  2037. bStartScan
  2038. );
  2039. if(Status == STATUS_NO_MORE_FILES) {
  2040. ret = NormalReturn;
  2041. break;
  2042. } else if(!NT_SUCCESS(Status)) {
  2043. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_WARNING_LEVEL, "SETUP: Unable to query directory %ws (%lx)\n", DirName, Status));
  2044. *ReturnData = Status;
  2045. ret = EnumFileError;
  2046. break;
  2047. }
  2048. if(bStartScan) {
  2049. bStartScan = FALSE;
  2050. }
  2051. //
  2052. // Now pass this entry off to our callback function for processing
  2053. //
  2054. if(!EnumFilesProc(DirName, DirectoryInfo, ReturnData, p1)) {
  2055. ret = CallbackReturn;
  2056. break;
  2057. }
  2058. }
  2059. SpMemFree(DirectoryInfo);
  2060. ZwClose(hFindFile);
  2061. return ret;
  2062. }
  2063. /*typedef struct {
  2064. PVOID OptionalPtr;
  2065. ENUMFILESPROC EnumProc;
  2066. } RECURSION_DATA, *PRECURSION_DATA;
  2067. BOOLEAN
  2068. SppRecursiveEnumProc (
  2069. IN PCWSTR DirName,
  2070. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  2071. OUT PULONG ret,
  2072. IN PVOID Param
  2073. )
  2074. {
  2075. PWSTR FullPath;
  2076. PWSTR temp;
  2077. ULONG Len;
  2078. NTSTATUS Status;
  2079. ULONG ReturnData;
  2080. ENUMFILESRESULT EnumResult;
  2081. BOOLEAN b = FALSE;
  2082. PRECURSION_DATA RecursionData;
  2083. RecursionData = (PRECURSION_DATA) Param;
  2084. //
  2085. // Build the full file or dir path
  2086. //
  2087. temp = TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2);
  2088. Len = FileInfo->FileNameLength/sizeof(WCHAR);
  2089. wcsncpy(temp,FileInfo->FileName,Len);
  2090. temp[Len] = 0;
  2091. wcscpy(TemporaryBuffer,DirName);
  2092. SpConcatenatePaths(TemporaryBuffer,temp);
  2093. FullPath = SpDupStringW(TemporaryBuffer);
  2094. //
  2095. // For directories, recurse
  2096. //
  2097. if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  2098. if( (wcscmp( temp, L"." ) == 0) ||
  2099. (wcscmp( temp, L".." ) == 0) ) {
  2100. //
  2101. // Skip past . and .. directories
  2102. //
  2103. b = TRUE;
  2104. } else {
  2105. //
  2106. // Recurse through subdirectory
  2107. //
  2108. EnumResult = SpEnumFilesRecursive (
  2109. FullPath,
  2110. RecursionData->EnumProc,
  2111. &ReturnData,
  2112. RecursionData->OptionalPtr
  2113. );
  2114. if (EnumResult != NormalReturn) {
  2115. *ret = EnumResult;
  2116. return FALSE;
  2117. }
  2118. }
  2119. }
  2120. //
  2121. // Call normal enum proc for file or dir (except . or .. dirs)
  2122. //
  2123. if (!b) {
  2124. b = RecursionData->EnumProc (
  2125. DirName,
  2126. FileInfo,
  2127. ret,
  2128. RecursionData->OptionalPtr
  2129. );
  2130. }
  2131. SpMemFree (FullPath);
  2132. return b;
  2133. }*/
  2134. /*BOOLEAN
  2135. SppRecursiveEnumProcDel (
  2136. IN PCWSTR DirName,
  2137. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  2138. OUT PULONG ret,
  2139. IN PVOID Param
  2140. )
  2141. {*/
  2142. /*
  2143. This function is the same as above except that it checks for reparse points. The reason
  2144. we have 2 seperate functions rather than one function and an extra parameter is so that
  2145. we don't have the Reparse point check overhead for other recursive processing like copying
  2146. file. Given the no. of files this could be overhead. Also this way we don't hack the
  2147. recursive directory search algo as well as reduce stack overhead in a recursive operation.
  2148. */
  2149. /*
  2150. HANDLE hFixed;
  2151. NTSTATUS Status;
  2152. UNICODE_STRING PathName;
  2153. OBJECT_ATTRIBUTES Obja;
  2154. IO_STATUS_BLOCK IoStatusBlock;
  2155. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  2156. PWSTR FullPath;
  2157. PWSTR temp;
  2158. ULONG Len;
  2159. ULONG ReturnData;
  2160. ENUMFILESRESULT EnumResult;
  2161. BOOLEAN b = FALSE;
  2162. BOOLEAN IsLink = FALSE;
  2163. PRECURSION_DATA RecursionData;
  2164. RecursionData = (PRECURSION_DATA) Param;
  2165. //
  2166. // Build the full file or dir path
  2167. //
  2168. temp = TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2);
  2169. Len = FileInfo->FileNameLength/sizeof(WCHAR);
  2170. wcsncpy(temp,FileInfo->FileName,Len);
  2171. temp[Len] = 0;
  2172. wcscpy(TemporaryBuffer,DirName);
  2173. SpConcatenatePaths(TemporaryBuffer,temp);
  2174. FullPath = SpDupStringW(TemporaryBuffer);
  2175. //
  2176. // For directories, recurse
  2177. //
  2178. if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  2179. if( (wcscmp( temp, L"." ) == 0) ||
  2180. (wcscmp( temp, L".." ) == 0) ) {
  2181. //
  2182. // Skip past . and .. directories
  2183. //
  2184. b = TRUE;
  2185. } else {
  2186. //
  2187. // Recurse through subdirectory
  2188. //
  2189. //
  2190. // Look for mount point and delete right away to avoid cycle complications
  2191. //
  2192. if( FileInfo->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  2193. IsLink = TRUE;
  2194. if( !IsLink ){
  2195. EnumResult = SpEnumFilesRecursiveDel (
  2196. FullPath,
  2197. RecursionData->EnumProc,
  2198. &ReturnData,
  2199. RecursionData->OptionalPtr
  2200. );
  2201. if (EnumResult != NormalReturn) {
  2202. *ret = EnumResult;
  2203. return FALSE;
  2204. }
  2205. }
  2206. }
  2207. }
  2208. //
  2209. // Call normal enum proc for file or dir (except . or .. dirs)
  2210. //
  2211. if (!b) {
  2212. b = RecursionData->EnumProc (
  2213. DirName,
  2214. FileInfo,
  2215. ret,
  2216. RecursionData->OptionalPtr
  2217. );
  2218. }
  2219. SpMemFree (FullPath);
  2220. return b;
  2221. }*/
  2222. #define LONGEST_NT_PATH_LENGTH 512 // RtlGetLongestNtPathLength always return just 277(MAX_PATH+UNC_PREFIX_LENGTH)
  2223. // longest NT path is 32000 character.
  2224. #define MAX_DEPTH -1
  2225. typedef struct
  2226. {
  2227. HANDLE hHandle;
  2228. int Index;
  2229. PFILE_BOTH_DIR_INFORMATION FileInfo;
  2230. }ENUM_LEVEL, *PENUM_LEVEL;
  2231. BOOLEAN
  2232. SpEnumFilesInline(
  2233. IN PCWSTR pPath,
  2234. IN ENUMFILESPROC EnumFilesProc,
  2235. OUT PULONG ReturnData,
  2236. IN PVOID p1 OPTIONAL,
  2237. IN BOOLEAN bExcludeRepasePointDirs OPTIONAL,
  2238. IN LONG DirectoriesMaxDepth,
  2239. IN BOOLEAN bEnumerateDirFirst OPTIONAL
  2240. )
  2241. {
  2242. PENUM_LEVEL level = NULL;
  2243. int MaxLevelNumber = 0;
  2244. UNICODE_STRING UnicodeString;
  2245. OBJECT_ATTRIBUTES ObjectAttributes;
  2246. IO_STATUS_BLOCK IoStatusBlock;
  2247. PFILE_BOTH_DIR_INFORMATION FileInfo = NULL;
  2248. int SizeOfFileInfo;
  2249. NTSTATUS Status;
  2250. PWSTR Path = NULL;
  2251. PWSTR SubDir = NULL;
  2252. int index;
  2253. int i;
  2254. BOOLEAN FirstQuery;
  2255. ENUMFILESRESULT enumResult = NormalReturn;
  2256. if(!pPath || wcslen(pPath) >= LONGEST_NT_PATH_LENGTH){
  2257. return EnumFileError;
  2258. }
  2259. __try{
  2260. Path = (PWSTR)SpMemAlloc(LONGEST_NT_PATH_LENGTH * sizeof(WCHAR));
  2261. if(!Path){
  2262. if(ReturnData){
  2263. *ReturnData = STATUS_NO_MEMORY;
  2264. }
  2265. enumResult = EnumFileError;
  2266. __leave;
  2267. }
  2268. SubDir = (PWSTR)SpMemAlloc(LONGEST_NT_PATH_LENGTH * sizeof(WCHAR));
  2269. if(!SubDir){
  2270. if(ReturnData){
  2271. *ReturnData = STATUS_NO_MEMORY;
  2272. }
  2273. enumResult = EnumFileError;
  2274. __leave;
  2275. }
  2276. SizeOfFileInfo = LONGEST_NT_PATH_LENGTH * sizeof(WCHAR) + sizeof(FILE_BOTH_DIR_INFORMATION);
  2277. FileInfo = (PFILE_BOTH_DIR_INFORMATION)SpMemAlloc(SizeOfFileInfo);
  2278. if(!FileInfo){
  2279. if(ReturnData){
  2280. *ReturnData = STATUS_NO_MEMORY;
  2281. }
  2282. enumResult = EnumFileError;
  2283. __leave;
  2284. }
  2285. MaxLevelNumber = LONGEST_NT_PATH_LENGTH / 2;
  2286. level = (PENUM_LEVEL)SpMemAlloc(sizeof(level[0]) * MaxLevelNumber);
  2287. if(!level){
  2288. if(ReturnData){
  2289. *ReturnData = STATUS_NO_MEMORY;
  2290. }
  2291. enumResult = EnumFileError;
  2292. __leave;
  2293. }
  2294. memset(level, 0, sizeof(level[0]) * MaxLevelNumber);
  2295. wcscpy(Path, pPath);
  2296. index = wcslen(Path) - 1;
  2297. if('\\' != Path[index] && '//' != Path[index]){
  2298. Path[index + 1] = '\\';
  2299. Path[index + 2] = '\0';
  2300. }
  2301. for(index = 0; index >= 0;){
  2302. INIT_OBJA(&ObjectAttributes, &UnicodeString, Path);
  2303. level[index].Index = wcslen(Path);
  2304. if(!bEnumerateDirFirst){
  2305. level[index].FileInfo = (PFILE_BOTH_DIR_INFORMATION)SpMemAlloc(SizeOfFileInfo);
  2306. if(!level[index].FileInfo){
  2307. if(ReturnData){
  2308. *ReturnData = STATUS_NO_MEMORY;
  2309. }
  2310. enumResult = EnumFileError;
  2311. __leave;
  2312. }
  2313. }
  2314. Status = ZwOpenFile(&level[index].hHandle,
  2315. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  2316. &ObjectAttributes,
  2317. &IoStatusBlock,
  2318. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2319. FILE_DIRECTORY_FILE |
  2320. FILE_SYNCHRONOUS_IO_NONALERT |
  2321. FILE_OPEN_FOR_BACKUP_INTENT
  2322. );
  2323. if(!NT_SUCCESS(Status)){
  2324. level[index].hHandle = NULL;
  2325. if(ReturnData){
  2326. *ReturnData = Status;
  2327. }
  2328. enumResult = EnumFileError;
  2329. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  2330. KdPrintEx((
  2331. DPFLTR_SETUP_ID,
  2332. DPFLTR_ERROR_LEVEL,
  2333. "SETUP:SpEnumFilesInline, Failed to open %ws folder for list access - status 0x%08X.\n",
  2334. Path,
  2335. Status));
  2336. }
  2337. __leave;//index--;
  2338. }
  2339. else{
  2340. FirstQuery = TRUE;
  2341. }
  2342. for(;;)
  2343. {
  2344. for(; index >= 0; index--){
  2345. Status = ZwQueryDirectoryFile(level[index].hHandle,
  2346. NULL, // no event to signal
  2347. NULL, // no apc routine
  2348. NULL, // no apc context
  2349. &IoStatusBlock,
  2350. FileInfo,
  2351. SizeOfFileInfo - sizeof(WCHAR), // leave room for terminating nul
  2352. FileBothDirectoryInformation,
  2353. TRUE, // want single entry
  2354. NULL, // get 'em all
  2355. FirstQuery);
  2356. FirstQuery = FALSE;
  2357. if(NT_SUCCESS(Status)){
  2358. break;
  2359. }
  2360. else{
  2361. if(STATUS_NO_MORE_FILES != Status){
  2362. if(ReturnData){
  2363. *ReturnData = Status;
  2364. }
  2365. KdPrintEx((
  2366. DPFLTR_SETUP_ID,
  2367. DPFLTR_ERROR_LEVEL,
  2368. "SETUP:SpEnumFilesInline, Failed to query %d level - status 0x%08X.\n",
  2369. index,
  2370. Status));
  2371. enumResult = EnumFileError;
  2372. __leave;
  2373. }
  2374. else{
  2375. if(!bEnumerateDirFirst){
  2376. if(index > 0){
  2377. wcsncpy(SubDir, Path, level[index - 1].Index);
  2378. SubDir[level[index - 1].Index] = '\0';
  2379. if(!EnumFilesProc(SubDir, level[index - 1].FileInfo, ReturnData, p1)){
  2380. enumResult = CallbackReturn;
  2381. KdPrintEx((
  2382. DPFLTR_SETUP_ID,
  2383. DPFLTR_ERROR_LEVEL,
  2384. "SETUP:SpEnumFilesInline, Callback returned FALSE on %ws\\%ws\n",
  2385. SubDir,
  2386. level[index - 1].FileInfo->FileName));
  2387. __leave;
  2388. }
  2389. }
  2390. }
  2391. }
  2392. }
  2393. ZwClose(level[index].hHandle);
  2394. level[index].hHandle = NULL;
  2395. }
  2396. if(index < 0){
  2397. break;
  2398. }
  2399. FileInfo->FileName[FileInfo->FileNameLength / sizeof(WCHAR)] = '\0';
  2400. wcscpy(&Path[level[index].Index], FileInfo->FileName);
  2401. wcsncpy(SubDir, Path, level[index].Index);
  2402. SubDir[level[index].Index] = '\0';
  2403. if(!(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
  2404. if(!EnumFilesProc(SubDir, FileInfo, ReturnData, p1)){
  2405. enumResult = CallbackReturn;
  2406. KdPrintEx((
  2407. DPFLTR_SETUP_ID,
  2408. DPFLTR_ERROR_LEVEL,
  2409. "SETUP:SpEnumFilesInline, Callback returned FALSE on %ws\\%ws\n",
  2410. SubDir,
  2411. FileInfo->FileName));
  2412. __leave;
  2413. }
  2414. }
  2415. else{
  2416. if(wcscmp(FileInfo->FileName, L".") &&
  2417. wcscmp(FileInfo->FileName, L"..")){
  2418. wcscat(Path, L"\\");
  2419. if(bEnumerateDirFirst){
  2420. if(!EnumFilesProc(SubDir, FileInfo, ReturnData, p1)){
  2421. enumResult = CallbackReturn;
  2422. KdPrintEx((
  2423. DPFLTR_SETUP_ID,
  2424. DPFLTR_ERROR_LEVEL,
  2425. "SETUP:SpEnumFilesInline, Callback returned FALSE on %ws\\%ws\n",
  2426. SubDir,
  2427. FileInfo->FileName));
  2428. __leave;
  2429. }
  2430. }
  2431. else{
  2432. ASSERT(level[index].FileInfo);
  2433. memcpy(level[index].FileInfo, FileInfo, SizeOfFileInfo);
  2434. }
  2435. if(DirectoriesMaxDepth >= 0 && index >= DirectoriesMaxDepth){
  2436. continue;
  2437. }
  2438. if(bExcludeRepasePointDirs && FileInfo->FileAttributes&FILE_ATTRIBUTE_REPARSE_POINT){
  2439. continue;
  2440. }
  2441. index++;
  2442. break;
  2443. }
  2444. }
  2445. }
  2446. }
  2447. enumResult = NormalReturn;
  2448. }
  2449. __finally{
  2450. if(level){
  2451. for(i = 0; i < MaxLevelNumber; i++){
  2452. if(level[i].hHandle){
  2453. ZwClose(level[i].hHandle);
  2454. }
  2455. if(level[i].FileInfo){
  2456. SpMemFree(level[i].FileInfo);
  2457. }
  2458. }
  2459. SpMemFree(level);
  2460. }
  2461. if(SubDir){
  2462. SpMemFree(SubDir);
  2463. }
  2464. if(Path){
  2465. SpMemFree(Path);
  2466. }
  2467. if(FileInfo){
  2468. SpMemFree(FileInfo);
  2469. }
  2470. }
  2471. return enumResult;
  2472. }
  2473. ENUMFILESRESULT
  2474. SpEnumFilesRecursive (
  2475. IN PWSTR DirName,
  2476. IN ENUMFILESPROC EnumFilesProc,
  2477. OUT PULONG ReturnData,
  2478. IN PVOID p1 OPTIONAL
  2479. )
  2480. {
  2481. return SpEnumFilesInline(DirName,
  2482. EnumFilesProc,
  2483. ReturnData,
  2484. p1,
  2485. FALSE,
  2486. MAX_DEPTH,
  2487. FALSE);
  2488. /*
  2489. RECURSION_DATA RecursionData;
  2490. RecursionData.OptionalPtr = p1;
  2491. RecursionData.EnumProc = EnumFilesProc;
  2492. return SpEnumFiles (
  2493. DirName,
  2494. SppRecursiveEnumProc,
  2495. ReturnData,
  2496. &RecursionData
  2497. );
  2498. */
  2499. }
  2500. /*typedef struct {
  2501. ULONG MaxDepth;
  2502. ULONG CurrentDepth;
  2503. PVOID OptionalPtr;
  2504. ENUMFILESPROC EnumProc;
  2505. } RECURSION_LIMITED_DATA, *PRECURSION_LIMITED_DATA;
  2506. BOOLEAN
  2507. SppRecursiveLimitedEnumProc (
  2508. IN PCWSTR DirName,
  2509. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  2510. OUT PULONG ret,
  2511. IN PVOID Param
  2512. )*/
  2513. /*++
  2514. Routine Description:
  2515. This routine is the same as SppRecursiveEnumProc with the added feature
  2516. that it supports recursion depth limiting. The recursion context is passed
  2517. in via the Param argument and is of type RECURSION_LIMITED_DATA.
  2518. Arguments:
  2519. DirName - Supplies the directory name containing the current directory of the
  2520. File/Dir currently being enumerated.
  2521. FileInfo - File/Dir info about the current file being enumerated
  2522. ret - Pointer to the returned data. The contents stored here
  2523. depend on the reason for termination:
  2524. NormalReturn - if the whole process completes uninterrupted
  2525. (ReturnData is not used)
  2526. EnumFileError - if an error occurs while enumerating files
  2527. (ReturnData contains the error code)
  2528. CallbackReturn - if the callback returns FALSE, causing termination
  2529. (ReturnData contains data defined by the callback)
  2530. Param - Recursion context
  2531. Return Value:
  2532. TRUE - continue processing
  2533. otherwise, FALSE
  2534. --*/
  2535. /*{
  2536. PWSTR FullPath;
  2537. PWSTR temp;
  2538. ULONG Len;
  2539. NTSTATUS Status;
  2540. ULONG ReturnData;
  2541. ENUMFILESRESULT EnumResult;
  2542. BOOLEAN b = FALSE;
  2543. PRECURSION_LIMITED_DATA RecursionData;
  2544. RecursionData = (PRECURSION_LIMITED_DATA) Param;
  2545. //
  2546. // If we are at our max recursion depth, bail out
  2547. //
  2548. // Note: using >= allows us to look at files at the MaxDepth,
  2549. // but not recurse into directories beyond MaxDepth.
  2550. //
  2551. if (RecursionData->CurrentDepth >= RecursionData->MaxDepth) {
  2552. *ret = NormalReturn;
  2553. return TRUE;
  2554. }
  2555. //
  2556. // Build the full file or dir path
  2557. //
  2558. temp = TemporaryBuffer + (sizeof(TemporaryBuffer) / sizeof(WCHAR) / 2);
  2559. Len = FileInfo->FileNameLength/sizeof(WCHAR);
  2560. wcsncpy(temp,FileInfo->FileName,Len);
  2561. temp[Len] = 0;
  2562. wcscpy(TemporaryBuffer,DirName);
  2563. SpConcatenatePaths(TemporaryBuffer,temp);
  2564. FullPath = SpDupStringW(TemporaryBuffer);
  2565. //
  2566. // if the length of FullPath >= MAX_PATH, then we might
  2567. // have encountered a corrupt region of the file system.
  2568. // Hence, ensure that the length of FullPath is < MAX_PATH-1.
  2569. // (allow for null termination when comparing to MAX_PATH)
  2570. //
  2571. if (wcslen(FullPath) >= MAX_PATH) {
  2572. SpMemFree(FullPath);
  2573. //
  2574. // skip this entry and continue scanning
  2575. //
  2576. // (Since this routine is used by Bootcfg in the recover console,
  2577. // this behavior is helpful because it allows us to continue scanning
  2578. // and perhaps find a valid Windows install - which would then allow
  2579. // us to possibly do more recovery work...)
  2580. //
  2581. *ret = NormalReturn;
  2582. return TRUE;
  2583. }
  2584. //
  2585. // For directories, recurse
  2586. //
  2587. if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  2588. if( (wcscmp( temp, L"." ) == 0) ||
  2589. (wcscmp( temp, L".." ) == 0) ) {
  2590. //
  2591. // Skip past . and .. directories
  2592. //
  2593. b = TRUE;
  2594. } else {
  2595. //
  2596. // Recurse through subdirectory
  2597. //
  2598. RecursionData->CurrentDepth++;
  2599. EnumResult = SpEnumFilesRecursiveLimited (
  2600. FullPath,
  2601. RecursionData->EnumProc,
  2602. RecursionData->MaxDepth,
  2603. RecursionData->CurrentDepth,
  2604. &ReturnData,
  2605. RecursionData->OptionalPtr
  2606. );
  2607. RecursionData->CurrentDepth--;
  2608. if (EnumResult != NormalReturn) {
  2609. *ret = EnumResult;
  2610. return FALSE;
  2611. }
  2612. }
  2613. }
  2614. //
  2615. // Call normal enum proc for file or dir (except . or .. dirs)
  2616. //
  2617. if (!b) {
  2618. b = RecursionData->EnumProc (
  2619. DirName,
  2620. FileInfo,
  2621. ret,
  2622. RecursionData->OptionalPtr
  2623. );
  2624. }
  2625. SpMemFree (FullPath);
  2626. return b;
  2627. }*/
  2628. ENUMFILESRESULT
  2629. SpEnumFilesRecursiveLimited (
  2630. IN PWSTR DirName,
  2631. IN ENUMFILESPROC EnumFilesProc,
  2632. IN ULONG MaxDepth,
  2633. IN ULONG CurrentDepth,
  2634. OUT PULONG ReturnData,
  2635. IN PVOID p1 OPTIONAL
  2636. )
  2637. /*++
  2638. Routine Description:
  2639. This routine processes every file (and subdirectory) in the directory
  2640. specified by 'DirName'. Each entry is sent to the callback function
  2641. 'EnumFilesProc' for processing. If the callback returns TRUE, processing
  2642. continues, otherwise processing terminates.
  2643. This routine employs recursion depth limiting.
  2644. Arguments:
  2645. DirName - Supplies the directory name containing the files/subdirectories
  2646. to be processed.
  2647. EnumFilesProc - Callback function to be called for each file/subdirectory.
  2648. The function must have the following prototype:
  2649. BOOLEAN EnumFilesProc(
  2650. IN PWSTR,
  2651. IN PFILE_BOTH_DIR_INFORMATION,
  2652. OUT PULONG
  2653. );
  2654. MaxDepth - The maximum depth the recursion will be allowed to go.
  2655. Note: During the recursion process, the directories will be
  2656. recursed until CurrentDepth == MaxDepth. Files at
  2657. MaxDepth + 1 will be processed via EnumProc, but any
  2658. directories below MaxDepth will not be visited.
  2659. CurrentDepth - The depth the recursion is currently at.
  2660. Note: When first calling this routine, CurrentDepth should be 0.
  2661. This argument exists because this routine is the core of the
  2662. recursion and is called by SppRecursiveLimitedEnumProc. Each
  2663. time SppRecursiveLimitedEnumProc calls this function, it passes
  2664. the current recursion depth.
  2665. ReturnData - Pointer to the returned data. The contents stored here
  2666. depend on the reason for termination (See below).
  2667. p1 - Optional pointer, to be passed to the callback function.
  2668. Return Value:
  2669. This function can return one of three values. The data stored in
  2670. 'ReturnData' depends upon which value is returned:
  2671. NormalReturn - if the whole process completes uninterrupted
  2672. (ReturnData is not used)
  2673. EnumFileError - if an error occurs while enumerating files
  2674. (ReturnData contains the error code)
  2675. CallbackReturn - if the callback returns FALSE, causing termination
  2676. (ReturnData contains data defined by the callback)
  2677. --*/
  2678. {
  2679. /* RECURSION_LIMITED_DATA RecursionData;
  2680. RecursionData.OptionalPtr = p1;
  2681. RecursionData.EnumProc = EnumFilesProc;
  2682. RecursionData.MaxDepth = MaxDepth;
  2683. RecursionData.CurrentDepth = CurrentDepth;
  2684. return SpEnumFiles (
  2685. DirName,
  2686. SppRecursiveLimitedEnumProc,
  2687. ReturnData,
  2688. &RecursionData
  2689. );*/
  2690. return SpEnumFilesInline(DirName,
  2691. EnumFilesProc,
  2692. ReturnData,
  2693. p1,
  2694. FALSE,
  2695. MaxDepth,
  2696. FALSE);
  2697. }
  2698. ENUMFILESRESULT
  2699. SpEnumFilesRecursiveDel (
  2700. IN PWSTR DirName,
  2701. IN ENUMFILESPROC EnumFilesProc,
  2702. OUT PULONG ReturnData,
  2703. IN PVOID p1 OPTIONAL
  2704. )
  2705. //
  2706. // This function is the same as SpEnumFilesRecursive except that
  2707. // it handles reparse points too and avoids name cycles and calls
  2708. // SppRecursiveEnumProcDel instead
  2709. //
  2710. {
  2711. return SpEnumFilesInline(DirName,
  2712. EnumFilesProc,
  2713. ReturnData,
  2714. p1,
  2715. TRUE,
  2716. MAX_DEPTH,
  2717. FALSE);
  2718. /* RECURSION_DATA RecursionData;
  2719. RecursionData.OptionalPtr = p1;
  2720. RecursionData.EnumProc = EnumFilesProc;
  2721. return SpEnumFiles (
  2722. DirName,
  2723. SppRecursiveEnumProcDel,
  2724. ReturnData,
  2725. &RecursionData
  2726. );*/
  2727. }
  2728. VOID
  2729. SpFatalKbdError(
  2730. IN ULONG MessageId,
  2731. ...
  2732. )
  2733. /*++
  2734. Routine Description:
  2735. Inform the user that a keyboard problem (specified by MessageId)
  2736. prevents setup from continuing. Since we can't prompt the user
  2737. to press a key to reboot, we just go into an infinite loop until
  2738. they power-cycle the computer.
  2739. Arguments:
  2740. MessageId - Message ID for keyboard error message to display
  2741. ... - Supply arguments for insertion/substitution into the message text.
  2742. Return Value:
  2743. DOES NOT RETURN
  2744. --*/
  2745. {
  2746. va_list arglist;
  2747. //
  2748. // Display a message indicating that a keyboard
  2749. // error prevents Setup from continuing.
  2750. //
  2751. CLEAR_CLIENT_SCREEN();
  2752. va_start(arglist, MessageId);
  2753. vSpDisplayFormattedMessage(
  2754. MessageId,
  2755. FALSE,
  2756. FALSE,
  2757. DEFAULT_ATTRIBUTE,
  2758. 3,
  2759. HEADER_HEIGHT+3,
  2760. arglist
  2761. );
  2762. va_end(arglist);
  2763. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, SP_STAT_KBD_HARD_REBOOT, 0);
  2764. while(TRUE); // Loop forever
  2765. }
  2766. VOID
  2767. SpFatalError(
  2768. IN ULONG MessageId,
  2769. ...
  2770. )
  2771. /*++
  2772. Routine Description:
  2773. Inform the user of a blocking problem. Then reboot.
  2774. Arguments:
  2775. MessageId - Message ID for keyboard error message to display
  2776. ... - Supply arguments for insertion/substitution into the message text.
  2777. Return Value:
  2778. DOES NOT RETURN
  2779. --*/
  2780. {
  2781. va_list arglist;
  2782. CLEAR_CLIENT_SCREEN();
  2783. va_start(arglist, MessageId);
  2784. vSpDisplayFormattedMessage(
  2785. MessageId,
  2786. FALSE,
  2787. FALSE,
  2788. DEFAULT_ATTRIBUTE,
  2789. 3,
  2790. HEADER_HEIGHT+3,
  2791. arglist
  2792. );
  2793. va_end(arglist);
  2794. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F3_EQUALS_REBOOT, 0);
  2795. SpInputDrain();
  2796. while( SpInputGetKeypress() != KEY_F3 );
  2797. SpDone( 0, FALSE, TRUE );
  2798. }
  2799. VOID
  2800. SpRunAutochkOnNtAndSystemPartitions(
  2801. IN HANDLE MasterSifHandle,
  2802. IN PDISK_REGION WinntPartitionRegion,
  2803. IN PDISK_REGION SystemPartitionRegion,
  2804. IN PWSTR SetupSourceDevicePath,
  2805. IN PWSTR DirectoryOnSourceDevice,
  2806. IN PWSTR TargetPath
  2807. )
  2808. /*++
  2809. Routine Description:
  2810. Run autochk on the NT and System partitions.
  2811. We always invoke autochk.exe for both the winnt and system
  2812. partitions. However under some conditions we pass flags that
  2813. cause it to run only if the dirty bit is set. Running only when
  2814. the dirty bit is set is referred to below as a "light check" wheras
  2815. running regardless of the state of the dirty bit is the "heavy check."
  2816. If this is repair, run the heavy check in all cases on both partitions.
  2817. If this is express setup or unattended operation, run light check on
  2818. ntfs partitions and heavy check on fat ones.
  2819. Otherwise (attended custom setup), ask the user.
  2820. Arguments:
  2821. MasterSifHandle - Handle to txtsetup.sif.
  2822. WinntPartitionRegion - Pointer to the structure that describes the
  2823. NT partition.
  2824. SystemPartitionRegion - Pointer to the structure that describes the
  2825. system partition.
  2826. SetupSourceDevicePath - NT device path where autochk.exe is located
  2827. DirectoryOnSourceDevice - Directory on that device where autochk.exe is located
  2828. Return Value:
  2829. None.
  2830. --*/
  2831. {
  2832. PWSTR MediaShortName;
  2833. PWSTR MediaDirectory;
  2834. PWSTR AutochkPath;
  2835. ULONG AutochkStatus;
  2836. WCHAR DriveLetterString[3] = L"?:";
  2837. NTSTATUS Status;
  2838. ULONG ValidKeys[3] = { ASCI_CR, ASCI_ESC, 0 };
  2839. PWSTR WinntPartition, SystemPartition;
  2840. ULONG WinntPartIndex, SystemPartIndex, i;
  2841. PWSTR AutochkPartition[2];
  2842. PWSTR AutochkType[2];
  2843. LARGE_INTEGER DelayTime;
  2844. PWSTR HeavyCheck = L"-t -p"; // -t causes autochk to send messages (like % complete)
  2845. PWSTR LightCheck = L"-t"; // to the setup driver
  2846. BOOLEAN RunAutochkForRepair;
  2847. BOOLEAN MultiplePartitions = TRUE, RebootRequired = FALSE;
  2848. ULONG InputChar;
  2849. //
  2850. // We first need to determine if either the system partition
  2851. // or winnt partition also contains the directory from which
  2852. // autochk is being run. If so, then we want to run autochk on that
  2853. // partition last. This is done so that no further access to
  2854. // that partition will be necessary should a reboot be required.
  2855. //
  2856. // First, get the device path of the nt partition and system partition.
  2857. //
  2858. #if defined(REMOTE_BOOT)
  2859. // Note that during a remote boot setup, there will be no winnt partition,
  2860. // and if the machine is diskless there will be no system partition.
  2861. //
  2862. #endif // defined(REMOTE_BOOT)
  2863. if (WinntPartitionRegion != NULL) {
  2864. SpNtNameFromRegion(
  2865. WinntPartitionRegion,
  2866. TemporaryBuffer,
  2867. sizeof(TemporaryBuffer),
  2868. PartitionOrdinalCurrent
  2869. );
  2870. WinntPartition = SpDupStringW(TemporaryBuffer);
  2871. } else {
  2872. WinntPartition = NULL;
  2873. }
  2874. if (SystemPartitionRegion != NULL) {
  2875. SpNtNameFromRegion(
  2876. SystemPartitionRegion,
  2877. TemporaryBuffer,
  2878. sizeof(TemporaryBuffer),
  2879. PartitionOrdinalCurrent
  2880. );
  2881. SystemPartition = SpDupStringW(TemporaryBuffer);
  2882. } else {
  2883. SystemPartition = NULL;
  2884. }
  2885. //
  2886. // Skip autocheck if not partitions names could
  2887. // be formed
  2888. //
  2889. if (!WinntPartition && !SystemPartition) {
  2890. return;
  2891. }
  2892. #if defined(REMOTE_BOOT)
  2893. if (!RemoteBootSetup) {
  2894. #endif // defined(REMOTE_BOOT)
  2895. if (WinntPartition) {
  2896. if (SystemPartition && !_wcsicmp(WinntPartition, SystemPartition)) {
  2897. SystemPartIndex = WinntPartIndex = 0;
  2898. MultiplePartitions = FALSE;
  2899. } else if(!_wcsicmp(WinntPartition, SetupSourceDevicePath)) {
  2900. WinntPartIndex = 1;
  2901. SystemPartIndex = 0;
  2902. } else {
  2903. WinntPartIndex = 0;
  2904. SystemPartIndex = 1;
  2905. }
  2906. } else {
  2907. WinntPartIndex = 1;
  2908. SystemPartIndex = 0;
  2909. }
  2910. AutochkPartition[WinntPartIndex] = WinntPartition;
  2911. if(MultiplePartitions) {
  2912. AutochkPartition[SystemPartIndex] = SystemPartition;
  2913. }
  2914. #if defined(REMOTE_BOOT)
  2915. } else {
  2916. //
  2917. // Remote boot system - only check the system partition.
  2918. //
  2919. SystemPartIndex = WinntPartIndex = 0;
  2920. AutochkPartition[SystemPartIndex] = SystemPartition;
  2921. MultiplePartitions = FALSE;
  2922. }
  2923. #endif // defined(REMOTE_BOOT)
  2924. //
  2925. // For repair or Disaster Recovery, we run the heavy check in all cases. // @@ mtp
  2926. //
  2927. if( RepairWinnt || SpDrEnabled() ) {
  2928. AutochkType[WinntPartIndex] = HeavyCheck;
  2929. if(MultiplePartitions) {
  2930. AutochkType[SystemPartIndex] = HeavyCheck;
  2931. }
  2932. } else {
  2933. #if defined(REMOTE_BOOT)
  2934. //
  2935. // On a diskless remote boot system, there will be no system partition.
  2936. //
  2937. if (SystemPartitionRegion != NULL)
  2938. #endif // defined(REMOTE_BOOT)
  2939. {
  2940. AutochkType[SystemPartIndex] = (SystemPartitionRegion->Filesystem == FilesystemNtfs) ? LightCheck : HeavyCheck;
  2941. }
  2942. //
  2943. // If MultiplePartitions is FALSE, then the WinntPartition is the same
  2944. // as the SystemPartition, so we are not going to autochk the WinntPartition.
  2945. //
  2946. #if defined(REMOTE_BOOT)
  2947. // MultiplePartitions will also be FALSE if this is a remote boot system,
  2948. // in which case the WinntPartition is remote. Again, we are not going
  2949. // to autochk the WinntPartition.
  2950. //
  2951. #endif // defined(REMOTE_BOOT)
  2952. if (MultiplePartitions) {
  2953. ASSERT(WinntPartitionRegion != NULL);
  2954. ASSERT(WinntPartition != NULL);
  2955. AutochkType[WinntPartIndex] = (WinntPartitionRegion->Filesystem == FilesystemNtfs) ? LightCheck : HeavyCheck;
  2956. }
  2957. }
  2958. CLEAR_CLIENT_SCREEN();
  2959. //
  2960. // Prepare to run autochk
  2961. //
  2962. MediaShortName = SpLookUpValueForFile(
  2963. MasterSifHandle,
  2964. L"autochk.exe",
  2965. INDEX_WHICHMEDIA,
  2966. TRUE
  2967. );
  2968. //
  2969. // Prompt the user to insert the setup media. If we're repairing,
  2970. // then we don't want to force the user to have the setup media
  2971. // (there's certain things they can do without it), so we give them
  2972. // a slightly different prompt, that allows them to press ESC and
  2973. // not run autochk.
  2974. //
  2975. if (!Win9xRollback) {
  2976. if(RepairWinnt) {
  2977. RunAutochkForRepair = SppPromptOptionalAutochk(
  2978. MasterSifHandle,
  2979. MediaShortName,
  2980. SetupSourceDevicePath
  2981. );
  2982. if(!RunAutochkForRepair) {
  2983. SpMemFree( WinntPartition );
  2984. SpMemFree( SystemPartition );
  2985. CLEAR_CLIENT_SCREEN();
  2986. return;
  2987. }
  2988. } else {
  2989. SpPromptForSetupMedia(
  2990. MasterSifHandle,
  2991. MediaShortName,
  2992. SetupSourceDevicePath
  2993. );
  2994. }
  2995. SpGetSourceMediaInfo(MasterSifHandle,MediaShortName,NULL,NULL,&MediaDirectory);
  2996. wcscpy( TemporaryBuffer, SetupSourceDevicePath );
  2997. SpConcatenatePaths( TemporaryBuffer, DirectoryOnSourceDevice );
  2998. SpConcatenatePaths( TemporaryBuffer, MediaDirectory );
  2999. SpConcatenatePaths( TemporaryBuffer, L"autochk.exe" );
  3000. AutochkPath = SpDupStringW( TemporaryBuffer );
  3001. } else {
  3002. //
  3003. // Win9x rollback -- autochk.exe is in $win_nt$.~bt\i386
  3004. //
  3005. wcscpy (TemporaryBuffer, NtBootDevicePath);
  3006. SpConcatenatePaths (TemporaryBuffer, DirectoryOnBootDevice);
  3007. SpConcatenatePaths (TemporaryBuffer, L"i386\\autochk.exe");
  3008. AutochkPath = SpDupStringW (TemporaryBuffer);
  3009. }
  3010. //
  3011. // Run autochk on the partition(s)
  3012. //
  3013. CLEAR_CLIENT_SCREEN();
  3014. SpDisplayScreen( SP_SCRN_RUNNING_AUTOCHK, 3, 4 );
  3015. //
  3016. // Create the gauge.
  3017. // Since we want only one progress bar displayed to the user
  3018. // while autochk is running, we initialize the range of the
  3019. // gauge based on the number of partitions to be examined.
  3020. // If the system and NT partitions are the same, the we set
  3021. // the range as 100. Otherwise, we set the range at 200.
  3022. // Note that on the multiple partitions case, 50% of the gauge
  3023. // will be used to display the progress for each disk.
  3024. // The IOCTL that calls SpFillGauge(), will have to adjust the
  3025. // amount of the gauge to be filled, based on the partition that
  3026. // is currently being examined.
  3027. //
  3028. UserModeGauge = SpCreateAndDisplayGauge( (MultiplePartitions)? 200 : 100,
  3029. 0,
  3030. 15,
  3031. L"",
  3032. NULL,
  3033. GF_PERCENTAGE,
  3034. 0
  3035. ); // Setup is checking disk(s)...
  3036. //
  3037. for(i = 0; i < (ULONG)(MultiplePartitions ? 2 : 1); i++) {
  3038. //
  3039. // Display message informing that autocheck is being run
  3040. //
  3041. if (AutochkPartition[i] != NULL) {
  3042. DriveLetterString[0] = (i == WinntPartIndex) ?
  3043. WinntPartitionRegion->DriveLetter :
  3044. SystemPartitionRegion->DriveLetter;
  3045. SpDisplayStatusText( SP_STAT_CHECKING_DRIVE,
  3046. DEFAULT_STATUS_ATTRIBUTE,
  3047. DriveLetterString );
  3048. if(!i) {
  3049. //
  3050. // Cheesy kludge below to wait 4 seconds before invoking autochk.exe
  3051. // the first time. This was necessary because the cache manager delays
  3052. // in closing the handle to system.log (opened by NT registry APIs when
  3053. // we find NT's to upgrade)
  3054. //
  3055. DelayTime.HighPart = -1;
  3056. DelayTime.LowPart = (ULONG)-40000000;
  3057. KeDelayExecutionThread (KernelMode, FALSE, &DelayTime);
  3058. }
  3059. //
  3060. // Tell the IOCTL which disk is being examined.
  3061. //
  3062. CurrentDiskIndex = i;
  3063. AutochkStatus = 0;
  3064. Status = SpExecuteImage( AutochkPath,
  3065. &AutochkStatus,
  3066. 2,
  3067. AutochkType[i],
  3068. AutochkPartition[i]
  3069. );
  3070. if( NT_SUCCESS( Status ) ) {
  3071. switch(AutochkStatus) {
  3072. case CHKDSK_EXIT_COULD_NOT_FIX :
  3073. //
  3074. // Inform that the partition has an unrecoverable error
  3075. //
  3076. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: autochk.exe failed on %ls. ReturnCode = %x \n", AutochkPartition[i], AutochkStatus ));
  3077. SpStartScreen( SP_SCRN_FATAL_ERROR_AUTOCHK_FAILED,
  3078. 3,
  3079. HEADER_HEIGHT+1,
  3080. FALSE,
  3081. FALSE,
  3082. DEFAULT_ATTRIBUTE,
  3083. DriveLetterString );
  3084. SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE,
  3085. SP_STAT_F3_EQUALS_EXIT,
  3086. 0 );
  3087. SpInputDrain();
  3088. while( SpInputGetKeypress() != KEY_F3 );
  3089. //
  3090. // The third arg of SpDone is TRUE to provide 15
  3091. // seconds before reboot. We don't want this during
  3092. // an uninstall.
  3093. //
  3094. SpDone( 0, FALSE, !Win9xRollback );
  3095. case CHKDSK_EXIT_ERRS_FIXED :
  3096. //
  3097. // Autochk was able to repair the partition, but will require a reboot.
  3098. //
  3099. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: autochk requires a reboot for %ls.\n", AutochkPartition[i]));
  3100. RebootRequired = TRUE;
  3101. default :
  3102. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Ran autochk.exe on %ls. \n", AutochkPartition[i] ));
  3103. }
  3104. } else {
  3105. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to run autochk.exe on %ls. Status = %x \n", AutochkPartition[i], Status ));
  3106. SpStartScreen( Win9xRollback ? SP_SCRN_CANT_RUN_AUTOCHK_UNINSTALL : SP_SCRN_CANT_RUN_AUTOCHK,
  3107. 3,
  3108. HEADER_HEIGHT+1,
  3109. FALSE,
  3110. FALSE,
  3111. DEFAULT_ATTRIBUTE,
  3112. DriveLetterString );
  3113. SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE,
  3114. SP_STAT_ENTER_EQUALS_CONTINUE,
  3115. 0 );
  3116. SpInputDrain();
  3117. do {
  3118. InputChar = SpInputGetKeypress();
  3119. } while (InputChar != ASCI_CR && (!Win9xRollback || InputChar != KEY_F3));
  3120. if (InputChar == KEY_F3) {
  3121. SpDone (0, FALSE, FALSE);
  3122. }
  3123. //
  3124. // Put the screen back the way it was
  3125. //
  3126. CLEAR_CLIENT_SCREEN();
  3127. SpDisplayScreen( SP_SCRN_RUNNING_AUTOCHK, 3, 4 );
  3128. if( UserModeGauge != NULL ) {
  3129. SpDrawGauge( UserModeGauge );
  3130. }
  3131. }
  3132. }
  3133. }
  3134. //
  3135. // The gauge is no longer needed.
  3136. //
  3137. SpDestroyGauge( UserModeGauge );
  3138. UserModeGauge = NULL;
  3139. if (WinntPartition != NULL) {
  3140. SpMemFree( WinntPartition );
  3141. }
  3142. if (SystemPartition != NULL) {
  3143. SpMemFree( SystemPartition );
  3144. }
  3145. SpMemFree( AutochkPath );
  3146. CLEAR_CLIENT_SCREEN();
  3147. if (RebootRequired) {
  3148. #ifdef _X86_
  3149. //
  3150. // If we are trying to cancel a setup that is in-progress, make sure
  3151. // that the textmode option is removed from boot.ini, but the textmode
  3152. // option that has /rollback is left in-place.
  3153. //
  3154. if (Win9xRollback) {
  3155. SpRemoveExtraBootIniEntry();
  3156. SpAddRollbackBootOption (TRUE);
  3157. SpFlushBootVars();
  3158. }
  3159. #endif
  3160. if (TargetPath && TargetPath[0] && NTUpgrade == UpgradeFull) {
  3161. SpSetUpgradeStatus(
  3162. WinntPartitionRegion,
  3163. TargetPath,
  3164. UpgradeNotInProgress
  3165. );
  3166. }
  3167. //
  3168. // If this is not an unattended case let the user see the
  3169. // error message and confirm it.
  3170. //
  3171. if (!UnattendedOperation) {
  3172. SpStartScreen( SP_SCRN_AUTOCHK_REQUIRES_REBOOT,
  3173. 3,
  3174. HEADER_HEIGHT+1,
  3175. TRUE,
  3176. TRUE,
  3177. DEFAULT_ATTRIBUTE );
  3178. SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE,
  3179. SP_STAT_F3_EQUALS_REBOOT,
  3180. 0 );
  3181. SpInputDrain();
  3182. while( SpInputGetKeypress() != KEY_F3 );
  3183. }
  3184. if (IsNEC_98) { //NEC98
  3185. Nec98RestoreBootFiles = FALSE;
  3186. } //NEC98
  3187. SpDone(SP_SCRN_AUTOCHK_REQUIRES_REBOOT, FALSE, TRUE );
  3188. }
  3189. }
  3190. BOOLEAN
  3191. SppPromptOptionalAutochk(
  3192. IN PVOID SifHandle,
  3193. IN PWSTR MediaShortname,
  3194. IN PWSTR DiskDevicePath
  3195. )
  3196. {
  3197. PWSTR Tagfile,Description,Directory;
  3198. NTSTATUS Status;
  3199. UNICODE_STRING UnicodeString;
  3200. OBJECT_ATTRIBUTES ObjectAttributes;
  3201. IO_STATUS_BLOCK IoStatusBlock;
  3202. HANDLE Handle;
  3203. ULONG ValidKeys[4] = { KEY_F3, ASCI_CR, ASCI_ESC, 0 };
  3204. BOOLEAN AutochkChosen;
  3205. SpGetSourceMediaInfo(SifHandle,MediaShortname,&Description,&Tagfile,&Directory);
  3206. //
  3207. // We initially see if the media is in the drive, and if not, we give
  3208. // the user a message with the option of skipping autochk. We
  3209. // do this now, so that the user doesn't simply get a disk prompt with
  3210. // a Cancel option (Cancel what? Autochk? The whole repair process?)
  3211. //
  3212. wcscpy(TemporaryBuffer, DiskDevicePath);
  3213. SpConcatenatePaths(TemporaryBuffer, Tagfile);
  3214. INIT_OBJA(&ObjectAttributes, &UnicodeString, TemporaryBuffer);
  3215. Status = ZwCreateFile(
  3216. &Handle,
  3217. FILE_GENERIC_READ,
  3218. &ObjectAttributes,
  3219. &IoStatusBlock,
  3220. NULL,
  3221. FILE_ATTRIBUTE_NORMAL,
  3222. FILE_SHARE_READ,
  3223. FILE_OPEN,
  3224. 0,
  3225. NULL,
  3226. 0
  3227. );
  3228. //
  3229. // If we got back success, then we're done.
  3230. //
  3231. if(NT_SUCCESS(Status)) {
  3232. ZwClose(Handle);
  3233. return TRUE;
  3234. }
  3235. //
  3236. // The media isn't currently in the drive, so give the
  3237. // user the option of whether to run autochk or not.
  3238. //
  3239. AutochkChosen = FALSE;
  3240. do {
  3241. SpDisplayScreen(SP_SCRN_AUTOCHK_OPTION, 3, HEADER_HEIGHT+1);
  3242. SpDisplayStatusOptions(
  3243. DEFAULT_STATUS_ATTRIBUTE,
  3244. SP_STAT_F3_EQUALS_EXIT,
  3245. SP_STAT_ENTER_EQUALS_CONTINUE,
  3246. SP_STAT_ESC_EQUALS_CANCEL,
  3247. 0
  3248. );
  3249. switch(SpWaitValidKey(ValidKeys, NULL, NULL)) {
  3250. case ASCI_ESC:
  3251. return FALSE;
  3252. case KEY_F3:
  3253. SpConfirmExit();
  3254. break;
  3255. case ASCI_CR:
  3256. AutochkChosen = TRUE;
  3257. }
  3258. } while(!AutochkChosen);
  3259. //
  3260. // Prompt for the disk, based on the setup media type.
  3261. //
  3262. return(SpPromptForDisk(Description, DiskDevicePath, Tagfile, FALSE, TRUE, TRUE, NULL));
  3263. }
  3264. PWSTR
  3265. SpMakePlatformSpecificSectionName(
  3266. IN PWSTR SectionName
  3267. )
  3268. {
  3269. PWSTR p;
  3270. p = SpMemAlloc((wcslen(SectionName) + wcslen(PlatformExtension) + 1) * sizeof(WCHAR));
  3271. wcscpy(p,SectionName);
  3272. wcscat(p,PlatformExtension);
  3273. return(p);
  3274. }
  3275. NTSTATUS
  3276. SpRunAutoFormat(
  3277. IN HANDLE MasterSifHandle,
  3278. IN PWSTR RegionDescription,
  3279. IN PDISK_REGION PartitionRegion,
  3280. IN ULONG FilesystemType,
  3281. IN BOOLEAN QuickFormat,
  3282. IN DWORD ClusterSize,
  3283. IN PWSTR SetupSourceDevicePath,
  3284. IN PWSTR DirectoryOnSourceDevice
  3285. )
  3286. /*++
  3287. Routine Description:
  3288. Run autofmt to format a partition.
  3289. Arguments:
  3290. MasterSifHandle - Handle to txtsetup.sif.
  3291. RegionDescription - The region description, as displayed to the
  3292. user, in the screen with the various partitions
  3293. for the user to choose.
  3294. PartitionRegion - Pointer to the structure that describes the
  3295. partition to be formatted.
  3296. FilesystemType - Indicates the file system to use.
  3297. ClusterSize - File system cluster-size to use. (0=>Use default)
  3298. SetupSourceDevicePath - NT device path where autochk.exe is located
  3299. DirectoryOnSourceDevice - Directory on that device where autochk.exe is located
  3300. Return Value:
  3301. None.
  3302. --*/
  3303. {
  3304. PWSTR MediaShortName;
  3305. PWSTR MediaDirectory;
  3306. PWSTR AutofmtPath;
  3307. ULONG AutofmtStatus;
  3308. NTSTATUS Status;
  3309. WCHAR AutofmtArgument[32];
  3310. PWSTR PartitionPath;
  3311. LARGE_INTEGER DelayTime;
  3312. ULONG PartitionOrdinal;
  3313. ASSERT( ( FilesystemType == FilesystemNtfs ) ||
  3314. ( FilesystemType == FilesystemFat32) ||
  3315. ( FilesystemType == FilesystemFat ) );
  3316. //
  3317. // Make SURE it's not partition0! The results of formatting partition0
  3318. // are so disasterous that this warrants a special check.
  3319. //
  3320. PartitionOrdinal = SpPtGetOrdinal(PartitionRegion,PartitionOrdinalCurrent);
  3321. if(!PartitionOrdinal) {
  3322. SpBugCheck(
  3323. SETUP_BUGCHECK_PARTITION,
  3324. PARTITIONBUG_B,
  3325. PartitionRegion->DiskNumber,
  3326. 0
  3327. );
  3328. }
  3329. //
  3330. // Get the device path of the partition to format
  3331. //
  3332. SpNtNameFromRegion(
  3333. PartitionRegion,
  3334. TemporaryBuffer,
  3335. sizeof(TemporaryBuffer),
  3336. PartitionOrdinalCurrent
  3337. );
  3338. PartitionPath = SpDupStringW(TemporaryBuffer);
  3339. CLEAR_CLIENT_SCREEN();
  3340. //
  3341. // Prepair to run autofmt
  3342. //
  3343. MediaShortName = SpLookUpValueForFile(
  3344. MasterSifHandle,
  3345. L"autofmt.exe",
  3346. INDEX_WHICHMEDIA,
  3347. TRUE
  3348. );
  3349. //
  3350. // Prompt the user to insert the setup media.
  3351. //
  3352. SpPromptForSetupMedia(
  3353. MasterSifHandle,
  3354. MediaShortName,
  3355. SetupSourceDevicePath
  3356. );
  3357. SpGetSourceMediaInfo(MasterSifHandle,MediaShortName,NULL,NULL,&MediaDirectory);
  3358. wcscpy( TemporaryBuffer, SetupSourceDevicePath );
  3359. SpConcatenatePaths( TemporaryBuffer, DirectoryOnSourceDevice );
  3360. SpConcatenatePaths( TemporaryBuffer, MediaDirectory );
  3361. SpConcatenatePaths( TemporaryBuffer, L"autofmt.exe" );
  3362. AutofmtPath = SpDupStringW( TemporaryBuffer );
  3363. //
  3364. // Run autofmt on the partition
  3365. //
  3366. CLEAR_CLIENT_SCREEN();
  3367. //
  3368. // Put up a screen indicating what we are doing.
  3369. //
  3370. SpStartScreen(
  3371. SP_SCRN_SETUP_IS_FORMATTING,
  3372. 0,
  3373. HEADER_HEIGHT + 3,
  3374. TRUE,
  3375. FALSE,
  3376. DEFAULT_ATTRIBUTE,
  3377. RegionDescription,
  3378. HardDisks[PartitionRegion->DiskNumber].Description
  3379. );
  3380. SpvidClearScreenRegion(
  3381. 0,
  3382. VideoVars.ScreenHeight-STATUS_HEIGHT,
  3383. VideoVars.ScreenWidth,
  3384. STATUS_HEIGHT,
  3385. DEFAULT_STATUS_BACKGROUND
  3386. );
  3387. //
  3388. // Create and display the (global) gauge.
  3389. //
  3390. SpFormatMessage(
  3391. TemporaryBuffer,
  3392. sizeof(TemporaryBuffer),
  3393. SP_TEXT_SETUP_IS_FORMATTING
  3394. );
  3395. UserModeGauge = SpCreateAndDisplayGauge( 100,
  3396. 0,
  3397. VideoVars.ScreenHeight - STATUS_HEIGHT - (3*GAUGE_HEIGHT/2),
  3398. TemporaryBuffer,
  3399. NULL,
  3400. GF_PERCENTAGE,
  3401. 0
  3402. );
  3403. //
  3404. // Cheesy kludge below to wait 4 seconds before invoking autochk.exe
  3405. // the first time. This was necessary because the cache manager delays
  3406. // in closing the handle to system.log (opened by NT registry APIs when
  3407. // we find NT's to upgrade)
  3408. //
  3409. DelayTime.HighPart = -1;
  3410. DelayTime.LowPart = (ULONG)-40000000;
  3411. KeDelayExecutionThread (KernelMode, FALSE, &DelayTime);
  3412. AutofmtStatus = AUTOFMT_EXIT_SUCCESS;
  3413. if (ClusterSize > 0) {
  3414. swprintf(AutofmtArgument, L"/a:%lu /t ", ClusterSize);
  3415. }
  3416. else {
  3417. wcscpy(AutofmtArgument, L"/t ");
  3418. }
  3419. if (QuickFormat) {
  3420. wcscat(AutofmtArgument, L"/Q ");
  3421. }
  3422. switch(FilesystemType) {
  3423. case FilesystemNtfs:
  3424. wcscat(AutofmtArgument, L"/fs:ntfs");
  3425. break;
  3426. case FilesystemFat32:
  3427. wcscat(AutofmtArgument, L"/fs:fat32");
  3428. break;
  3429. case FilesystemFat:
  3430. default:
  3431. wcscat(AutofmtArgument, L"/fs:fat");
  3432. break;
  3433. }
  3434. //
  3435. // Tell the IOCTL which disk is being examined.
  3436. //
  3437. CurrentDiskIndex = 0;
  3438. //
  3439. // For quick format, emulate as though progress is
  3440. // being made
  3441. //
  3442. if (UserModeGauge && QuickFormat) {
  3443. SpFillGauge(UserModeGauge, 20);
  3444. }
  3445. //
  3446. // Note that autofmt requires that the partition path comes
  3447. // before the autofmt switches
  3448. //
  3449. Status = SpExecuteImage( AutofmtPath,
  3450. &AutofmtStatus,
  3451. 2,
  3452. PartitionPath,
  3453. AutofmtArgument
  3454. );
  3455. //
  3456. // For quick format, emulate as though progress is
  3457. // being made
  3458. //
  3459. if (UserModeGauge && QuickFormat) {
  3460. SpFillGauge(UserModeGauge, 100);
  3461. //
  3462. // wait for a second so that user can
  3463. // see it filled
  3464. //
  3465. DelayTime.HighPart = -1;
  3466. DelayTime.LowPart = (ULONG)-10000000;
  3467. KeDelayExecutionThread (KernelMode, FALSE, &DelayTime);
  3468. }
  3469. //
  3470. // Destroy the gauge
  3471. //
  3472. SpDestroyGauge( UserModeGauge );
  3473. UserModeGauge = NULL;
  3474. if( NT_SUCCESS( Status ) ) {
  3475. //
  3476. // autofmt.exe was run.
  3477. // Find out if the partition was formatted.
  3478. //
  3479. KdPrint(("SETUP:AutoFormat Status : %lx\n", AutofmtStatus));
  3480. switch(AutofmtStatus) {
  3481. case AUTOFMT_EXIT_SUCCESS:
  3482. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Ran autofmt.exe on %ls. \n", PartitionPath ));
  3483. #ifdef _X86_
  3484. if (!IsNEC_98) { //NEC98
  3485. //
  3486. // If we formatted C:, then clear the previous OS entry
  3487. // in boot.ini.
  3488. //
  3489. if(PartitionRegion == SpPtValidSystemPartition()) {
  3490. *OldSystemLine = '\0';
  3491. }
  3492. } //NEC98
  3493. #endif
  3494. break;
  3495. // case AUTOFMT_EXIT_COULD_NOT_FORMAT :
  3496. default:
  3497. //
  3498. // autofmt was unable to format the partition
  3499. //
  3500. Status = STATUS_UNSUCCESSFUL;
  3501. break;
  3502. }
  3503. } else {
  3504. //
  3505. // autofmt.exe didn't get executed.
  3506. // Display a fatal error message.
  3507. //
  3508. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to run autofmt.exe on %ls. Status = %x \n", PartitionPath, Status ));
  3509. SpStartScreen( SP_SCRN_CANT_RUN_AUTOFMT,
  3510. 3,
  3511. HEADER_HEIGHT+1,
  3512. FALSE,
  3513. FALSE,
  3514. DEFAULT_ATTRIBUTE );
  3515. SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE,
  3516. SP_STAT_F3_EQUALS_EXIT,
  3517. 0 );
  3518. SpInputDrain();
  3519. while( SpInputGetKeypress() != KEY_F3 );
  3520. SpDone( 0, FALSE, TRUE );
  3521. }
  3522. //
  3523. // Do the cleanup and return
  3524. //
  3525. SpMemFree( PartitionPath );
  3526. SpMemFree( AutofmtPath );
  3527. CLEAR_CLIENT_SCREEN();
  3528. return( Status );
  3529. }
  3530. //
  3531. // NEC98
  3532. //
  3533. //
  3534. // On floppyless setup if user have canceled setup or setup be stoped by error
  3535. // occured,previous OS cann't boot to be written boot code and boot loader.
  3536. //
  3537. NTSTATUS
  3538. SpDeleteAndBackupBootFiles(
  3539. BOOLEAN RestoreBackupFiles,
  3540. BOOLEAN DeleteBackupFiles,
  3541. BOOLEAN DeleteRootDirFiles,
  3542. BOOLEAN RestorePreviousOs,
  3543. BOOLEAN ClearBootFlag
  3544. )
  3545. {
  3546. #define WINNT_BAK L"$WIN_NT$.~BU"
  3547. #define ATTR_RHS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
  3548. PWSTR DeleteRootFiles[] = {L"ntdetect.com",L"$ldr$",L"boot.ini",L"txtsetup.sif",L"ntldr",L"bootfont.bin",L"bootsect.dos"};
  3549. PWSTR RestoreFiles[] = {L"boot.ini",L"ntdetect.com",L"ntldr"};
  3550. WCHAR DevicePath[256],SourceFileName[256],TargetFileName[256],TmpFileName[256];
  3551. UCHAR i;
  3552. NTSTATUS status=0;
  3553. PWSTR SetupSourceDevicePath,DirectoryOnSetupSource;
  3554. SpdInitialize();
  3555. #ifdef _X86_
  3556. if(RestorePreviousOs){
  3557. //
  3558. // IF bootsect.dos exist in boot path, setup restore previous OS bootcode.
  3559. //
  3560. // NOTE:When you modefied boot.ini for multi boot function if it is same NT boot partition
  3561. // and partition where is exiting bootsect.dos , setup restore DOS bootcode.
  3562. // Therefore NT on this partition is not boot forever.
  3563. //
  3564. SppRestoreBootCode();
  3565. }
  3566. #endif
  3567. if(DeleteRootDirFiles){
  3568. //
  3569. // Delete floppy less boot files in root.
  3570. //
  3571. for(i=0 ; i < ELEMENT_COUNT(DeleteRootFiles); i++) {
  3572. wcscpy(TargetFileName,NtBootDevicePath);
  3573. SpDeleteFile(TargetFileName, DeleteRootFiles[i], NULL);
  3574. }
  3575. #ifdef _X86_
  3576. //
  3577. // If we're on an x86, but it's *NOT* an ARC machine,
  3578. // then there's no need for the arc loaders to be
  3579. // present.
  3580. //
  3581. if( !SpIsArc() ) {
  3582. wcscpy(TargetFileName,NtBootDevicePath);
  3583. SpDeleteFile(TargetFileName, L"arcsetup.exe", NULL);
  3584. wcscpy(TargetFileName,NtBootDevicePath);
  3585. SpDeleteFile(TargetFileName, L"arcldr.exe", NULL);
  3586. }
  3587. #endif
  3588. }
  3589. //
  3590. // If \BOOTSECT.NEC exists, restore it to \BOOTSECT.DOS.
  3591. // BTY, winnt32 makes \BOOTSECT.DOS even if boot sector is for NT.(NEC98 only)
  3592. //
  3593. wcscpy(SourceFileName,NtBootDevicePath);
  3594. SpConcatenatePaths(SourceFileName,L"\\");
  3595. SpConcatenatePaths(SourceFileName,L"bootsect.nec");
  3596. wcscpy(TargetFileName,NtBootDevicePath);
  3597. SpConcatenatePaths(TargetFileName,L"\\");
  3598. SpConcatenatePaths(TargetFileName,L"bootsect.dos");
  3599. if(SpFileExists(SourceFileName,FALSE)) {
  3600. if(SpFileExists(TargetFileName,FALSE)) {
  3601. SpDeleteFile( TargetFileName, NULL, NULL);
  3602. }
  3603. SpRenameFile( SourceFileName, TargetFileName, FALSE );
  3604. }
  3605. if(RestoreBackupFiles){
  3606. //
  3607. // Restore previous NT files to root form $WIN_NT$.~BU.
  3608. //
  3609. for(i=0 ; i < ELEMENT_COUNT(RestoreFiles) ;i++) {
  3610. wcscpy(SourceFileName,NtBootDevicePath);
  3611. SpConcatenatePaths(SourceFileName,WINNT_BAK);
  3612. SpConcatenatePaths(SourceFileName,RestoreFiles[i]);
  3613. wcscpy(TargetFileName,NtBootDevicePath);
  3614. SpConcatenatePaths(TargetFileName,L"\\");
  3615. SpConcatenatePaths(TargetFileName,RestoreFiles[i]);
  3616. if( SpFileExists( SourceFileName, FALSE ) ) {
  3617. SpCopyFileUsingNames(SourceFileName,TargetFileName,ATTR_RHS,0L);
  3618. }
  3619. }
  3620. //
  3621. // Force uncompressd to "\ntldr".
  3622. //
  3623. wcscpy(TargetFileName,NtBootDevicePath);
  3624. SpConcatenatePaths(TargetFileName,L"\\");
  3625. SpConcatenatePaths(TargetFileName,L"ntldr");
  3626. if( SpFileExists( TargetFileName, FALSE ) ) {
  3627. SpVerifyNoCompression(TargetFileName);
  3628. }
  3629. }
  3630. if(DeleteBackupFiles){
  3631. //
  3632. // Delete files in $WIN_NT$.~BU.
  3633. //
  3634. for(i=0 ; i < ELEMENT_COUNT(RestoreFiles); i++) {
  3635. wcscpy(TargetFileName,NtBootDevicePath);
  3636. SpConcatenatePaths(TargetFileName,WINNT_BAK);
  3637. SpDeleteFile(TargetFileName, RestoreFiles[i], NULL);
  3638. }
  3639. //
  3640. // Delete $WIN_NT$.~BU
  3641. //
  3642. wcscpy(TargetFileName,NtBootDevicePath);
  3643. SpConcatenatePaths(TargetFileName,WINNT_BAK);
  3644. if( SpFileExists( TargetFileName, FALSE ) ) {
  3645. SpDeleteFile(TargetFileName, NULL, NULL);
  3646. }
  3647. #if NEC_TEST //0
  3648. //
  3649. // It's not available to delete $WIN_NT.~BT, but we will try
  3650. // to delete $WIN_NT$.~LS, Because Nec98 will boot back after F.3
  3651. //
  3652. if (WinntSetup && !WinntFromCd && !RemoteBootSetup && LocalSourceRegion) {
  3653. SpGetWinntParams(&SetupSourceDevicePath,&DirectoryOnSetupSource);
  3654. wcscpy(TargetFileName,SetupSourceDevicePath);
  3655. SpConcatenatePaths(TargetFileName,DirectoryOnSetupSource);
  3656. if( SpFileExists( TargetFileName, FALSE ) ) {
  3657. SpDeleteFile(TargetFileName, NULL, NULL);
  3658. }
  3659. }
  3660. #endif //NEC_TEST
  3661. }
  3662. //if(ClearBootFlag && TmpTargetRegion){
  3663. if(ClearBootFlag){
  3664. SpSetAutoBootFlag(NULL,FALSE);
  3665. }
  3666. SpdTerminate();
  3667. return(status);
  3668. }
  3669. BOOLEAN
  3670. SpFindServiceInList(
  3671. IN PWSTR ServiceName
  3672. )
  3673. {
  3674. LIST_ENTRY *Next;
  3675. PSERVICE_ENTRY ServiceEntry;
  3676. Next = SpServiceList.Flink;
  3677. while ((ULONG_PTR)Next != (ULONG_PTR)&SpServiceList) {
  3678. ServiceEntry = CONTAINING_RECORD( Next, SERVICE_ENTRY, Next );
  3679. Next = ServiceEntry->Next.Flink;
  3680. if (_wcsicmp( ServiceEntry->ServiceName, ServiceName ) == 0) {
  3681. return TRUE;
  3682. }
  3683. }
  3684. return FALSE;
  3685. }
  3686. BOOLEAN
  3687. AddServiceToList(
  3688. IN PWSTR ServiceName
  3689. )
  3690. {
  3691. PSERVICE_ENTRY ServiceEntry;
  3692. if (SpFindServiceInList(ServiceName)) {
  3693. return TRUE;
  3694. }
  3695. ServiceEntry = (PSERVICE_ENTRY) SpMemAlloc( sizeof(SERVICE_ENTRY) );
  3696. if (ServiceEntry == NULL) {
  3697. return FALSE;
  3698. }
  3699. ServiceEntry->ServiceName = SpDupStringW( ServiceName );
  3700. InsertTailList( &SpServiceList, &ServiceEntry->Next );
  3701. return TRUE;
  3702. }
  3703. BOOLEAN
  3704. SpFindServiceDependencies(
  3705. IN HANDLE ServicesHandle,
  3706. IN PWSTR ServiceName,
  3707. IN PWSTR ServiceDependName
  3708. )
  3709. {
  3710. NTSTATUS Status;
  3711. HANDLE KeyHandle;
  3712. UNICODE_STRING UnicodeString;
  3713. OBJECT_ATTRIBUTES Obja;
  3714. PKEY_VALUE_PARTIAL_INFORMATION ValInfo;
  3715. ULONG ResultLength;
  3716. PWSTR SubkeyName;
  3717. PWSTR s;
  3718. BOOLEAN rVal = FALSE;
  3719. INIT_OBJA( &Obja, &UnicodeString, ServiceName );
  3720. Obja.RootDirectory = ServicesHandle;
  3721. Status = ZwOpenKey( &KeyHandle, KEY_READ, &Obja );
  3722. if (!NT_SUCCESS(Status)) {
  3723. return rVal;
  3724. }
  3725. ValInfo = (PKEY_VALUE_PARTIAL_INFORMATION) TemporaryBuffer;
  3726. RtlInitUnicodeString( &UnicodeString, L"DependOnService");
  3727. Status = ZwQueryValueKey(
  3728. KeyHandle,
  3729. &UnicodeString,
  3730. KeyValuePartialInformation,
  3731. TemporaryBuffer,
  3732. sizeof(TemporaryBuffer),
  3733. &ResultLength
  3734. );
  3735. if (!NT_SUCCESS(Status)) {
  3736. ZwClose( KeyHandle );
  3737. return rVal;
  3738. }
  3739. if (ValInfo->Type == REG_MULTI_SZ) {
  3740. s = (PWSTR)ValInfo->Data;
  3741. while (s && *s) {
  3742. SubkeyName = SpDupStringW( s );
  3743. if (SubkeyName) {
  3744. if (_wcsicmp( ServiceDependName, SubkeyName ) == 0) {
  3745. if (AddServiceToList( ServiceName )) {
  3746. rVal = TRUE;
  3747. }
  3748. } else if (SpFindServiceDependencies( ServicesHandle, SubkeyName, ServiceDependName )) {
  3749. if (AddServiceToList( ServiceName )) {
  3750. rVal = TRUE;
  3751. }
  3752. }
  3753. SpMemFree( SubkeyName );
  3754. }
  3755. s = s + ((wcslen(s)+1)*sizeof(WCHAR));
  3756. }
  3757. } else if (ValInfo->Type == REG_SZ) {
  3758. SubkeyName = SpDupStringW( (PWSTR)ValInfo->Data );
  3759. if (_wcsicmp( ServiceDependName, SubkeyName ) == 0) {
  3760. if (AddServiceToList( ServiceName )) {
  3761. rVal = TRUE;
  3762. }
  3763. } else if (SpFindServiceDependencies( ServicesHandle, SubkeyName, ServiceDependName )) {
  3764. if (AddServiceToList( ServiceName )) {
  3765. rVal = TRUE;
  3766. }
  3767. }
  3768. SpMemFree( SubkeyName );
  3769. }
  3770. ZwClose( KeyHandle );
  3771. return rVal;
  3772. }
  3773. NTSTATUS
  3774. SpGetServiceTree(
  3775. IN PWSTR ServiceName
  3776. )
  3777. {
  3778. NTSTATUS Status;
  3779. HANDLE KeyHandle = NULL;
  3780. HANDLE ServicesHandle = NULL;
  3781. UNICODE_STRING UnicodeString;
  3782. OBJECT_ATTRIBUTES Obja;
  3783. ULONG ResultLength;
  3784. ULONG SubKeyIndex;
  3785. PKEY_BASIC_INFORMATION KeyInfo;
  3786. PWSTR SubkeyName;
  3787. InitializeListHead( &SpServiceList );
  3788. RtlInitUnicodeString( &UnicodeString, REGKEY_SERVICES );
  3789. InitializeObjectAttributes( &Obja, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL );
  3790. Status = ZwOpenKey( &ServicesHandle, KEY_READ, &Obja );
  3791. if (!NT_SUCCESS(Status)) {
  3792. return(Status);
  3793. }
  3794. for (SubKeyIndex=0,KeyInfo=(PKEY_BASIC_INFORMATION)TemporaryBuffer;
  3795. NT_SUCCESS( ZwEnumerateKey( ServicesHandle,
  3796. SubKeyIndex,
  3797. KeyBasicInformation,
  3798. TemporaryBuffer,
  3799. sizeof(TemporaryBuffer), &ResultLength ) );
  3800. SubKeyIndex++
  3801. )
  3802. {
  3803. KeyInfo->Name[KeyInfo->NameLength/sizeof(WCHAR)] = 0;
  3804. SubkeyName = SpDupStringW(KeyInfo->Name);
  3805. if (SubkeyName) {
  3806. SpFindServiceDependencies( ServicesHandle,
  3807. SubkeyName,
  3808. ServiceName );
  3809. SpMemFree( SubkeyName );
  3810. }
  3811. }
  3812. ZwClose( ServicesHandle );
  3813. return Status;
  3814. }
  3815. VOID
  3816. SpCreateNewGuid(
  3817. IN GUID *Guid
  3818. )
  3819. /*++
  3820. Routine Description:
  3821. Creates a new pseudo GUID
  3822. Arguments:
  3823. Guid - Place holder for the new pseudo
  3824. Return Value:
  3825. None.
  3826. --*/
  3827. {
  3828. if (Guid) {
  3829. LARGE_INTEGER Time;
  3830. ULONG Random1 = RtlRandom(&RandomSeed);
  3831. ULONG Random2 = RtlRandom(&RandomSeed);
  3832. //
  3833. // Get system time
  3834. //
  3835. KeQuerySystemTime(&Time);
  3836. RtlZeroMemory(Guid, sizeof(GUID));
  3837. //
  3838. // First 8 bytes is system time
  3839. //
  3840. RtlCopyMemory(Guid, &(Time.QuadPart), sizeof(Time.QuadPart));
  3841. //
  3842. // Next 8 bytes are two random numbers
  3843. //
  3844. RtlCopyMemory(Guid->Data4, &Random1, sizeof(ULONG));
  3845. RtlCopyMemory(((PCHAR)Guid->Data4) + sizeof(ULONG),
  3846. &Random2, sizeof(ULONG));
  3847. #if 0
  3848. {
  3849. WCHAR GuidStr[256];
  3850. KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  3851. "SETUP: SpCreateNewGuid : %ws\n",
  3852. SpPtGuidToString(Guid, GuidStr)));
  3853. }
  3854. #endif
  3855. }
  3856. }
  3857. NTSTATUS
  3858. RegisterSetupProgressCallback(
  3859. IN TM_SETUP_PROGRESS_CALLBACK Callback,
  3860. IN PVOID Context
  3861. )
  3862. /*++
  3863. Routine Description:
  3864. Registers the given callback function to
  3865. post setup progress events
  3866. Arguments:
  3867. Callback - The callback function
  3868. Context - Caller specified, context for the callback function
  3869. that needs to sent with each event
  3870. Return Value:
  3871. STATUS_SUCCESS if successful, otherwise appropriate
  3872. error code.
  3873. --*/
  3874. {
  3875. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  3876. if (Callback) {
  3877. if (ProgressSubscribersCount < MAX_SETUP_PROGRESS_SUBSCRIBERS) {
  3878. ProgressSubscribers[ProgressSubscribersCount].Callback = Callback;
  3879. ProgressSubscribers[ProgressSubscribersCount].Context = Context;
  3880. ProgressSubscribersCount++;
  3881. Callback(CallbackEvent, CallbackInitialize, Context, NULL);
  3882. Status = STATUS_SUCCESS;
  3883. } else {
  3884. Status = STATUS_NO_MEMORY;
  3885. }
  3886. }
  3887. return Status;
  3888. }
  3889. NTSTATUS
  3890. DeregisterSetupProgressCallback(
  3891. IN TM_SETUP_PROGRESS_CALLBACK Callback,
  3892. IN PVOID Context
  3893. )
  3894. /*++
  3895. Routine Description:
  3896. Deregisters the given callback function to
  3897. quit posting setup progress events
  3898. Arguments:
  3899. Callback - The callback function
  3900. Context - Caller specified, context for the callback function
  3901. that needs to sent with each event
  3902. Return Value:
  3903. STATUS_SUCCESS if successful, otherwise appropriate
  3904. error code.
  3905. --*/
  3906. {
  3907. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  3908. if (Callback) {
  3909. ULONG Index;
  3910. for (Index = 0; Index < MAX_SETUP_PROGRESS_SUBSCRIBERS; Index++) {
  3911. if (ProgressSubscribers[Index].Callback == Callback) {
  3912. ProgressSubscribers[Index].Callback = NULL;
  3913. ProgressSubscribers[Index].Context = NULL;
  3914. ProgressSubscribersCount--;
  3915. Index++;
  3916. //
  3917. // Compact the array
  3918. //
  3919. while ((Index < MAX_SETUP_PROGRESS_SUBSCRIBERS) &&
  3920. (ProgressSubscribers[Index].Callback)) {
  3921. ProgressSubscribers[Index - 1] = ProgressSubscribers[Index];
  3922. Index++;
  3923. }
  3924. //
  3925. // Indicate the callback is going away
  3926. //
  3927. Callback(CallbackEvent, CallbackDeInitialize, Context, NULL);
  3928. Status = STATUS_SUCCESS;
  3929. break;
  3930. }
  3931. }
  3932. }
  3933. return Status;
  3934. }
  3935. VOID
  3936. SendSetupProgressEvent(
  3937. IN TM_SETUP_MAJOR_EVENT MajorEvent,
  3938. IN TM_SETUP_MINOR_EVENT MinorEvent,
  3939. IN PVOID EventData
  3940. )
  3941. /*++
  3942. Routine Description:
  3943. Post the specified events and the associated data to
  3944. all the registered parties interested in setup progress
  3945. events.
  3946. Arguments:
  3947. MajorEvent - Setup progress major event
  3948. MinorEvent - Setup progress minor event, w.r.t to the
  3949. major event type
  3950. EventData - The associated event data with the specified
  3951. Major and Minor event pair
  3952. Return Value:
  3953. None.
  3954. --*/
  3955. {
  3956. ULONG Index;
  3957. for (Index = 0; Index < ProgressSubscribersCount; Index++) {
  3958. ASSERT(ProgressSubscribers[Index].Callback != NULL);
  3959. ProgressSubscribers[Index].Callback(MajorEvent,
  3960. MinorEvent,
  3961. ProgressSubscribers[Index].Context,
  3962. EventData);
  3963. }
  3964. }
  3965. ULONG
  3966. SpGetHeaderTextId(
  3967. VOID
  3968. )
  3969. /*++
  3970. Routine Description:
  3971. Retreives the appropriate product type title id based on the system.
  3972. Arguments:
  3973. None.
  3974. Return Value:
  3975. Text ID for the product. This ID may be found in usetup.exe
  3976. --*/
  3977. {
  3978. ULONG HeaderTextId;
  3979. if (AdvancedServer) {
  3980. HeaderTextId = SP_HEAD_SRV_SETUP;
  3981. if (SpIsProductSuite(VER_SUITE_BLADE)) {
  3982. HeaderTextId = SP_HEAD_BLA_SETUP;
  3983. }
  3984. if (SpIsProductSuite(VER_SUITE_SMALLBUSINESS_RESTRICTED)) {
  3985. HeaderTextId = SP_HEAD_SBS_SETUP;
  3986. }
  3987. if (SpIsProductSuite(VER_SUITE_ENTERPRISE)) {
  3988. HeaderTextId = SP_HEAD_ADS_SETUP;
  3989. }
  3990. if (SpIsProductSuite(VER_SUITE_DATACENTER)) {
  3991. HeaderTextId = SP_HEAD_DTC_SETUP;
  3992. }
  3993. } else {
  3994. HeaderTextId = SP_HEAD_PRO_SETUP;
  3995. if (SpIsProductSuite(VER_SUITE_PERSONAL)) {
  3996. HeaderTextId = SP_HEAD_PER_SETUP;
  3997. }
  3998. }
  3999. return(HeaderTextId);
  4000. }
  4001. NTSTATUS
  4002. SpGetVersionFromStr(
  4003. IN PWSTR VersionStr,
  4004. OUT PDWORD Version, // major * 100 + minor
  4005. OUT PDWORD BuildNumber
  4006. )
  4007. /*++
  4008. Routine Description:
  4009. Converts the given version string major.minor.build#.sp#
  4010. (e.g. 5.0.2195.1) to the two dwords
  4011. Arguments:
  4012. VersionStr : The version string
  4013. Version : Place holder for receiving major & minor version
  4014. (major * 100 + minor)
  4015. BuildNumber : Place holder for receiving build number
  4016. Return Value:
  4017. STATUS_SUCCESS if successful otherwise appropriate error code
  4018. --*/
  4019. {
  4020. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  4021. if (VersionStr && (Version || BuildNumber)) {
  4022. DWORD MajorVer = 0, MinorVer = 0, BuildNum = 0;
  4023. WCHAR *EndPtr = NULL;
  4024. WCHAR *EndChar = NULL;
  4025. WCHAR TempBuff[64] = {0};
  4026. EndPtr = wcschr(VersionStr, TEXT('.'));
  4027. if (EndPtr) {
  4028. wcsncpy(TempBuff, VersionStr, (EndPtr - VersionStr));
  4029. MajorVer = SpStringToLong(TempBuff, &EndChar, 10);
  4030. VersionStr = EndPtr + 1;
  4031. if (VersionStr) {
  4032. EndPtr = wcschr(VersionStr, TEXT('.'));
  4033. if (EndPtr) {
  4034. memset(TempBuff, 0, sizeof(TempBuff));
  4035. wcsncpy(TempBuff, VersionStr, (EndPtr - VersionStr));
  4036. MinorVer = SpStringToLong(TempBuff, &EndChar, 10);
  4037. VersionStr = EndPtr + 1;
  4038. if (VersionStr) {
  4039. EndPtr = wcschr(VersionStr, TEXT('.'));
  4040. if (EndPtr) {
  4041. memset(TempBuff, 0, sizeof(TempBuff));
  4042. wcsncpy(TempBuff, VersionStr, (EndPtr - VersionStr));
  4043. BuildNum = SpStringToLong(TempBuff, &EndChar, 10);
  4044. }
  4045. }
  4046. }
  4047. }
  4048. }
  4049. if ((MajorVer > 0) || (MinorVer > 0) || (BuildNum > 0))
  4050. Status = STATUS_SUCCESS;
  4051. if (NT_SUCCESS(Status)) {
  4052. if (Version)
  4053. *Version = (MajorVer * 100) + MinorVer;
  4054. if (BuildNumber)
  4055. *BuildNumber = BuildNum;
  4056. }
  4057. }
  4058. return Status;
  4059. }
  4060. NTSTATUS
  4061. SpQueryCanonicalName(
  4062. IN PWSTR Name,
  4063. IN ULONG MaxDepth,
  4064. OUT PWSTR CanonicalName,
  4065. IN ULONG SizeOfBufferInBytes
  4066. )
  4067. /*++
  4068. Routine Description:
  4069. Resolves the symbolic name to the specified depth. To resolve
  4070. a symbolic name completely specify the MaxDepth as -1
  4071. Arguments:
  4072. Name - Symbolic name to be resolved
  4073. MaxDepth - The depth till which the resolution needs to
  4074. be carried out
  4075. CanonicalName - The fully resolved name
  4076. SizeOfBufferInBytes - The size of the CanonicalName buffer in
  4077. bytes
  4078. Return Value:
  4079. Appropriate NT status code
  4080. --*/
  4081. {
  4082. UNICODE_STRING name, canonName;
  4083. OBJECT_ATTRIBUTES oa;
  4084. NTSTATUS status;
  4085. HANDLE handle;
  4086. ULONG CurrentDepth;
  4087. RtlInitUnicodeString(&name, Name);
  4088. canonName.MaximumLength = (USHORT) (SizeOfBufferInBytes - sizeof(WCHAR));
  4089. canonName.Length = 0;
  4090. canonName.Buffer = CanonicalName;
  4091. if (name.Length >= canonName.MaximumLength) {
  4092. return STATUS_BUFFER_TOO_SMALL;
  4093. }
  4094. RtlCopyMemory(canonName.Buffer, name.Buffer, name.Length);
  4095. canonName.Length = name.Length;
  4096. canonName.Buffer[canonName.Length/sizeof(WCHAR)] = 0;
  4097. for (CurrentDepth = 0; CurrentDepth < MaxDepth; CurrentDepth++) {
  4098. InitializeObjectAttributes(&oa, &canonName, OBJ_CASE_INSENSITIVE, 0, 0);
  4099. status = ZwOpenSymbolicLinkObject(&handle,
  4100. READ_CONTROL | SYMBOLIC_LINK_QUERY,
  4101. &oa);
  4102. if (!NT_SUCCESS(status)) {
  4103. break;
  4104. }
  4105. status = ZwQuerySymbolicLinkObject(handle, &canonName, NULL);
  4106. ZwClose(handle);
  4107. if (!NT_SUCCESS(status)) {
  4108. return status;
  4109. }
  4110. canonName.Buffer[canonName.Length/sizeof(WCHAR)] = 0;
  4111. }
  4112. return STATUS_SUCCESS;
  4113. }
  4114. NTSTATUS
  4115. SpIterateMountMgrMountPoints(
  4116. IN PVOID Context,
  4117. IN SPMOUNTMGR_ITERATION_CALLBACK Callback
  4118. )
  4119. /*++
  4120. Routine Description:
  4121. Iterates through all the mount points acquired from mountmgr
  4122. and calls the call back function for each mount point.
  4123. Arguments:
  4124. Context : Context that needs to be passed on to the caller
  4125. across iterations
  4126. Callback : The function that needs to be called back for
  4127. each mount point.
  4128. Return Value:
  4129. Appropriate NT status code
  4130. --*/
  4131. {
  4132. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  4133. OBJECT_ATTRIBUTES ObjAttrs;
  4134. UNICODE_STRING UnicodeString;
  4135. HANDLE MountMgrHandle;
  4136. IO_STATUS_BLOCK IoStatusBlock;
  4137. if (Callback) {
  4138. INIT_OBJA(&ObjAttrs, &UnicodeString, MOUNTMGR_DEVICE_NAME);
  4139. //
  4140. // Open the mountmgr
  4141. //
  4142. Status = ZwOpenFile(&MountMgrHandle,
  4143. (ACCESS_MASK)(FILE_GENERIC_READ),
  4144. &ObjAttrs,
  4145. &IoStatusBlock,
  4146. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE ,
  4147. FILE_NON_DIRECTORY_FILE);
  4148. if (NT_SUCCESS(Status)) {
  4149. MOUNTMGR_MOUNT_POINT MountPoint;
  4150. ULONG BufferLength = 0;
  4151. PVOID Buffer = NULL;
  4152. Status = STATUS_BUFFER_OVERFLOW;
  4153. RtlZeroMemory(&MountPoint, sizeof(MOUNTMGR_MOUNT_POINT));
  4154. while (Status == STATUS_BUFFER_OVERFLOW) {
  4155. if (Buffer) {
  4156. BufferLength = ((PMOUNTMGR_MOUNT_POINTS)Buffer)->Size;
  4157. SpMemFree(Buffer);
  4158. } else {
  4159. BufferLength += (8 * 1024); // start with 8K
  4160. }
  4161. //
  4162. // Allocate the output buffer
  4163. //
  4164. Buffer = SpMemAlloc(BufferLength);
  4165. if (!Buffer) {
  4166. Status = STATUS_NO_MEMORY;
  4167. break; // ran out of memory
  4168. }
  4169. RtlZeroMemory(Buffer, BufferLength);
  4170. //
  4171. // Get the mount points
  4172. //
  4173. Status = ZwDeviceIoControlFile(MountMgrHandle,
  4174. NULL,
  4175. NULL,
  4176. NULL,
  4177. &IoStatusBlock,
  4178. IOCTL_MOUNTMGR_QUERY_POINTS,
  4179. &MountPoint,
  4180. sizeof(MOUNTMGR_MOUNT_POINT),
  4181. Buffer,
  4182. BufferLength);
  4183. }
  4184. if (NT_SUCCESS(Status)) {
  4185. ULONG Index;
  4186. BOOLEAN Done = FALSE;
  4187. PMOUNTMGR_MOUNT_POINTS MountPoints = (PMOUNTMGR_MOUNT_POINTS)Buffer;
  4188. //
  4189. // Call the callback function for each mountpoint until the requester
  4190. // doesn't want to continue on.
  4191. //
  4192. for (Index=0; !Done && (Index < MountPoints->NumberOfMountPoints); Index++) {
  4193. Done = Callback(Context, MountPoints, MountPoints->MountPoints + Index);
  4194. }
  4195. }
  4196. //
  4197. // Free the allocated buffer
  4198. //
  4199. if (Buffer) {
  4200. SpMemFree(Buffer);
  4201. }
  4202. //
  4203. // Done with mountmgr handle
  4204. //
  4205. ZwClose(MountMgrHandle);
  4206. }
  4207. }
  4208. return Status;
  4209. }
  4210. NTSTATUS
  4211. SppLockBootStatusData(
  4212. OUT PHANDLE BootStatusDataHandle,
  4213. IN PDISK_REGION TargetRegion,
  4214. IN PWSTR SystemRoot
  4215. )
  4216. /*
  4217. This function has the same functionality as the RtlLockBootStatusData API except that
  4218. it doesn't point to SystemRoot. This is needed for textmode setup to open the
  4219. correct boot status data file on the installation we are upgrading.
  4220. We can still call the RtlUnlock routine as it operates on the handle.
  4221. */
  4222. {
  4223. OBJECT_ATTRIBUTES objectAttributes;
  4224. UNICODE_STRING fileName;
  4225. HANDLE dataFileHandle;
  4226. IO_STATUS_BLOCK ioStatusBlock;
  4227. NTSTATUS status;
  4228. PWSTR NtPartition;
  4229. //
  4230. // Get the name of the target patition.
  4231. //
  4232. SpNtNameFromRegion(
  4233. TargetRegion,
  4234. TemporaryBuffer,
  4235. sizeof(TemporaryBuffer),
  4236. PartitionOrdinalCurrent
  4237. );
  4238. SpConcatenatePaths(TemporaryBuffer,SystemRoot);
  4239. SpConcatenatePaths(TemporaryBuffer,L"bootstat.dat");
  4240. RtlInitUnicodeString(&fileName, TemporaryBuffer);
  4241. InitializeObjectAttributes(&objectAttributes,
  4242. &fileName,
  4243. OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  4244. NULL,
  4245. NULL);
  4246. status = ZwOpenFile(&dataFileHandle,
  4247. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  4248. &objectAttributes,
  4249. &ioStatusBlock,
  4250. 0,
  4251. FILE_SYNCHRONOUS_IO_NONALERT);
  4252. ASSERT(status != STATUS_PENDING);
  4253. if(NT_SUCCESS(status)) {
  4254. *BootStatusDataHandle = dataFileHandle;
  4255. } else {
  4256. *BootStatusDataHandle = NULL;
  4257. }
  4258. return status;
  4259. }
  4260. void
  4261. SpDisableCrashRecoveryForGuiMode(
  4262. IN PDISK_REGION TargetRegion,
  4263. IN PWSTR SystemRoot
  4264. )
  4265. /*
  4266. This function processes the Crash Recovery settings. Crash Recovery functions are
  4267. implemented as RTL functions. We try to call RtlLockBootStatusData to
  4268. see if there are settings already in place. If we get STATUS_OBJECT_NAME_NOT_FOUND we know there
  4269. weren't any settings before and we move on. If we succeed we save away the settings and then
  4270. disable the feature for GUI mode. At the end of GUI mode we migrate the settings
  4271. and re-enable crash recovery.
  4272. */
  4273. {
  4274. NTSTATUS Status;
  4275. HANDLE BootStatusData;
  4276. BOOLEAN Enabled = TRUE;
  4277. PWSTR szYes = L"Yes";
  4278. PWSTR szNo = L"No";
  4279. //We make this special call to lock the file as the RTL API looks at SystemRoot
  4280. //that points to ~bt in textmode setup.
  4281. Status = SppLockBootStatusData( &BootStatusData, TargetRegion, SystemRoot );
  4282. if(!NT_SUCCESS(Status)){
  4283. if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  4284. //Some other error occured
  4285. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpDisableCrashRecoveryForGuiMode() - RtlLockBootStatusData failed - Status = %lx \n", Status));
  4286. }
  4287. return;
  4288. }
  4289. // If we made it here we need to migrate the current settings.
  4290. Status = RtlGetSetBootStatusData(
  4291. BootStatusData,
  4292. TRUE,
  4293. RtlBsdItemAabEnabled,
  4294. &Enabled,
  4295. sizeof(BOOLEAN),
  4296. NULL
  4297. );
  4298. if(!NT_SUCCESS(Status)){
  4299. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpDisableCrashRecoveryForGuiMode() - RtlGetSetBootStatusData failed to get AabEnabled - Status = %lx \n", Status));
  4300. }
  4301. SpAddLineToSection(
  4302. WinntSifHandle,
  4303. SIF_DATA,
  4304. WINNT_D_CRASHRECOVERYENABLED_W,
  4305. Enabled ? &szYes : &szNo,
  4306. 1
  4307. );
  4308. // Finally disable Crash Recovery for Guimode setup
  4309. Enabled = FALSE;
  4310. Status = RtlGetSetBootStatusData(
  4311. BootStatusData,
  4312. FALSE,
  4313. RtlBsdItemAabEnabled,
  4314. &Enabled,
  4315. sizeof(BOOLEAN),
  4316. NULL
  4317. );
  4318. if(!NT_SUCCESS(Status)){
  4319. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpDisableCrashRecoveryForGuiMode() - RtlGetSetBootStatusData failed to set AabEnabled - Status = %lx \n", Status));
  4320. }
  4321. RtlUnlockBootStatusData( BootStatusData );
  4322. return;
  4323. }
  4324. #endif