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.

1025 lines
26 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. win31upg.c
  5. Abstract:
  6. Code for checking install into an existing win31 directory. This is
  7. only relevant on non ARC machines since Windows NT doesn't allow
  8. installation of Windows 3.1, therefore DOS is needed to install
  9. Windows 3.1.
  10. The Windows 3.1 directory can only exist on FAT volumes. However
  11. in the functions below we take care of this fact only implicitly
  12. by taking advantage of the fact that since the volumes are not
  13. cached, any file operation below will fail if it is on a non FAT
  14. volume.
  15. Author:
  16. Sunil Pai (sunilp) Nov-1992
  17. Revision History:
  18. Ted Miller (tedm) Sep-1993
  19. - reworked for new text setup.
  20. --*/
  21. #include "spprecmp.h"
  22. #pragma hdrstop
  23. // in win9xupg.c
  24. BOOLEAN
  25. SpIsWin9xMsdosSys(
  26. IN PDISK_REGION Region,
  27. OUT PSTR* Win9xPath
  28. );
  29. BOOLEAN
  30. SpIsDosConfigSys(
  31. IN PDISK_REGION Region
  32. );
  33. PUCHAR
  34. SpGetDosPath(
  35. IN PDISK_REGION Region
  36. );
  37. BOOLEAN
  38. SpIsWin31Dir(
  39. IN PDISK_REGION Region,
  40. IN PWSTR PathComponent,
  41. IN ULONG MinKB
  42. );
  43. VOID
  44. SpWin31DriveFull(
  45. IN PDISK_REGION Region,
  46. IN PWSTR DosPathComponent,
  47. IN ULONG MinKB
  48. );
  49. BOOLEAN
  50. SpConfirmWin31Upgrade(
  51. IN PDISK_REGION Region,
  52. IN PWSTR DosPathComponent
  53. );
  54. WCHAR
  55. SpExtractDriveLetter(
  56. IN PWSTR PathComponent
  57. );
  58. extern BOOLEAN DriveAssignFromA; //NEC98
  59. BOOLEAN
  60. SpLocateWin31(
  61. IN PVOID SifHandle,
  62. OUT PDISK_REGION *InstallRegion,
  63. OUT PWSTR *InstallPath,
  64. OUT PDISK_REGION *SystemPartitionRegion
  65. )
  66. /*++
  67. Routine Description:
  68. High level function to determine whether a windows directory exists
  69. and whether to install into that directory. Win31 directories
  70. can only be on FAT volumes.
  71. Arguments:
  72. SifHandle - supplies handle to loaded setup information file.
  73. InstallRegion - if this routine returns TRUE, then this returns a pointer
  74. to the region to install to.
  75. InstallPath - if this routine returns TRUE, then this returns a pointer
  76. to a buffer containing the path on the partition to install to.
  77. The caller must free this buffer with SpMemFree().
  78. SystemPartitionRegion - if this routine returns TRUE, then this returns
  79. a pointer to the region for the system partition (ie, C:).
  80. Return Value:
  81. TRUE if we are going to install into a win3.1 directory.
  82. FALSE otherwise.
  83. --*/
  84. {
  85. PDISK_REGION CColonRegion;
  86. PDISK_REGION Region;
  87. PDISK_REGION FoundRegion;
  88. PUCHAR DosPath;
  89. PWSTR FoundComponent;
  90. PWSTR *DosPathComponents;
  91. ULONG ComponentCount;
  92. ULONG i,j,pass;
  93. ULONG MinKB;
  94. BOOLEAN NoSpace;
  95. ULONG Space;
  96. BOOLEAN StartsWithDriveLetter;
  97. WCHAR chDeviceName[128]; //NEC98
  98. CLEAR_CLIENT_SCREEN();
  99. SpDisplayStatusText(SP_STAT_LOOKING_FOR_WIN31,DEFAULT_STATUS_ATTRIBUTE);
  100. if (!IsNEC_98) { //NEC98
  101. //
  102. // See if there is a valid C: already. If not, then silently fail.
  103. //
  104. CColonRegion = SpPtValidSystemPartition();
  105. if(!CColonRegion) {
  106. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: no C:, no windows 3.1!\n"));
  107. return(FALSE);
  108. }
  109. //
  110. // This is the system partition.
  111. //
  112. *SystemPartitionRegion = CColonRegion;
  113. //
  114. // Check the filesystem. If not FAT, then silently fail.
  115. //
  116. if(CColonRegion->Filesystem != FilesystemFat) {
  117. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: C: is not FAT, no windows 3.1!\n"));
  118. return(FALSE);
  119. }
  120. //
  121. // Check to see if there is enough free space, etc on C:.
  122. // If not, silently fail.
  123. //
  124. if(!SpPtValidateCColonFormat(SifHandle,NULL,CColonRegion,TRUE,NULL,NULL)) {
  125. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: C: not acceptable, no windows 3.1!\n"));
  126. return(FALSE);
  127. }
  128. } else { //NEC98
  129. //
  130. // Don'y see only C: on PC98.
  131. //
  132. CColonRegion = NULL;
  133. } //NEC98
  134. if (!IsNEC_98) { //NEC98
  135. //
  136. // Don't confuse Win95 with Win3.1 - we're looking only for Win3.1
  137. //
  138. if(SpIsWin9xMsdosSys(CColonRegion, &DosPath) )
  139. return(FALSE);
  140. //
  141. // Determine whether config.sys is for DOS.
  142. //
  143. if(!SpIsDosConfigSys(CColonRegion)) {
  144. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: config.sys not DOS; no windows 3.1!\n"));
  145. return(FALSE);
  146. }
  147. //
  148. // Get the DOS path.
  149. //
  150. DosPath = SpGetDosPath(CColonRegion);
  151. } else { //NEC98
  152. DosPath = NULL;
  153. wcscpy(chDeviceName+1,L":");
  154. for (i=0; i<(L'Z'-L'A'); i++) {
  155. chDeviceName[0] = (WCHAR)('A' + i);
  156. CColonRegion = SpRegionFromDosName(chDeviceName);
  157. if ( CColonRegion ) {
  158. if ( (CColonRegion->Filesystem != FilesystemFat) ||
  159. (SpIsWin9xMsdosSys(CColonRegion, &DosPath) ) ||
  160. (!SpIsDosConfigSys(CColonRegion)) ) {
  161. continue;
  162. }
  163. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: found config.sys on %s\n", chDeviceName));
  164. DosPath = SpGetDosPath(CColonRegion);
  165. if (DosPath) {
  166. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: found dos path on %s\n", chDeviceName));
  167. break;
  168. }
  169. }
  170. }
  171. } //NEC98
  172. if(!DosPath) {
  173. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: no dos path; no windows 3.1!\n"));
  174. return(FALSE);
  175. }
  176. //
  177. // Break up the DOS path into components.
  178. //
  179. SpGetEnvVarWComponents(DosPath,&DosPathComponents,&ComponentCount);
  180. if(!ComponentCount) {
  181. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: no components in dos path\n"));
  182. //
  183. // data structure still built even if no components
  184. //
  185. SpFreeEnvVarComponents(DosPathComponents);
  186. return(FALSE);
  187. }
  188. //
  189. // Search each one of the components and check to see if it is
  190. // a windows directory
  191. //
  192. FoundRegion = NULL;
  193. for(i=0; DosPathComponents[i] && !FoundRegion; i++) {
  194. Region = SpPathComponentToRegion(DosPathComponents[i]);
  195. if(Region) {
  196. //
  197. // Fetch the amount of free space required on the windows nt drive.
  198. //
  199. SpFetchDiskSpaceRequirements( SifHandle,
  200. Region->BytesPerCluster,
  201. &MinKB,
  202. NULL);
  203. //
  204. // See whether windows is in this directory on
  205. // the drive.
  206. //
  207. if(SpIsWin31Dir(Region,DosPathComponents[i],MinKB)) {
  208. FoundRegion = Region;
  209. FoundComponent = DosPathComponents[i];
  210. }
  211. }
  212. }
  213. //
  214. // The drive letters we are using in NT will not always match
  215. // those in use by DOS. So if we have not found the windows directory
  216. // yet, then try using every path component on every drive.
  217. //
  218. if(!FoundRegion) {
  219. for(i=0; i<HardDiskCount && !FoundRegion; i++) {
  220. for(pass=0; pass<2; pass++) {
  221. for( Region= ( pass
  222. ? PartitionedDisks[i].ExtendedDiskRegions
  223. : PartitionedDisks[i].PrimaryDiskRegions
  224. );
  225. Region;
  226. Region=Region->Next
  227. )
  228. {
  229. for(j=0; DosPathComponents[j] && !FoundRegion; j++) {
  230. //
  231. // Fetch the amount of free space required on the windows nt drive.
  232. //
  233. SpFetchDiskSpaceRequirements( SifHandle,
  234. Region->BytesPerCluster,
  235. &MinKB,
  236. NULL);
  237. if(SpIsWin31Dir(Region,DosPathComponents[j],MinKB)) {
  238. FoundRegion = Region;
  239. FoundComponent = DosPathComponents[j];
  240. }
  241. }
  242. }
  243. }
  244. }
  245. }
  246. //
  247. // If directory has been found, check space on the drive and and the
  248. // user if he wants to install into the directory.
  249. //
  250. if(FoundRegion) {
  251. StartsWithDriveLetter = (BOOLEAN)(SpExtractDriveLetter(FoundComponent) != 0);
  252. recheck:
  253. NoSpace = FALSE;
  254. if(FoundRegion->AdjustedFreeSpaceKB < MinKB) {
  255. //
  256. // There is not enough free space on this drive.
  257. // Determine if NT is there already. If so, we will
  258. // allow the user to remove to it make room.
  259. //
  260. if(SpIsNtOnPartition(FoundRegion)) {
  261. NoSpace = TRUE;
  262. } else {
  263. //
  264. // NT not there, no space, bail.
  265. //
  266. SpWin31DriveFull(FoundRegion,FoundComponent,MinKB);
  267. FoundRegion = NULL;
  268. }
  269. } else {
  270. //
  271. // There is enough free space, so just continue on.
  272. //
  273. ;
  274. }
  275. if(FoundRegion) {
  276. //
  277. // Ask the user if he wishes to install into this path.
  278. // If not, exit this routine.
  279. //
  280. if(SpConfirmWin31Upgrade(FoundRegion,FoundComponent)) {
  281. //
  282. // He wants to install into win3.1. If there's not enough space,
  283. // he'll have to delete nt installations first.
  284. //
  285. if(NoSpace) {
  286. WCHAR DriveSpec[3];
  287. BOOLEAN b;
  288. if(StartsWithDriveLetter) {
  289. DriveSpec[0] = FoundComponent[0];
  290. DriveSpec[1] = L':';
  291. DriveSpec[2] = 0;
  292. }
  293. b = SpAllowRemoveNt(
  294. FoundRegion,
  295. StartsWithDriveLetter ? DriveSpec : NULL,
  296. TRUE,
  297. SP_SCRN_REMOVE_NT_FILES_WIN31,
  298. &Space
  299. );
  300. if(b) {
  301. Region->FreeSpaceKB += Space/1024;
  302. Region->AdjustedFreeSpaceKB += Space/1024;
  303. //
  304. // Account for rounding error.
  305. //
  306. if((Space % 1024) >= 512) {
  307. (Region->FreeSpaceKB)++;
  308. (Region->AdjustedFreeSpaceKB)++;
  309. }
  310. goto recheck;
  311. } else {
  312. FoundRegion = NULL;
  313. }
  314. } else {
  315. //
  316. // There is enough space. Accept this partition.
  317. //
  318. ;
  319. }
  320. } else {
  321. FoundRegion = NULL;
  322. }
  323. }
  324. //
  325. // Do the disk configuration needed
  326. //
  327. if(FoundRegion) {
  328. if (!IsNEC_98) { //NEC98
  329. SpPtMakeRegionActive(CColonRegion);
  330. SpPtDoCommitChanges();
  331. } else {
  332. *SystemPartitionRegion = FoundRegion;
  333. } //NEC98
  334. *InstallRegion = FoundRegion;
  335. *InstallPath = SpDupStringW(FoundComponent+(StartsWithDriveLetter ? 2 : 0));
  336. ASSERT(*InstallPath);
  337. }
  338. }
  339. SpMemFree(DosPath);
  340. SpFreeEnvVarComponents(DosPathComponents);
  341. return((BOOLEAN)(FoundRegion != NULL));
  342. }
  343. VOID
  344. SpWin31DriveFull(
  345. IN PDISK_REGION Region,
  346. IN PWSTR DosPathComponent,
  347. IN ULONG MinKB
  348. )
  349. /*++
  350. Routine Description:
  351. Inform a user that Setup has found a previous Windows installation
  352. but is unable to install into the same path because the drive is too
  353. full. The user has the option to continue on and specify a new path
  354. or exit and create enough space.
  355. Arguments:
  356. Return Value:
  357. None. Function doesn't return if the user chooses to exit setup at
  358. this point. If the function returns, it is implicit that the user
  359. wants to continue on and specify a new path for Microsoft Windows NT.
  360. --*/
  361. {
  362. ULONG ValidKeys[3] = { KEY_F3,ASCI_CR,0 };
  363. ASSERT(Region->PartitionedSpace);
  364. while(1) {
  365. SpStartScreen(
  366. SP_SCRN_WIN31_DRIVE_FULL,
  367. 3,
  368. HEADER_HEIGHT+1,
  369. FALSE,
  370. FALSE,
  371. DEFAULT_ATTRIBUTE,
  372. //NEC98: Win3.x for NEC must be assign hard drive from A:
  373. ((!IsNEC_98 || DriveAssignFromA || (Region->DriveLetter < L'C'))
  374. ? Region->DriveLetter :
  375. Region->DriveLetter - 2),
  376. DosPathComponent + (SpExtractDriveLetter(DosPathComponent) ? 2 : 0),
  377. MinKB/1024
  378. );
  379. SpDisplayStatusOptions(
  380. DEFAULT_STATUS_ATTRIBUTE,
  381. SP_STAT_F3_EQUALS_EXIT,
  382. SP_STAT_ENTER_EQUALS_CONTINUE,
  383. 0
  384. );
  385. switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
  386. case KEY_F3:
  387. SpConfirmExit();
  388. break;
  389. case ASCI_CR:
  390. //
  391. // User wants to continue.
  392. //
  393. return;
  394. }
  395. }
  396. }
  397. BOOLEAN
  398. SpConfirmWin31Upgrade(
  399. IN PDISK_REGION Region,
  400. IN PWSTR DosPathComponent
  401. )
  402. /*++
  403. Routine Description:
  404. Inform a user that Setup has found a previous Windows installation.
  405. The user has the option to continue on and specify a new path
  406. or accept the windows 3.1 path.
  407. Arguments:
  408. Return Value:
  409. TRUE if the user wants to upgrade win3.1, FALSE if he wants
  410. to select a new path.
  411. --*/
  412. {
  413. ULONG ValidKeys[3] = { KEY_F3,ASCI_CR,0 };
  414. ULONG Mnemonics[2] = { MnemonicNewPath,0 };
  415. ASSERT(Region->PartitionedSpace);
  416. if(UnattendedOperation) {
  417. PWSTR p;
  418. p = SpGetSectionKeyIndex(UnattendedSifHandle,SIF_UNATTENDED,L"Win31Upgrade",0);
  419. if(p) {
  420. if(!_wcsicmp(p,L"yes")) {
  421. return(TRUE);
  422. } else {
  423. if(!_wcsicmp(p,L"no")) {
  424. return(FALSE);
  425. }
  426. // bogus value; user gets attended behavior.
  427. }
  428. } else {
  429. //
  430. // Not specified; default to no.
  431. //
  432. return(FALSE);
  433. }
  434. }
  435. while(1) {
  436. SpStartScreen(
  437. SP_SCRN_WIN31_UPGRADE,
  438. 3,
  439. HEADER_HEIGHT+1,
  440. FALSE,
  441. FALSE,
  442. DEFAULT_ATTRIBUTE,
  443. //NEC98: Win3.x for NEC must be assign hard drive from A:
  444. ((!IsNEC_98 || DriveAssignFromA || (Region->DriveLetter < L'C'))
  445. ? Region->DriveLetter :
  446. Region->DriveLetter - 2),
  447. DosPathComponent + (SpExtractDriveLetter(DosPathComponent) ? 2 : 0)
  448. );
  449. SpDisplayStatusOptions(
  450. DEFAULT_STATUS_ATTRIBUTE,
  451. SP_STAT_F3_EQUALS_EXIT,
  452. SP_STAT_ENTER_EQUALS_CONTINUE,
  453. SP_STAT_N_EQUALS_NEW_PATH,
  454. 0
  455. );
  456. switch(SpWaitValidKey(ValidKeys,NULL,Mnemonics)) {
  457. case KEY_F3:
  458. SpConfirmExit();
  459. break;
  460. case ASCI_CR:
  461. return(TRUE);
  462. default:
  463. //
  464. // Must have chosen n for new path.
  465. //
  466. return(FALSE);
  467. }
  468. }
  469. }
  470. BOOLEAN
  471. SpConfirmRemoveWin31(
  472. VOID
  473. )
  474. /*++
  475. Routine Description:
  476. Upgrading NT case:
  477. Tell the user that the NT he is upgrading is coexistent with the
  478. win31 path. Since this will remove Win3.1, confirm that this is OK.
  479. The options are to continue, which removes Win31, or exit setup.
  480. Not upgrading NT case:
  481. Tell the user that the path he entered is also the win31 dir.
  482. Since installing NT in there will remove Win31, confirm that this
  483. is OK. The options are to continue the win31 upgrade, exit setup,
  484. or choose a dofferent location.
  485. Arguments:
  486. Return Value:
  487. TRUE if the user wants to upgrade win3.1, FALSE if he wants
  488. to select a new path.
  489. --*/
  490. {
  491. ULONG ValidKeys[4] = { KEY_F3,0 };
  492. ULONG Mnemonics[3] = { MnemonicUpgrade,0,0 };
  493. ULONG c;
  494. if(NTUpgrade != UpgradeFull) {
  495. Mnemonics[1] = MnemonicNewPath;
  496. }
  497. while(1) {
  498. SpStartScreen(
  499. SP_SCRN_WIN31_REMOVE,
  500. 3,
  501. HEADER_HEIGHT+1,
  502. FALSE,
  503. FALSE,
  504. DEFAULT_ATTRIBUTE
  505. );
  506. SpDisplayStatusOptions(
  507. DEFAULT_STATUS_ATTRIBUTE,
  508. SP_STAT_F3_EQUALS_EXIT,
  509. SP_STAT_U_EQUALS_UPGRADE,
  510. 0,
  511. 0
  512. );
  513. if((c = SpWaitValidKey(ValidKeys,NULL,Mnemonics)) == KEY_F3) {
  514. SpConfirmExit();
  515. } else {
  516. c &= ~KEY_MNEMONIC;
  517. if(c == MnemonicUpgrade) {
  518. return(TRUE);
  519. }
  520. // new path
  521. return(FALSE);
  522. }
  523. }
  524. }
  525. BOOLEAN
  526. SpIsWin31Dir(
  527. IN PDISK_REGION Region,
  528. IN PWSTR PathComponent,
  529. IN ULONG MinKB
  530. )
  531. /*++
  532. Routine Description:
  533. To find out if the directory indicated on the region contains a
  534. Microsoft Windows 3.x installation.
  535. Arguments:
  536. Region - supplies pointer to disk region descriptor for region
  537. containing the directory to be checked.
  538. PathComponent - supplies a component of the dos path to search
  539. on the region. This is assumes to be in the form x:\dir.
  540. If it is not in this form, this routine will fail.
  541. MinKB - supplies the minimum size of the partition in KB.
  542. If the partition is not at least this large, then this
  543. routine will return false.
  544. Return Value:
  545. TRUE if this path contains a Microsoft Windows 3.x installation.
  546. FALSE otherwise.
  547. --*/
  548. {
  549. PWSTR files[] = { L"WIN.COM", L"WIN.INI", L"SYSTEM.INI" };
  550. PWCHAR OpenPath;
  551. ULONG SizeKB;
  552. ULONG remainder;
  553. BOOLEAN rc;
  554. LARGE_INTEGER temp;
  555. //
  556. // Assume failure.
  557. //
  558. rc = FALSE;
  559. //
  560. // If the partition is not FAT, then ignore it.
  561. //
  562. if(Region->PartitionedSpace && (Region->Filesystem == FilesystemFat)) {
  563. //
  564. // If the partition is not large enough, ignore it.
  565. // Calculate the size of the partition in KB.
  566. //
  567. temp.QuadPart = UInt32x32To64(
  568. Region->SectorCount,
  569. HardDisks[Region->DiskNumber].Geometry.BytesPerSector
  570. );
  571. SizeKB = RtlExtendedLargeIntegerDivide(temp,1024,&remainder).LowPart;
  572. if(remainder >= 512) {
  573. SizeKB++;
  574. }
  575. if(SizeKB >= MinKB) {
  576. OpenPath = SpMemAlloc(512*sizeof(WCHAR));
  577. //
  578. // Form the name of the partition.
  579. //
  580. SpNtNameFromRegion(Region,OpenPath,512*sizeof(WCHAR),PartitionOrdinalCurrent);
  581. //
  582. // Slap on the directory part of the path component.
  583. //
  584. SpConcatenatePaths(
  585. OpenPath,
  586. PathComponent + (SpExtractDriveLetter(PathComponent) ? 2 : 0)
  587. );
  588. //
  589. // Determine whether all the required files are present.
  590. //
  591. rc = SpNFilesExist(OpenPath,files,ELEMENT_COUNT(files),FALSE);
  592. if(rc) {
  593. //
  594. // Make sure this isn't a Windows 4.x installation.
  595. //
  596. rc = !SpIsWin4Dir(Region, PathComponent);
  597. }
  598. SpMemFree(OpenPath);
  599. }
  600. }
  601. return(rc);
  602. }
  603. BOOLEAN
  604. SpIsDosConfigSys(
  605. IN PDISK_REGION Region
  606. )
  607. {
  608. WCHAR OpenPath[512];
  609. HANDLE FileHandle,SectionHandle;
  610. ULONG FileSize;
  611. PVOID ViewBase;
  612. PUCHAR pFile,pFileEnd,pLineEnd;
  613. ULONG i;
  614. NTSTATUS Status;
  615. ULONG LineLen,KeyLen;
  616. PCHAR Keywords[] = { "MAXWAIT","PROTSHELL","RMSIZE","THREADS",
  617. "SWAPPATH","PROTECTONLY","IOPL", NULL };
  618. //
  619. // Form name of config.sys.
  620. //
  621. SpNtNameFromRegion(Region,OpenPath,sizeof(OpenPath),PartitionOrdinalCurrent);
  622. SpConcatenatePaths(OpenPath,L"config.sys");
  623. //
  624. // Open and map the file.
  625. //
  626. FileHandle = 0;
  627. Status = SpOpenAndMapFile(
  628. OpenPath,
  629. &FileHandle,
  630. &SectionHandle,
  631. &ViewBase,
  632. &FileSize,
  633. FALSE
  634. );
  635. if(!NT_SUCCESS(Status)) {
  636. return(FALSE);
  637. }
  638. pFile = ViewBase;
  639. pFileEnd = pFile + FileSize;
  640. //
  641. // This code must guard access to the config.sys buffer because the
  642. // buffer is memory mapped (an i/o error would raise an exception).
  643. // This code could be structured better, as it now works by returning
  644. // from the try body -- but performance isn't an issue so this is acceptable
  645. // because it is so darned convenient.
  646. //
  647. try {
  648. while(1) {
  649. //
  650. // Skip whitespace. If at end of file, then this is a DOS config.sys.
  651. //
  652. while((pFile < pFileEnd) && strchr(" \r\n\t",*pFile)) {
  653. pFile++;
  654. }
  655. if(pFile == pFileEnd) {
  656. return(TRUE);
  657. }
  658. //
  659. // Find the end of the current line.
  660. //
  661. pLineEnd = pFile;
  662. while((pLineEnd < pFileEnd) && !strchr("\r\n",*pLineEnd)) {
  663. pLineEnd++;
  664. }
  665. LineLen = pLineEnd - pFile;
  666. //
  667. // Now check the line against known non-DOS config.sys keywords.
  668. //
  669. for(i=0; Keywords[i]; i++) {
  670. KeyLen = strlen(Keywords[i]);
  671. if((KeyLen <= LineLen) && !_strnicmp(pFile,Keywords[i],KeyLen)) {
  672. return(FALSE);
  673. }
  674. }
  675. pFile = pLineEnd;
  676. }
  677. } finally {
  678. SpUnmapFile(SectionHandle,ViewBase);
  679. ZwClose(FileHandle);
  680. }
  681. }
  682. PUCHAR
  683. SpGetDosPath(
  684. IN PDISK_REGION Region
  685. )
  686. {
  687. WCHAR OpenPath[512];
  688. HANDLE FileHandle,SectionHandle;
  689. ULONG FileSize;
  690. PVOID ViewBase;
  691. PUCHAR pFile,pFileEnd,pLineEnd;
  692. PUCHAR PathSpec;
  693. ULONG l,i;
  694. NTSTATUS Status;
  695. //
  696. // Form name of autoexec.bat.
  697. //
  698. SpNtNameFromRegion(Region,OpenPath,sizeof(OpenPath),PartitionOrdinalCurrent);
  699. SpConcatenatePaths(OpenPath,L"autoexec.bat");
  700. //
  701. // Open and map the file.
  702. //
  703. FileHandle = 0;
  704. Status = SpOpenAndMapFile(
  705. OpenPath,
  706. &FileHandle,
  707. &SectionHandle,
  708. &ViewBase,
  709. &FileSize,
  710. FALSE
  711. );
  712. if(!NT_SUCCESS(Status)) {
  713. return(NULL);
  714. }
  715. pFile = ViewBase;
  716. pFileEnd = pFile + FileSize;
  717. PathSpec = SpMemAlloc(1);
  718. *PathSpec = 0;
  719. #define SKIP(s) while((pFile<pFileEnd)&&strchr(s,*pFile))pFile++;if(pFile==pFileEnd)return(PathSpec)
  720. //
  721. // This code must guard access to the autoexec.bat buffer because the
  722. // buffer is memory mapped (an i/o error would raise an exception).
  723. // This code could be structured better, as it now works by returning
  724. // from the try body -- but performance isn't an issue so this is acceptable
  725. // because it is so darned convenient.
  726. //
  727. try {
  728. while(1) {
  729. //
  730. // Skip whitespace. If at end of file, then we're done.
  731. //
  732. SKIP(" \t\r\n");
  733. //
  734. // Find the end of the current line.
  735. //
  736. pLineEnd = pFile;
  737. while((pLineEnd < pFileEnd) && !strchr("\r\n",*pLineEnd)) {
  738. pLineEnd++;
  739. }
  740. //
  741. // Skip the no echo symbol if present.
  742. //
  743. if(*pFile == '@') {
  744. pFile++;
  745. }
  746. SKIP(" \t");
  747. //
  748. // See if the line starts with "set." If so, skip it.
  749. // To be meaningful, the line must have at least 10
  750. // characters ("set path=x" is 10 chars).
  751. //
  752. if((pLineEnd - pFile >= 10) && !_strnicmp(pFile,"set",3)) {
  753. pFile += 3;
  754. }
  755. //
  756. // Skip whitespace.
  757. //
  758. SKIP(" \t");
  759. //
  760. // See if the line has "path" -- if so, we're in business.
  761. // To be meaningful, the line must have at least 5 characters
  762. // ("path x" or "path=x" is 6 chars).
  763. //
  764. if((pLineEnd - pFile >= 5) && !_strnicmp(pFile,"path",4)) {
  765. //
  766. // Skip PATH
  767. //
  768. pFile += 4;
  769. SKIP(" \t");
  770. if(*pFile == '=') {
  771. pFile++;
  772. }
  773. SKIP(" \t");
  774. //
  775. // Strip off trailing spaces.
  776. //
  777. while(strchr(" \t",*(pLineEnd-1))) {
  778. pLineEnd--;
  779. }
  780. //
  781. // The rest of the line is the path. Append it to
  782. // what we have so far.
  783. //
  784. l = strlen(PathSpec);
  785. PathSpec = SpMemRealloc(PathSpec,pLineEnd-pFile+l+2);
  786. if(l) {
  787. PathSpec[l++] = ';';
  788. }
  789. for(i=0; i<(ULONG)(pLineEnd-pFile); i++) {
  790. PathSpec[l+i] = pFile[i];
  791. }
  792. PathSpec[l+i] = 0;
  793. }
  794. pFile = pLineEnd;
  795. }
  796. } finally {
  797. SpUnmapFile(SectionHandle,ViewBase);
  798. ZwClose(FileHandle);
  799. }
  800. }
  801. VOID
  802. SpRemoveWin31(
  803. IN PDISK_REGION NtPartitionRegion,
  804. IN LPCWSTR Sysroot
  805. )
  806. {
  807. LPWSTR p,q;
  808. p = SpMemAlloc(500);
  809. q = SpMemAlloc(500);
  810. //
  811. // Rename win.com to wincom.w31. Delete wincom.w31 first.
  812. //
  813. SpNtNameFromRegion(NtPartitionRegion,p,500,PartitionOrdinalCurrent);
  814. SpConcatenatePaths(p,Sysroot);
  815. wcscpy(q,p);
  816. SpConcatenatePaths(p,L"WIN.COM");
  817. SpConcatenatePaths(q,L"WINCOM.W31");
  818. SpDeleteFile(q,NULL,NULL);
  819. SpRenameFile(p,q,FALSE);
  820. SpMemFree(q);
  821. SpMemFree(p);
  822. }