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.

2038 lines
54 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. dnboot.c
  5. Abstract:
  6. Routines for booting to NT text-mode setup.
  7. Author:
  8. Ted Miller (tedm) 2-April-1992
  9. Revision History:
  10. --*/
  11. #include "winnt.h"
  12. #include <errno.h>
  13. #include <stdlib.h>
  14. #include <dos.h>
  15. #include <string.h>
  16. #include <time.h>
  17. #include <direct.h>
  18. #include <fcntl.h>
  19. #include <share.h>
  20. #if NEC_98
  21. #include <memory.h>
  22. #include <io.h>
  23. extern USHORT FirstFD; // 1'st Floppy Drive No
  24. #endif // NEC_98
  25. //
  26. // This header file contains an array of 512 bytes
  27. // representing the NT FAT boot code, in a variable
  28. // of type unsigned char[] called FatBootCode.
  29. //
  30. #define _FAT32
  31. #if NEC_98
  32. #include <boot98f.h>
  33. #ifdef _FAT32
  34. #include <boot98f2.h>
  35. #endif
  36. #else
  37. #include <bootfat.h>
  38. #ifdef _FAT32
  39. #include <bootf32.h>
  40. #endif
  41. #endif // NEC_98
  42. #if NEC_98
  43. #define FLOPPY_CAPACITY_525 1250304L
  44. #else // NEC_98
  45. #define FLOPPY_CAPACITY_525 1213952L
  46. #endif // NEC_98
  47. #define FLOPPY_CAPACITY_35 1457664L
  48. #ifdef ALLOW_525
  49. #define FLOPPY_CAPACITY FLOPPY_CAPACITY_525
  50. #else
  51. #define FLOPPY_CAPACITY FLOPPY_CAPACITY_35
  52. #endif
  53. #define SECTOR_SIZE 512
  54. //
  55. // Old int13 vector. See Int13Hook(), below.
  56. //
  57. void (_interrupt _far *OldInt13Vector)();
  58. #if NEC_98
  59. extern USHORT Cylinders; // For Dos 3.x format
  60. extern UCHAR TargetDA_UA;
  61. #endif // NEC_98
  62. #pragma pack(1)
  63. //
  64. // Define bpb structure.
  65. //
  66. typedef struct _MY_BPB {
  67. USHORT BytesPerSector;
  68. UCHAR SectorsPerCluster;
  69. USHORT ReservedSectors;
  70. UCHAR FatCount;
  71. USHORT RootDirectoryEntries;
  72. USHORT SectorCountSmall;
  73. UCHAR MediaDescriptor;
  74. USHORT SectorsPerFat;
  75. USHORT SectorsPerTrack;
  76. USHORT HeadCount;
  77. } MY_BPB, *PMY_BPB;
  78. //
  79. // Define device params structure.
  80. //
  81. typedef struct _MY_DEVICE_PARAMS {
  82. UCHAR SpecialFunctions;
  83. UCHAR DeviceType;
  84. USHORT DeviceAttributes;
  85. USHORT CylinderCount;
  86. UCHAR MediaType;
  87. MY_BPB Bpb;
  88. ULONG HiddenSectors;
  89. ULONG SectorCountLarge;
  90. ULONG Padding[5]; // in case the struct grows in later dos versions!
  91. } MY_DEVICE_PARAMS, *PMY_DEVICE_PARAMS;
  92. //
  93. // Define read write block request for ioctl call.
  94. //
  95. typedef struct _MY_READWRITE_BLOCK {
  96. UCHAR SpecialFunctions;
  97. USHORT Head;
  98. USHORT Cylinder;
  99. USHORT FirstSector;
  100. USHORT SectorCount;
  101. VOID _far *Buffer;
  102. } MY_READWRITE_BLOCK, *PMY_READWRITE_BLOCK;
  103. #pragma pack()
  104. VOID
  105. DnInstallNtBoot(
  106. IN unsigned Drive // 0=A, etc
  107. );
  108. unsigned
  109. DnpScanBootSector(
  110. IN PUCHAR BootSector,
  111. IN PUCHAR Pattern
  112. );
  113. BOOLEAN
  114. DnpAreAllFilesPresent(
  115. IN CHAR DriveLetter,
  116. IN PCHAR FileList[]
  117. );
  118. BOOLEAN
  119. DnpHasMZHeader(
  120. IN CHAR DriveLetter,
  121. IN PCHAR Filename
  122. );
  123. BOOLEAN
  124. DnpInstallNtBootSector(
  125. IN unsigned Drive, // 0=A, etc.
  126. IN OUT PUCHAR BootSector,
  127. OUT PCHAR *PreviousOsText
  128. );
  129. #if NEC_98
  130. VOID RestoreBootcode(VOID);
  131. #endif // NEC_98
  132. PCHAR MsDosFileList[] = { "?:\\MSDOS.SYS", "?:\\IO.SYS", NULL };
  133. //
  134. // Some versions of PC-DOS have ibmio.com, others have ibmbio.com.
  135. //
  136. //PCHAR PcDosFileList[] = { "?:\\IBMDOS.COM", "?:\\IBMIO.COM", NULL };
  137. #if NEC_98
  138. #else // NEC_98
  139. PCHAR PcDosFileList[] = { "?:\\IBMDOS.COM", NULL };
  140. #endif
  141. PCHAR Os2FileList[] = { "?:\\OS2LDR", "?:\\OS2KRNL", NULL };
  142. void
  143. _interrupt
  144. _far
  145. Int13Hook(
  146. unsigned _es,
  147. unsigned _ds,
  148. unsigned _di,
  149. unsigned _si,
  150. unsigned _bp,
  151. unsigned _sp,
  152. unsigned _bx,
  153. unsigned _dx,
  154. unsigned _cx,
  155. unsigned _ax,
  156. unsigned _ip,
  157. unsigned _cs,
  158. unsigned _flags
  159. )
  160. /*++
  161. Routine Description:
  162. We have encountered machines which cannot seem to create the floppies
  163. successfully. The user sees strange error messages about how the disk is
  164. not blank, etc even when the disk should be perfectly acceptable.
  165. To compensate for machines with broken change lines, we will hook int13
  166. to force a disk change error on the very next int13 call after the user
  167. has inserted a new disk.
  168. The logic is simple: when we first start to make the boot floppies, we save
  169. away the int13 vector. Then right after the user presses return at
  170. a disk prompt (ie, when he confirms the presence of a new floppy in the drive),
  171. which is right before we do a getbpb call, we set a new int13 vector.
  172. The int13 hook simply unhooks itself and returns the disk change error.
  173. This should force dos to recognize the new disk at the proper times.
  174. Arguments:
  175. Registers pushed on stack as per spec of _interrupt-type functions.
  176. Return Value:
  177. None. We modify the ax and flags registers return values.
  178. --*/
  179. {
  180. //
  181. // Unhook ourselves.
  182. //
  183. #if NEC_98
  184. _dos_setvect(0x1b,OldInt13Vector);
  185. #else // NEC_98
  186. _dos_setvect(0x13,OldInt13Vector);
  187. #endif // NEC_98
  188. //
  189. // Force disk changed error.
  190. //
  191. _asm {
  192. mov _ax,0x600
  193. or word ptr _flags,1
  194. }
  195. }
  196. VOID
  197. DnpFlushBuffers(
  198. IN BOOLEAN TellUser
  199. )
  200. /*++
  201. Routine Description:
  202. Flush disk buffers.
  203. Arguments:
  204. TellUser - if TRUE, we clear the screen and put up a message
  205. telling the user that we are flushing files. Otherwise
  206. this routine doesn't touch the screen.
  207. Return Value:
  208. None.
  209. --*/
  210. {
  211. if(TellUser) {
  212. DnClearClientArea();
  213. DnWriteStatusText(DntFlushingData);
  214. }
  215. _asm {
  216. pusha
  217. mov ah,0xd
  218. int 21h
  219. popa
  220. }
  221. }
  222. VOID
  223. DnToNtSetup(
  224. VOID
  225. )
  226. /*++
  227. Routine Description:
  228. Launch NT text-mode setup.
  229. Make sure the boot floppy we created is in the drive and reboot the
  230. machine.
  231. Arguments:
  232. None.
  233. Return Value:
  234. None. Does not return.
  235. --*/
  236. {
  237. ULONG ValidKey[2];
  238. DnpFlushBuffers(TRUE);
  239. //
  240. // Make sure the setup boot floppy we created is in the drive
  241. // if necessary.
  242. //
  243. if(!DngUnattended) {
  244. DnClearClientArea();
  245. if(DngWindows) {
  246. DnDisplayScreen(
  247. DngFloppyless
  248. ? &DnsAboutToExitX
  249. : (DngServer ? &DnsAboutToExitS : &DnsAboutToExitW)
  250. );
  251. } else {
  252. DnDisplayScreen(
  253. DngFloppyless
  254. ? &DnsAboutToRebootX
  255. : (DngServer ? &DnsAboutToRebootS : &DnsAboutToRebootW)
  256. );
  257. }
  258. DnWriteStatusText(DntEnterEqualsContinue);
  259. ValidKey[0] = ASCI_CR;
  260. ValidKey[1] = 0;
  261. DnGetValidKey(ValidKey);
  262. }
  263. //
  264. // Reboot the machine unless we are being run on Windows.
  265. // In that case, there should be a wrapper program that will shut down
  266. // the system using the Windows API -- our attempt to shut down using the
  267. // usual method will fail.
  268. //
  269. if(!DngWindows) {
  270. DnaReboot();
  271. }
  272. }
  273. BOOLEAN
  274. DnIndicateWinnt(
  275. IN PCHAR Directory
  276. )
  277. {
  278. PCHAR WinntData = WINNT_DATA_A;
  279. PCHAR WinntAccess = WINNT_ACCESSIBILITY_A;
  280. PCHAR WinntMsdos = WINNT_D_MSDOS_A;
  281. PCHAR WinntSif = WINNT_SIF_FILE_A;
  282. PCHAR WinntFloppy = WINNT_D_FLOPPY_A;
  283. PCHAR WinntUnattended = WINNT_UNATTENDED_A;
  284. PCHAR WinntOne = WINNT_A_ONE;
  285. PCHAR WinntZero = WINNT_A_ZERO;
  286. PCHAR WinntUpgrade = WINNT_U_NTUPGRADE;
  287. PCHAR WinntYes = WINNT_A_YES;
  288. PVOID InfHandle;
  289. PVOID UnattendHandle;
  290. PCHAR FileName;
  291. PCHAR p;
  292. PCHAR OptionalDirString;
  293. unsigned OptionalDirLength = 0;
  294. unsigned u,l;
  295. FILE *f;
  296. int Status;
  297. PCHAR SectionName;
  298. unsigned LineNumber;
  299. CHAR ServerAndShare[128];
  300. BOOLEAN AccessibleSetup = FALSE;
  301. CHAR AccessibleScriptFile[] = "setupacc.txt";
  302. //
  303. // Allocate a new INF file buffer
  304. //
  305. InfHandle = DnNewSetupTextFile();
  306. if (InfHandle == NULL) {
  307. return (FALSE);
  308. }
  309. //
  310. // Build the default file name
  311. //
  312. FileName = MALLOC(strlen(Directory)+strlen(WinntSif)+2,TRUE);
  313. if(FileName == NULL) {
  314. DnFreeINFBuffer( InfHandle );
  315. return FALSE;
  316. }
  317. //
  318. // Display to the user what we are doing
  319. //
  320. DnWriteStatusText(DntPreparingData);
  321. //
  322. // Build the name of the file we wish to save the INF file as
  323. //
  324. strcpy(FileName,Directory);
  325. strcat(FileName,"\\");
  326. strcat(FileName,WinntSif);
  327. //
  328. // Handle Accessibility utilities
  329. //
  330. if(DngMagnifier) {
  331. DnAddLineToSection(
  332. InfHandle,
  333. WinntAccess,
  334. WINNT_D_ACC_MAGNIFIER,
  335. &WinntOne,
  336. 1);
  337. AccessibleSetup = TRUE;
  338. }
  339. if(DngTalker) {
  340. DnAddLineToSection(
  341. InfHandle,
  342. WinntAccess,
  343. WINNT_D_ACC_READER,
  344. &WinntOne,
  345. 1);
  346. AccessibleSetup = TRUE;
  347. }
  348. if(DngKeyboard) {
  349. DnAddLineToSection(
  350. InfHandle,
  351. WinntAccess,
  352. WINNT_D_ACC_KEYBOARD,
  353. &WinntOne,
  354. 1);
  355. AccessibleSetup = TRUE;
  356. }
  357. if(AccessibleSetup && !DngUnattended) {
  358. DngUnattended = TRUE;
  359. DngScriptFile = MALLOC(strlen(DngSourceRootPath) +
  360. strlen(AccessibleScriptFile) + 2, TRUE);
  361. if(DngScriptFile == NULL) {
  362. DnFatalError(&DnsOutOfMemory);
  363. }
  364. strcpy(DngScriptFile,DngSourceRootPath);
  365. strcat(DngScriptFile,"\\");
  366. strcat(DngScriptFile,AccessibleScriptFile);
  367. }
  368. //
  369. // Append script file if necessary.
  370. // Do this processing first because we want to be able to
  371. // override anything that the user sets in the unattend file
  372. // that the user has no business setting
  373. //
  374. if(DngUnattended) {
  375. if(DngScriptFile) {
  376. //
  377. // First open the script file as a dos file
  378. //
  379. f = fopen(DngScriptFile,"rt");
  380. if(f == NULL) {
  381. //
  382. // fatal error.
  383. //
  384. DnFatalError(&DnsOpenReadScript);
  385. }
  386. //
  387. // Now open it as a INF file
  388. //
  389. LineNumber = 0;
  390. Status = DnInitINFBuffer (f, &UnattendHandle, &LineNumber);
  391. fclose(f);
  392. if(Status == ENOMEM) {
  393. DnFatalError(&DnsOutOfMemory);
  394. } else if(Status) {
  395. DnFatalError(&DnsParseScriptFile, DngScriptFile, LineNumber);
  396. }
  397. //
  398. // Process all of the section names
  399. //
  400. for( SectionName = NULL;
  401. ((SectionName = DnGetSectionName( UnattendHandle )) != NULL);
  402. ) {
  403. //
  404. // We won't allow the data section or the [OemBootFiles]
  405. // to be copied
  406. //
  407. if ((strcmpi(WinntData,SectionName) != 0) &&
  408. (strcmpi(WINNT_OEMBOOTFILES,SectionName) != 0)
  409. ) {
  410. //
  411. // Copy the sections from the Unattend INF
  412. // to the Main INF
  413. //
  414. DnCopySetupTextSection(
  415. UnattendHandle,
  416. InfHandle,
  417. SectionName);
  418. }
  419. FREE (SectionName);
  420. }
  421. //
  422. // We no longer need the unattend inf file at this point
  423. //
  424. DnFreeINFBuffer( UnattendHandle );
  425. }
  426. if(!DngScriptFile) {
  427. //
  428. // No script. Put a dummy [Unattended] section in there.
  429. //
  430. DnAddLineToSection(InfHandle,WinntUnattended,"unused",&WinntZero,1);
  431. }
  432. }
  433. //
  434. // Add the default line to the inf
  435. //
  436. DnAddLineToSection(
  437. InfHandle,
  438. WinntData,
  439. WinntMsdos,
  440. &WinntOne,
  441. 1);
  442. //
  443. // Set the floppy flags
  444. //
  445. if(DngFloppyless) {
  446. DnAddLineToSection(
  447. InfHandle,
  448. WinntData,
  449. WinntFloppy,
  450. &WinntOne,
  451. 1);
  452. } else {
  453. DnAddLineToSection(
  454. InfHandle,
  455. WinntData,
  456. WinntFloppy,
  457. &WinntZero,
  458. 1);
  459. }
  460. //
  461. // Remember udf info
  462. //
  463. if(UniquenessId) {
  464. DnAddLineToSection(
  465. InfHandle,
  466. WinntData,
  467. WINNT_D_UNIQUENESS,
  468. &UniquenessId,
  469. 1);
  470. }
  471. //
  472. // Write info about original source.
  473. //
  474. // We only distinguish here between remote and CD-ROM.
  475. // If it doesn't appear to be a remote drive, either by
  476. // being UNC or a redirected local drive, then we assume
  477. // it's a CD-ROM drive (this behavior is intended to force
  478. // GUI Setup to locate a valid CD-ROM if one is available).
  479. // Because we have no idea what the drive letters will be
  480. // on NT, we always write A: in there.
  481. //
  482. #define DRIVE_REMOTE 4
  483. #define DRIVE_CDROM 5
  484. u = DRIVE_CDROM;
  485. if(DngOemPreInstall) {
  486. //
  487. // Preinstall case, force GUI Setup to locate a CD-ROM drive
  488. // and assume the I386 directory is on the root of the CD
  489. // (that's how we ship the retail CDs).
  490. //
  491. strcpy(ServerAndShare,"A:\\I386");
  492. } else {
  493. if(DngSourceRootPath[0] == '\\') {
  494. //
  495. // UNC path. change drive type to remote and remember
  496. // the entire path.
  497. //
  498. u = DRIVE_REMOTE;
  499. strcpy(ServerAndShare,DngSourceRootPath);
  500. } else {
  501. //
  502. // Assume fully-qualified path starting with a drive letter.
  503. //
  504. if(DnIsDriveRemote((unsigned)DngSourceRootPath[0]+1-(unsigned)'A',ServerAndShare)) {
  505. //
  506. // It's a redirected network drive.
  507. //
  508. if(ServerAndShare[0]) {
  509. //
  510. // Change type to remote drive. ServerAndShare has the
  511. // \\server\share, to which we append the rest of the path, below.
  512. //
  513. u = DRIVE_REMOTE;
  514. } else {
  515. //
  516. // Strange case where we can't resolve the local drive letter
  517. // to its server and share. Leave as CD-ROM.
  518. //
  519. ServerAndShare[0] = 'A';
  520. ServerAndShare[1] = ':';
  521. ServerAndShare[2] = 0;
  522. }
  523. strcat(ServerAndShare,DngSourceRootPath+2);
  524. } else {
  525. //
  526. // Not a network drive. Assume CD-ROM.
  527. //
  528. strcpy(ServerAndShare,DngSourceRootPath);
  529. ServerAndShare[0] = 'A';
  530. }
  531. }
  532. }
  533. p = ServerAndShare;
  534. DnAddLineToSection(InfHandle,WinntData,WINNT_D_ORI_SRCPATH,&p,1);
  535. sprintf(p,"%u",u);
  536. DnAddLineToSection(InfHandle,WinntData,WINNT_D_ORI_SRCTYPE,&p,1);
  537. if(CmdToExecuteAtEndOfGui) {
  538. DnAddLineToSection(InfHandle,WINNT_SETUPPARAMS,WINNT_S_USEREXECUTE,&CmdToExecuteAtEndOfGui,1);
  539. }
  540. if(OptionalDirCount) {
  541. //
  542. // If an optional dir string is present then we want to generate
  543. // and entry in the sif file that contains a line with the dir
  544. // string in the form of dir1*dir2*...*dirn
  545. //
  546. OptionalDirString = NULL;
  547. for(u=0; u<OptionalDirCount; u++) {
  548. if( ( OptionalDirFlags[u] & OPTDIR_OEMOPT ) ||
  549. ( OptionalDirFlags[u] & OPTDIR_OEMSYS ) ) {
  550. continue;
  551. }
  552. if(!(OptionalDirFlags[u] & OPTDIR_TEMPONLY)) {
  553. p = OptionalDirs[u];
  554. if(OptionalDirLength == 0) {
  555. //
  556. // We haven't allocated any memory yet...
  557. //
  558. OptionalDirString = MALLOC((strlen(p)+2) * sizeof(CHAR),TRUE);
  559. strcpy(OptionalDirString,p);
  560. } else {
  561. //
  562. // This is the original case that should be used in the
  563. // release version of the product. We use a REALLOC because
  564. // it is more memory conservative then using 2 MALLOCs
  565. //
  566. OptionalDirString = REALLOC(
  567. OptionalDirString,
  568. (strlen(p) + 2 + OptionalDirLength) * sizeof(CHAR),TRUE);
  569. strcat(OptionalDirString,p);
  570. }
  571. strcat(OptionalDirString,"*");
  572. OptionalDirLength = strlen(OptionalDirString);
  573. }
  574. }
  575. if(OptionalDirString) {
  576. //
  577. // Remove trailing * if any
  578. //
  579. l = strlen(OptionalDirString);
  580. if(l && (OptionalDirString[l-1] == '*')) {
  581. OptionalDirString[l-1] = 0;
  582. }
  583. DnAddLineToSection(
  584. InfHandle,
  585. WINNT_SETUPPARAMS,
  586. WINNT_S_OPTIONALDIRS,
  587. &OptionalDirString,
  588. 1);
  589. FREE(OptionalDirString);
  590. }
  591. OptionalDirLength = 0;
  592. }
  593. //
  594. // Display a message to the user about what we are doing
  595. //
  596. DnWriteStatusText(DngFloppyless ? DntWritingData : DntConfiguringFloppy);
  597. //
  598. // Write the file to disk
  599. //
  600. Status = (int) DnWriteSetupTextFile(InfHandle,FileName);
  601. //
  602. // Free the memory used by the INF structure
  603. //
  604. DnFreeINFBuffer(InfHandle);
  605. FREE(FileName);
  606. return ((BOOLEAN) Status);
  607. }
  608. VOID
  609. DnPromptAndInspectFloppy(
  610. IN PSCREEN FirstPromptScreen,
  611. IN PSCREEN SubsequentPromptScreen,
  612. OUT PMY_BPB Bpb
  613. )
  614. {
  615. ULONG ValidKey[3];
  616. ULONG c;
  617. MY_DEVICE_PARAMS DeviceParams;
  618. union REGS RegistersIn,RegistersOut;
  619. PSCREEN PromptScreen,ErrorScreen;
  620. struct diskfree_t DiskSpace;
  621. ULONG FreeSpace;
  622. struct find_t FindData;
  623. #if NEC_98
  624. UCHAR FddNo;
  625. UCHAR TextInf[32];
  626. UCHAR AlReg;
  627. #endif // NEC_98
  628. PromptScreen = FirstPromptScreen;
  629. ValidKey[0] = ASCI_CR;
  630. ValidKey[1] = DN_KEY_F3;
  631. ValidKey[2] = 0;
  632. do {
  633. DnClearClientArea();
  634. DnDisplayScreen(PromptScreen);
  635. DnWriteStatusText("%s %s",DntEnterEqualsContinue,DntF3EqualsExit);
  636. PromptScreen = SubsequentPromptScreen;
  637. ErrorScreen = NULL;
  638. while(1) {
  639. c = DnGetValidKey(ValidKey);
  640. if(c == ASCI_CR) {
  641. break;
  642. }
  643. if(c == DN_KEY_F3) {
  644. DnExitDialog();
  645. }
  646. }
  647. DnClearClientArea();
  648. DnWriteStatusText(DntConfiguringFloppy);
  649. #if NEC_98
  650. FddNo = (UCHAR)FirstFD;
  651. _asm {
  652. push ds
  653. mov ah,1ch
  654. mov dl,FddNo
  655. int 21h
  656. pop ds
  657. mov AlReg,al
  658. }
  659. #endif // NEC_98
  660. //
  661. // Hook int13h. We will force a disk change error
  662. // at this point to work around broken change lines.
  663. // The hook will automatically unhook itself as appropriate.
  664. //
  665. if(!DngFloppyless) {
  666. #if NEC_98
  667. if(AlReg == 0xff) {
  668. ErrorScreen = &DnsFloppyNotFormatted;
  669. goto FarstFddErr;
  670. }
  671. _dos_setvect(0x1b,Int13Hook);
  672. sprintf(TextInf,"%c:\\*.*\0" ,(UCHAR)(FirstFD + 0x60));
  673. _dos_findfirst(TextInf,_A_NORMAL,&FindData);
  674. #else // NEC_98
  675. _dos_setvect(0x13,Int13Hook);
  676. _dos_findfirst("a:\\*.*",_A_NORMAL,&FindData);
  677. #endif // NEC_98
  678. }
  679. //
  680. // Get the BPB for the disk in the drive.
  681. //
  682. DeviceParams.SpecialFunctions = 1; // set up to get current bpb
  683. RegistersIn.x.ax = 0x440d; // ioctl for block device
  684. #if NEC_98
  685. RegistersIn.x.bx = FirstFD; // First Floppy Drive
  686. #else // NEC_98
  687. RegistersIn.x.bx = 1; // A:
  688. #endif // NEC_98
  689. RegistersIn.x.cx = 0x860; // category disk, get device params
  690. RegistersIn.x.dx = (unsigned)(void _near *)&DeviceParams; // ds = ss
  691. intdos(&RegistersIn,&RegistersOut);
  692. if(RegistersOut.x.cflag) {
  693. //
  694. // Unable to get the current BPB for the disk. Assume
  695. // Assume not formatted or not formatted correctly.
  696. //
  697. ErrorScreen = &DnsFloppyNotFormatted;
  698. } else {
  699. //
  700. // Sanity check on the BPB
  701. //
  702. if((DeviceParams.Bpb.BytesPerSector != SECTOR_SIZE)
  703. || ( (DeviceParams.Bpb.SectorsPerCluster != 1)
  704. && (DeviceParams.Bpb.SectorsPerCluster != 2)) // for 2.88M disks
  705. || (DeviceParams.Bpb.ReservedSectors != 1)
  706. || (DeviceParams.Bpb.FatCount != 2)
  707. || !DeviceParams.Bpb.SectorCountSmall // should be < 32M
  708. || (DeviceParams.Bpb.MediaDescriptor == 0xf8) // hard disk
  709. || (DeviceParams.Bpb.HeadCount != 2)
  710. || !DeviceParams.Bpb.RootDirectoryEntries) {
  711. ErrorScreen = &DnsFloppyBadFormat;
  712. } else {
  713. #if NEC_98
  714. if(_dos_getdiskfree(FirstFD,&DiskSpace)) {
  715. #else // NEC_98
  716. if(_dos_getdiskfree(1,&DiskSpace)) {
  717. #endif // NEC_98
  718. ErrorScreen = &DnsFloppyCantGetSpace;
  719. } else {
  720. FreeSpace = (ULONG)DiskSpace.avail_clusters
  721. * (ULONG)DiskSpace.sectors_per_cluster
  722. * (ULONG)DiskSpace.bytes_per_sector;
  723. if(DngCheckFloppySpace && (FreeSpace < FLOPPY_CAPACITY)) {
  724. ErrorScreen = &DnsFloppyNotBlank;
  725. }
  726. }
  727. }
  728. }
  729. //
  730. // If there is a problem with the disk, inform the user.
  731. //
  732. if(ErrorScreen) {
  733. #if NEC_98
  734. FarstFddErr:
  735. #endif // NEC_98
  736. DnClearClientArea();
  737. DnDisplayScreen(ErrorScreen);
  738. DnWriteStatusText("%s %s",DntEnterEqualsContinue,DntF3EqualsExit);
  739. while(1) {
  740. c = DnGetValidKey(ValidKey);
  741. if(c == ASCI_CR) {
  742. break;
  743. }
  744. if(c == DN_KEY_F3) {
  745. DnExitDialog();
  746. }
  747. }
  748. }
  749. } while(ErrorScreen);
  750. //
  751. // Copy the bpb for the drive into the structure provided
  752. // by the caller.
  753. //
  754. memcpy(Bpb,&DeviceParams.Bpb,sizeof(MY_BPB));
  755. }
  756. VOID
  757. DnCreateBootFloppies(
  758. VOID
  759. )
  760. /*++
  761. Routine Description:
  762. Create a set of 3 boot floppies if we are not in floppyless operation.
  763. If we are in floppyless operation, place the floppy files on the system
  764. partition instead.
  765. Note that we flush buffers after each floppy so the user who has
  766. write-behind turned on for floppies doesn't get confused as we ask
  767. him to shuffle floppies around.
  768. Arguments:
  769. None.
  770. Return Value:
  771. None.
  772. --*/
  773. {
  774. ULONG ValidKey[3];
  775. ULONG c;
  776. int i;
  777. PSCREEN ErrorScreen;
  778. UCHAR SectorBuffer[SECTOR_SIZE],VerifyBuffer[SECTOR_SIZE];
  779. MY_BPB Bpb;
  780. union REGS RegistersIn,RegistersOut;
  781. MY_READWRITE_BLOCK ReadWriteBlock;
  782. CHAR BootRoot[sizeof(FLOPPYLESS_BOOT_ROOT) + 2];
  783. CHAR System32Dir[sizeof(FLOPPYLESS_BOOT_ROOT) + sizeof("\\SYSTEM32") + 1];
  784. #if NEC_98
  785. #else // NEC_98
  786. unsigned HostDrive;
  787. struct diskfree_t DiskSpace;
  788. #endif // NEC_98
  789. //
  790. // Need to determine the system partition. It is usually C:
  791. // but if C: is compressed we need to find the host drive.
  792. //
  793. #if NEC_98
  794. BootRoot[0] = (CHAR)toupper(DngTargetDriveLetter);
  795. #else // NEC_98
  796. if(DnIsDriveCompressedVolume(3,&HostDrive)) {
  797. BootRoot[0] = (CHAR)(HostDrive + (unsigned)'A' - 1);
  798. } else {
  799. BootRoot[0] = 'C';
  800. }
  801. #endif // NEC_98
  802. BootRoot[1] = ':';
  803. strcpy(BootRoot+2,FLOPPYLESS_BOOT_ROOT);
  804. #if NEC_98
  805. #else // NEC_98
  806. DnDelnode(BootRoot);
  807. #endif // NEC_98
  808. //
  809. // Create the boot root if necessary.
  810. //
  811. if(DngFloppyless) {
  812. #if NEC_98
  813. #else // NEC_98
  814. //
  815. // Check free space on the system partition.
  816. //
  817. if(_dos_getdiskfree((unsigned)BootRoot[0]-(unsigned)'A'+1,&DiskSpace)
  818. ||( ((ULONG)DiskSpace.avail_clusters
  819. * (ULONG)DiskSpace.sectors_per_cluster
  820. * (ULONG)DiskSpace.bytes_per_sector) < (3L*FLOPPY_CAPACITY_525)))
  821. {
  822. DnFatalError(&DnsNoSpaceOnSyspart);
  823. }
  824. #endif // NEC_98
  825. mkdir(BootRoot);
  826. DnInstallNtBoot((unsigned)BootRoot[0]-(unsigned)'A');
  827. } else {
  828. //
  829. // Remember old int13 vector because we will be hooking int13.
  830. //
  831. #if NEC_98
  832. OldInt13Vector = _dos_getvect(0x1b);
  833. #else // NEC_98
  834. OldInt13Vector = _dos_getvect(0x13);
  835. #endif // NEC_98
  836. //
  837. // Boot root is A:.
  838. //
  839. #if NEC_98
  840. sprintf(BootRoot,"%c:\0" ,(UCHAR)(FirstFD + 0x60));
  841. #else // NEC_98
  842. strcpy(BootRoot,"A:");
  843. #endif // NEC_98
  844. }
  845. strcpy(System32Dir,BootRoot);
  846. strcat(System32Dir,"\\SYSTEM32");
  847. ValidKey[0] = ASCI_CR;
  848. ValidKey[1] = DN_KEY_F3;
  849. ValidKey[2] = 0;
  850. do {
  851. ErrorScreen = NULL;
  852. //
  853. // Get a floppy in the drive -- this will be "Windows NT Setup Disk #3"
  854. //
  855. if(!DngFloppyless) {
  856. DnPromptAndInspectFloppy(
  857. DngServer ? &DnsNeedSFloppyDsk3_0 : &DnsNeedFloppyDisk3_0,
  858. DngServer ? &DnsNeedSFloppyDsk3_1 : &DnsNeedFloppyDisk3_1,
  859. &Bpb
  860. );
  861. }
  862. //
  863. // Hack: create system 32 directory on the disk.
  864. // Remove any file called system32.
  865. //
  866. _dos_setfileattr(System32Dir,_A_NORMAL);
  867. remove(System32Dir);
  868. mkdir(System32Dir);
  869. //
  870. // Copy files into the disk.
  871. //
  872. DnCopyFloppyFiles(DnfFloppyFiles3,BootRoot);
  873. if(!DngFloppyless) {
  874. DnpFlushBuffers(TRUE);
  875. }
  876. } while(ErrorScreen);
  877. //
  878. // Get a floppy in the drive -- this will be "Windows NT Setup Disk #2"
  879. //
  880. if(!DngFloppyless) {
  881. DnPromptAndInspectFloppy(
  882. DngServer ? &DnsNeedSFloppyDsk1_0 : &DnsNeedFloppyDisk1_0,
  883. DngServer ? &DnsNeedSFloppyDsk1_0 : &DnsNeedFloppyDisk1_0,
  884. &Bpb
  885. );
  886. }
  887. //
  888. // Copy files into the disk.
  889. //
  890. DnCopyFloppyFiles(DnfFloppyFiles2,BootRoot);
  891. DnCopyFloppyFiles(DnfFloppyFiles1,BootRoot);
  892. do {
  893. ErrorScreen = NULL;
  894. //
  895. // Get a floppy in the drive -- this will be "Windows NT Setup Boot Disk"
  896. //
  897. if(DngFloppyless) {
  898. DnCopyFloppyFiles(DnfFloppyFiles0,BootRoot);
  899. } else {
  900. DnPromptAndInspectFloppy(
  901. DngServer ? &DnsNeedSFloppyDsk0_0 : &DnsNeedFloppyDisk0_0,
  902. DngServer ? &DnsNeedSFloppyDsk0_0 : &DnsNeedFloppyDisk0_0,
  903. &Bpb
  904. );
  905. #if NEC_98
  906. memcpy(SectorBuffer,PC98FatBootCode,512);
  907. #else // NEC_98
  908. memcpy(SectorBuffer,FatBootCode,SECTOR_SIZE);
  909. #endif // NEC_98
  910. //
  911. // Copy the BPB we retreived for the disk into the bootcode template.
  912. // We only care about the original BPB fields, through the head count
  913. // field. We will fill in the other fields ourselves.
  914. //
  915. strncpy(SectorBuffer+3,"MSDOS5.0",8);
  916. memcpy(SectorBuffer+11,&Bpb,sizeof(MY_BPB));
  917. //
  918. // Set up other fields in the bootsector/BPB/xBPB.
  919. //
  920. // Large sector count (4 bytes)
  921. // Hidden sector count (4 bytes)
  922. // current head (1 byte, not necessary to set this, but what the heck)
  923. // physical disk# (1 byte)
  924. //
  925. memset(SectorBuffer+28,0,10);
  926. //
  927. // Extended BPB signature
  928. //
  929. *(PUCHAR)(SectorBuffer+38) = 41;
  930. //
  931. // Serial number
  932. //
  933. srand((unsigned)clock());
  934. *(PULONG)(SectorBuffer+39) = (((ULONG)clock() * (ULONG)rand()) << 8) | rand();
  935. //
  936. // volume label/system id
  937. //
  938. strncpy(SectorBuffer+43,"NO NAME ",11);
  939. strncpy(SectorBuffer+54,"FAT12 ",8);
  940. //
  941. // Overwrite the 'ntldr' string with 'setupldr.bin' so the right file gets
  942. // loaded when the floppy is booted.
  943. //
  944. if(i = DnpScanBootSector(SectorBuffer,"NTLDR ")) {
  945. strncpy(SectorBuffer+i,"SETUPLDRBIN",11);
  946. }
  947. //
  948. // Write the boot sector.
  949. //
  950. #if NEC_98
  951. RegistersIn.h.ah = 0x30;
  952. intdos(&RegistersIn,&RegistersOut);
  953. if(RegistersOut.h.al < 0x7) {
  954. RegistersIn.x.ax = FirstFD - 1;
  955. RegistersIn.x.bx = (unsigned)(void _near *)&SectorBuffer;
  956. RegistersIn.x.cx = 1;
  957. RegistersIn.x.dx = 0;
  958. int86(0x26,&RegistersIn,&RegistersOut);
  959. } else {
  960. ReadWriteBlock.SpecialFunctions = 0;
  961. ReadWriteBlock.Head = 0; // head
  962. ReadWriteBlock.Cylinder = 0; // cylinder
  963. ReadWriteBlock.FirstSector = 0; // sector
  964. ReadWriteBlock.SectorCount = 1; // sector count
  965. ReadWriteBlock.Buffer = SectorBuffer;
  966. RegistersIn.x.ax = 0x440d; // ioctl for block device
  967. RegistersIn.x.bx = FirstFD; // A:
  968. RegistersIn.x.cx = 0x841; // category disk; write sectors
  969. RegistersIn.x.dx = (unsigned)(void _near *)&ReadWriteBlock;
  970. intdos(&RegistersIn,&RegistersOut);
  971. }
  972. if(RegistersOut.x.cflag) {
  973. #else // NEC_98
  974. ReadWriteBlock.SpecialFunctions = 0;
  975. ReadWriteBlock.Head = 0; // head
  976. ReadWriteBlock.Cylinder = 0; // cylinder
  977. ReadWriteBlock.FirstSector = 0; // sector
  978. ReadWriteBlock.SectorCount = 1; // sector count
  979. ReadWriteBlock.Buffer = SectorBuffer;
  980. RegistersIn.x.ax = 0x440d; // ioctl for block device
  981. RegistersIn.x.bx = 1; // A:
  982. RegistersIn.x.cx = 0x841; // category disk; write sectors
  983. RegistersIn.x.dx = (unsigned)(void _near *)&ReadWriteBlock;
  984. intdos(&RegistersIn,&RegistersOut);
  985. if(RegistersOut.x.cflag) {
  986. #endif // NEC_98
  987. ErrorScreen = &DnsFloppyWriteBS;
  988. } else {
  989. DnpFlushBuffers(FALSE);
  990. //
  991. // Read the sector back in and verify that we wrote what we think
  992. // we wrote.
  993. //
  994. #if NEC_98
  995. RegistersIn.h.ah = 0x30;
  996. intdos(&RegistersIn,&RegistersOut);
  997. if(RegistersOut.h.al < 0x7) {
  998. RegistersIn.x.ax = FirstFD - 1;
  999. RegistersIn.x.bx = (unsigned)(void _near *)&VerifyBuffer;
  1000. RegistersIn.x.cx = 1;
  1001. RegistersIn.x.dx = 0;
  1002. int86(0x25,&RegistersIn,&RegistersOut);
  1003. } else {
  1004. ReadWriteBlock.Buffer = VerifyBuffer;
  1005. RegistersIn.x.ax = 0x440d; // ioctl for block device
  1006. RegistersIn.x.bx = FirstFD; // A:
  1007. RegistersIn.x.cx = 0x861; // category disk; write sectors
  1008. RegistersIn.x.dx = (unsigned)(void _near *)&ReadWriteBlock;
  1009. intdos(&RegistersIn,&RegistersOut);
  1010. }
  1011. if(RegistersOut.x.cflag || memcmp(SectorBuffer,VerifyBuffer,512)) {
  1012. #else // NEC_98
  1013. ReadWriteBlock.Buffer = VerifyBuffer;
  1014. RegistersIn.x.ax = 0x440d; // ioctl for block device
  1015. RegistersIn.x.bx = 1; // A:
  1016. RegistersIn.x.cx = 0x861; // category disk; write sectors
  1017. RegistersIn.x.dx = (unsigned)(void _near *)&ReadWriteBlock;
  1018. intdos(&RegistersIn,&RegistersOut);
  1019. if(RegistersOut.x.cflag || memcmp(SectorBuffer,VerifyBuffer,SECTOR_SIZE)) {
  1020. #endif // NEC_98
  1021. ErrorScreen = &DnsFloppyVerifyBS;
  1022. } else {
  1023. //
  1024. // Copy the relevent files to the floppy.
  1025. //
  1026. DnCopyFloppyFiles(DnfFloppyFiles0,BootRoot);
  1027. //
  1028. // Flush buffers
  1029. //
  1030. DnpFlushBuffers(TRUE);
  1031. }
  1032. }
  1033. }
  1034. if( !ErrorScreen ) {
  1035. //
  1036. // Put a small file on the disk indicating that it's a winnt setup.
  1037. //
  1038. if(DngWinntFloppies) {
  1039. if(!DnIndicateWinnt(BootRoot)) {
  1040. ErrorScreen = &DnsCantWriteFloppy;
  1041. } else {
  1042. if(!DngFloppyless) {
  1043. DnpFlushBuffers(TRUE);
  1044. }
  1045. }
  1046. }
  1047. }
  1048. if(ErrorScreen) {
  1049. DnClearClientArea();
  1050. DnDisplayScreen(ErrorScreen);
  1051. DnWriteStatusText("%s %s",DntEnterEqualsContinue,DntF3EqualsExit);
  1052. while(1) {
  1053. c = DnGetValidKey(ValidKey);
  1054. if(c == ASCI_CR) {
  1055. break;
  1056. }
  1057. if(c == DN_KEY_F3) {
  1058. DnExitDialog();
  1059. }
  1060. }
  1061. }
  1062. } while(ErrorScreen);
  1063. //
  1064. // Additionally in the floppyless case, we need to copy some files
  1065. // from the boot directory to the root of the system partition drive.
  1066. //
  1067. if(DngFloppyless) {
  1068. DnCopyFloppyFiles(DnfFloppyFilesX,BootRoot);
  1069. System32Dir[0] = BootRoot[0];
  1070. System32Dir[1] = ':';
  1071. System32Dir[2] = 0;
  1072. DnCopyFilesInSection(CPY_PRESERVE_NAME,DnfRootBootFiles,BootRoot,System32Dir);
  1073. if( DngOemPreInstall ) {
  1074. //
  1075. // If this is an OEM preinstall, then create the directory
  1076. // $win_nt$.~bt\$OEM$, and copy all files listed in
  1077. // OemBootFiles to this directory
  1078. //
  1079. PCHAR OEMBootDir;
  1080. OEMBootDir = MALLOC( strlen( BootRoot ) + 1 +
  1081. strlen( WINNT_OEM_DIR ) + 1, TRUE );
  1082. strcpy(OEMBootDir, BootRoot);
  1083. strcat(OEMBootDir, "\\");
  1084. strcat(OEMBootDir, WINNT_OEM_DIR);
  1085. //
  1086. // Hack: create $win_nt$.~ls\$oem$ directory on the disk.
  1087. // Remove any file called $oem$.
  1088. //
  1089. _dos_setfileattr(OEMBootDir,_A_NORMAL);
  1090. remove(OEMBootDir);
  1091. mkdir(OEMBootDir);
  1092. //
  1093. // Copy the OEM boot files
  1094. //
  1095. DnCopyOemBootFiles(OEMBootDir);
  1096. }
  1097. }
  1098. }
  1099. BOOLEAN
  1100. DnpWriteOutLine(
  1101. IN int Handle,
  1102. IN PUCHAR Line
  1103. )
  1104. {
  1105. unsigned bw,l;
  1106. l = strlen(Line);
  1107. return((BOOLEAN)((_dos_write(Handle,Line,l,&bw) == 0) && (bw == l)));
  1108. }
  1109. VOID
  1110. DnInstallNtBoot(
  1111. IN unsigned Drive // 0=A, etc
  1112. )
  1113. {
  1114. PUCHAR Buffer,p,next,orig;
  1115. unsigned BootIniSize;
  1116. BOOLEAN b;
  1117. CHAR BootIniName[] = "?:\\BOOT.INI";
  1118. struct find_t FindData;
  1119. BOOLEAN InOsSection;
  1120. BOOLEAN SawPreviousOsLine;
  1121. CHAR c;
  1122. PCHAR PreviousOs;
  1123. int h;
  1124. //
  1125. // This buffer is used to read in boot.ini as well as
  1126. // to hold a bootsector. So make it big enough.
  1127. //
  1128. Buffer = MALLOC(10000,TRUE);
  1129. BootIniName[0] = (CHAR)(Drive + (unsigned)'A');
  1130. b = TRUE;
  1131. if(b = DnpInstallNtBootSector(Drive,Buffer,&PreviousOs)) {
  1132. //
  1133. // Load boot.ini.
  1134. //
  1135. _dos_setfileattr(BootIniName,_A_NORMAL);
  1136. BootIniSize = 0;
  1137. if(!_dos_findfirst(BootIniName,_A_RDONLY|_A_HIDDEN|_A_SYSTEM,&FindData)) {
  1138. if(!_dos_open(BootIniName,O_RDWR|SH_COMPAT,&h)) {
  1139. BootIniSize = (unsigned)max(FindData.size,(16*1024)-1);
  1140. if(_dos_read(h,Buffer,BootIniSize,&BootIniSize)) {
  1141. BootIniSize = 0;
  1142. }
  1143. _dos_close(h);
  1144. }
  1145. }
  1146. Buffer[BootIniSize] = 0;
  1147. //
  1148. // Truncate at control-z if one exists.
  1149. //
  1150. if(p = strchr(Buffer,26)) {
  1151. *p = 0;
  1152. BootIniSize = p-Buffer;
  1153. }
  1154. //
  1155. // Recreate bootini.
  1156. //
  1157. if(_dos_creat(BootIniName,_A_RDONLY|_A_HIDDEN|_A_SYSTEM,&h)) {
  1158. b = FALSE;
  1159. }
  1160. if(b) {
  1161. b = DnpWriteOutLine(
  1162. h,
  1163. "[Boot Loader]\r\n"
  1164. "Timeout=5\r\n"
  1165. "Default=C:" FLOPPYLESS_BOOT_ROOT "\\" FLOPPYLESS_BOOT_SEC "\r\n"
  1166. "[Operating Systems]\r\n"
  1167. );
  1168. }
  1169. if(b) {
  1170. //
  1171. // Process each line in boot.ini.
  1172. // If it's the previous os line and we have new previous os text,
  1173. // we'll throw out the old text in favor of the new.
  1174. // If it's the setup boot sector line, we'll throw it out.
  1175. //
  1176. InOsSection = FALSE;
  1177. SawPreviousOsLine = FALSE;
  1178. for(p=Buffer; *p && b; p=next) {
  1179. while((*p==' ') || (*p=='\t')) {
  1180. p++;
  1181. }
  1182. if(*p) {
  1183. //
  1184. // Find first byte of next line.
  1185. //
  1186. for(next=p; *next && (*next++ != '\n'); );
  1187. //
  1188. // Look for start of [operating systems] section
  1189. // or at each line in that section.
  1190. //
  1191. if(InOsSection) {
  1192. switch(*p) {
  1193. case '[': // end of section.
  1194. *p=0; // force break out of loop
  1195. break;
  1196. case 'C':
  1197. case 'c': // potential start of c:\ line
  1198. if((next-p >= 6) && (p[1] == ':') && (p[2] == '\\')) {
  1199. orig = p;
  1200. p += 3;
  1201. while((*p == ' ') || (*p == '\t')) {
  1202. p++;
  1203. }
  1204. if(*p == '=') {
  1205. //
  1206. // Previous os line. Leave intact unless we have
  1207. // new text for it.
  1208. //
  1209. SawPreviousOsLine = TRUE;
  1210. if(PreviousOs) {
  1211. if((b=DnpWriteOutLine(h,"C:\\ = \""))
  1212. && (b=DnpWriteOutLine(h,PreviousOs))) {
  1213. b=DnpWriteOutLine(h,"\"\r\n");
  1214. }
  1215. break;
  1216. } else {
  1217. //
  1218. // The current line in boot.ini is for the previous
  1219. // OS but we do not need to write a new previous os
  1220. // line. We want to leave this line alone and write
  1221. // it out as is.
  1222. //
  1223. p = orig;
  1224. // falls through to default case
  1225. }
  1226. } else {
  1227. //
  1228. // See if it's a line for setup boot.
  1229. // If so, ignore it.
  1230. // If it's not a line for setup boot, write it out as-is.
  1231. //
  1232. if(strnicmp(orig,"C:" FLOPPYLESS_BOOT_ROOT,sizeof("C:" FLOPPYLESS_BOOT_ROOT)-1)) {
  1233. p = orig;
  1234. } else {
  1235. break;
  1236. }
  1237. }
  1238. }
  1239. // may fall through on purpose
  1240. default:
  1241. //
  1242. // Random line. write it out.
  1243. //
  1244. c = *next;
  1245. *next = 0;
  1246. b = DnpWriteOutLine(h,p);
  1247. *next = c;
  1248. break;
  1249. }
  1250. } else {
  1251. if(!strnicmp(p,"[operating systems]",19)) {
  1252. InOsSection = TRUE;
  1253. }
  1254. }
  1255. }
  1256. }
  1257. //
  1258. // If we need to, write out a line for the previous os.
  1259. // We'll need to if there was no previous os line in the existing
  1260. // boot.ini but we discovered that there is a previous os on the machine.
  1261. //
  1262. if(b && PreviousOs && !SawPreviousOsLine) {
  1263. if((b=DnpWriteOutLine(h,"C:\\ = \""))
  1264. && (b=DnpWriteOutLine(h,PreviousOs))) {
  1265. b=DnpWriteOutLine(h,"\"\r\n");
  1266. }
  1267. }
  1268. //
  1269. // Write out our line
  1270. //
  1271. if(b
  1272. && (b=DnpWriteOutLine(h,"C:" FLOPPYLESS_BOOT_ROOT "\\" FLOPPYLESS_BOOT_SEC " = \""))
  1273. && (b=DnpWriteOutLine(h,DntBootIniLine))) {
  1274. b = DnpWriteOutLine(h,"\"\r\n");
  1275. }
  1276. }
  1277. _dos_close(h);
  1278. } else {
  1279. b = FALSE;
  1280. }
  1281. if(!b) {
  1282. DnFatalError(&DnsNtBootSect);
  1283. }
  1284. FREE(Buffer);
  1285. }
  1286. BOOLEAN
  1287. DnpInstallNtBootSector(
  1288. IN unsigned Drive, // 0=A, etc.
  1289. IN OUT PUCHAR BootSector,
  1290. OUT PCHAR *PreviousOsText
  1291. )
  1292. {
  1293. PUCHAR BootTemplate,p;
  1294. PSCREEN ErrorScreen = NULL;
  1295. CHAR BootsectDosName[] = "?:\\BOOTSECT.DOS";
  1296. int h;
  1297. unsigned BytesWritten;
  1298. unsigned u;
  1299. CHAR DriveLetter;
  1300. #ifdef _FAT32
  1301. BOOLEAN Fat32;
  1302. #endif
  1303. #if NEC_98
  1304. UCHAR Head,Sector; // For Dos 3.x format
  1305. ULONG Hidden_Sectors,lHead;
  1306. UCHAR AL_Reg;
  1307. CHAR OldBootsectDosName[] = "?:\\BOOTSECT.NEC";
  1308. #endif // NEC_98
  1309. *PreviousOsText = NULL;
  1310. DriveLetter = (CHAR)(Drive + (unsigned)'A');
  1311. //
  1312. // Read first sector of the boot drive.
  1313. //
  1314. if(!DnAbsoluteSectorIo(Drive,0L,1,BootSector,FALSE)) {
  1315. return(FALSE);
  1316. }
  1317. //
  1318. // Make sure the disk is formatted.
  1319. //
  1320. if(BootSector[21] != 0xf8) {
  1321. return(FALSE);
  1322. }
  1323. #ifdef _FAT32
  1324. //
  1325. // Determine if Fat32. Root dir entry count is 0 on Fat32.
  1326. //
  1327. Fat32 = TRUE;
  1328. if(BootSector[17] || BootSector[18]) {
  1329. Fat32 = FALSE;
  1330. }
  1331. #endif
  1332. //
  1333. // Check for NT boot code. If it's there,
  1334. // assume NT boot is already installed and we're done.
  1335. // Also meaning that we assume boot.ini is there
  1336. // and correct, so we don't need to worry about
  1337. // the previous OS selection.
  1338. //
  1339. if( 1 ) {
  1340. #if NEC_98
  1341. #ifdef _FAT32
  1342. BootTemplate = Fat32 ? PC98Fat32BootCode : PC98FatBootCode;
  1343. #else
  1344. BootTemplate = PC98FatBootCode;
  1345. #endif
  1346. #else //NEC_98
  1347. #ifdef _FAT32
  1348. BootTemplate = Fat32 ? Fat32BootCode : FatBootCode;
  1349. #else
  1350. BootTemplate = FatBootCode;
  1351. #endif
  1352. #endif // NEC_98
  1353. if( !DnpScanBootSector( BootSector, "NTLDR" ) ) {
  1354. //
  1355. // Write old boot sector to bootsect.dos.
  1356. //
  1357. BootsectDosName[0] = DriveLetter;
  1358. _dos_setfileattr(BootsectDosName,_A_NORMAL);
  1359. #if NEC_98
  1360. OldBootsectDosName[0] = DriveLetter;
  1361. _dos_setfileattr(OldBootsectDosName,_A_NORMAL);
  1362. remove(OldBootsectDosName);
  1363. _dos_setfileattr(BootsectDosName,_A_NORMAL);
  1364. rename(BootsectDosName, OldBootsectDosName);
  1365. #else
  1366. remove(BootsectDosName);
  1367. #endif
  1368. if(_dos_creatnew(BootsectDosName,_A_SYSTEM | _A_HIDDEN, &h)) {
  1369. return(FALSE);
  1370. }
  1371. u = _dos_write(h,BootSector,SECTOR_SIZE,&BytesWritten);
  1372. _dos_close(h);
  1373. if(u || (BytesWritten != SECTOR_SIZE)) {
  1374. return(FALSE);
  1375. }
  1376. }
  1377. //
  1378. // Transfer bpb of old boot sector to NT boot code.
  1379. //
  1380. memmove(BootTemplate+3,BootSector+3,BootTemplate[1]-1);
  1381. #ifndef _FAT32
  1382. //
  1383. // The int13 unit number is elsewhere in fat32
  1384. // No real need to do this in fat16 case either,
  1385. // since the bpb on the disk should have the right value in it!
  1386. //
  1387. BootTemplate[36] = 0x80;
  1388. #endif
  1389. #ifdef _FAT32
  1390. //
  1391. // If FAT32 then we need to lay down the second boot sector,
  1392. // which in the NT case is at sector 12. We do this first so
  1393. // in case it fails the user isn't left with NT code on sector 0
  1394. // that won't boot because the second part is missing from sector 12.
  1395. //
  1396. if(Fat32) {
  1397. if(!DnAbsoluteSectorIo(Drive,12L,1,BootTemplate+1024,TRUE)) {
  1398. return(FALSE);
  1399. }
  1400. }
  1401. #endif
  1402. #if NEC_98
  1403. AL_Reg = TargetDA_UA;
  1404. _asm{
  1405. mov ah,84h
  1406. mov al,AL_Reg
  1407. int 1bh
  1408. mov Head,dh
  1409. mov Sector,dl
  1410. }
  1411. lHead = Head;
  1412. Hidden_Sectors = lHead * Sector * Cylinders;
  1413. (ULONG)BootTemplate[0x1c] = Hidden_Sectors;
  1414. if((USHORT)BootTemplate[0x13] != 0){
  1415. (ULONG)BootTemplate[0x20] = 0L;
  1416. }
  1417. #endif // NEC_98
  1418. //
  1419. // Lay NT boot code onto the disk.
  1420. //
  1421. if(!DnAbsoluteSectorIo(Drive,0L,1,BootTemplate,TRUE)) {
  1422. return(FALSE);
  1423. }
  1424. //
  1425. // Determine previous OS if any.
  1426. // We do this such that if the drive has been formatted
  1427. // by another os but the os is not actually installed,
  1428. // the right thing will happen.
  1429. //
  1430. if(DnpScanBootSector(BootSector,"MSDOS SYS")) {
  1431. if(DnpAreAllFilesPresent(DriveLetter,MsDosFileList)) {
  1432. //
  1433. // Both Chicago and MS-DOS share the same set of signature
  1434. // files in C:\, so we must check IO.SYS to see if it has
  1435. // a Win32 header.
  1436. //
  1437. if(DnpHasMZHeader(DriveLetter, "?:\\IO.SYS")) { // it's Chicago
  1438. *PreviousOsText = DntMsWindows;
  1439. } else { // it's MS-DOS
  1440. *PreviousOsText = DntMsDos;
  1441. }
  1442. }
  1443. } else {
  1444. #if NEC_98
  1445. if(DnpScanBootSector(BootSector,"OS2")) {
  1446. if(DnpAreAllFilesPresent(DriveLetter,Os2FileList)) {
  1447. *PreviousOsText = DntOs2;
  1448. }
  1449. } else {
  1450. *PreviousOsText = DntPreviousOs;
  1451. }
  1452. #else // NEC_98
  1453. if(DnpScanBootSector(BootSector,"IBMDOS COM")) {
  1454. if(DnpAreAllFilesPresent(DriveLetter,PcDosFileList)) {
  1455. *PreviousOsText = DntPcDos;
  1456. }
  1457. } else {
  1458. if(DnpScanBootSector(BootSector,"OS2")) {
  1459. if(DnpAreAllFilesPresent(DriveLetter,Os2FileList)) {
  1460. *PreviousOsText = DntOs2;
  1461. }
  1462. } else {
  1463. *PreviousOsText = DntPreviousOs;
  1464. }
  1465. }
  1466. #endif // NEC_98
  1467. }
  1468. }
  1469. //
  1470. // Now we create the boot sector that we will use
  1471. // to load $LDR$ (setupldr.bin) instead of ntldr.
  1472. //
  1473. if(!DnAbsoluteSectorIo(Drive,0L,1,BootSector,FALSE)) {
  1474. return(FALSE);
  1475. }
  1476. //
  1477. // Overwrite the 'NTLDR' string with '$LDR$' so the right file gets
  1478. // loaded at boot time. Make sure to scan for the full 11 chars
  1479. // so we don't find an error message in the bootcode by accident.
  1480. //
  1481. if(u = DnpScanBootSector(BootSector,"NTLDR ")) {
  1482. strncpy(BootSector+u,"$LDR$",5);
  1483. }
  1484. //
  1485. // Write this into the correct file in the boot directory.
  1486. //
  1487. p = MALLOC(sizeof(FLOPPYLESS_BOOT_ROOT)+sizeof(FLOPPYLESS_BOOT_SEC)+2,TRUE);
  1488. p[0] = DriveLetter;
  1489. p[1] = ':';
  1490. strcpy(p+2,FLOPPYLESS_BOOT_ROOT);
  1491. strcat(p,"\\" FLOPPYLESS_BOOT_SEC);
  1492. _dos_setfileattr(p,_A_NORMAL);
  1493. if(_dos_creat(p,_A_NORMAL,&h)) {
  1494. FREE(p);
  1495. return(FALSE);
  1496. }
  1497. u = _dos_write(h,BootSector,SECTOR_SIZE,&BytesWritten);
  1498. _dos_close(h);
  1499. FREE(p);
  1500. return((BOOLEAN)((u == 0) && (BytesWritten == SECTOR_SIZE)));
  1501. }
  1502. unsigned
  1503. DnpScanBootSector(
  1504. IN PUCHAR BootSector,
  1505. IN PUCHAR Pattern
  1506. )
  1507. {
  1508. unsigned len;
  1509. unsigned i;
  1510. len = strlen(Pattern);
  1511. for(i=510-len; i>62; --i) {
  1512. if(!memcmp(Pattern,BootSector+i,len)) {
  1513. return(i);
  1514. }
  1515. }
  1516. return(0);
  1517. }
  1518. BOOLEAN
  1519. DnpAreAllFilesPresent(
  1520. IN CHAR DriveLetter,
  1521. IN PCHAR FileList[]
  1522. )
  1523. {
  1524. unsigned i;
  1525. struct find_t FindData;
  1526. for(i=0; FileList[i]; i++) {
  1527. FileList[i][0] = DriveLetter;
  1528. if(_dos_findfirst(FileList[i],_A_RDONLY|_A_HIDDEN|_A_SYSTEM,&FindData)) {
  1529. return(FALSE);
  1530. }
  1531. }
  1532. return(TRUE);
  1533. }
  1534. BOOLEAN
  1535. DnpHasMZHeader(
  1536. IN CHAR DriveLetter,
  1537. IN PCHAR Filename
  1538. )
  1539. {
  1540. FILE *FileHandle;
  1541. CHAR Buffer[2];
  1542. BOOLEAN Ret = FALSE;
  1543. Filename[0] = DriveLetter;
  1544. if(!(FileHandle = fopen(Filename, "rb"))) {
  1545. return FALSE;
  1546. }
  1547. if(fread(Buffer, sizeof(CHAR), 2, FileHandle) == 2) {
  1548. if((Buffer[0] == 'M') && (Buffer[1] == 'Z')) {
  1549. Ret = TRUE;
  1550. }
  1551. }
  1552. fclose(FileHandle);
  1553. return Ret;
  1554. }
  1555. #if NEC_98
  1556. #else // NEC_98
  1557. BOOLEAN
  1558. DoPatchBootMessages(
  1559. IN OUT PCHAR BootCode,
  1560. IN unsigned OffsetOffset
  1561. )
  1562. {
  1563. unsigned Offset;
  1564. //
  1565. // Figure out exactly where in the boot code array the messages go.
  1566. //
  1567. Offset = (unsigned)(unsigned char)BootCode[OffsetOffset] + 256;
  1568. //
  1569. // Lay in the messages. The first message is the no system message.
  1570. // The second is the I/O error message. The third is a common msg
  1571. // instructing the user to hit a key.
  1572. //
  1573. // We also supply cr/lf and a special 255 char as punctuation that
  1574. // is meaningful to the bootcode itself.
  1575. //
  1576. BootCode[OffsetOffset] = (UCHAR)(Offset-256);
  1577. BootCode[Offset++] = 13;
  1578. BootCode[Offset++] = 10;
  1579. strcpy(BootCode+Offset,BootMsgNtldrIsMissing);
  1580. Offset += strlen(BootMsgNtldrIsMissing);
  1581. BootCode[Offset++] = (UCHAR)255;
  1582. BootCode[OffsetOffset+1] = (UCHAR)(Offset-256);
  1583. BootCode[Offset++] = 13;
  1584. BootCode[Offset++] = 10;
  1585. strcpy(BootCode+Offset,BootMsgDiskError);
  1586. Offset += strlen(BootMsgDiskError);
  1587. BootCode[Offset++] = (UCHAR)255;
  1588. BootCode[OffsetOffset+2] = (UCHAR)(Offset-256);
  1589. BootCode[Offset++] = 13;
  1590. BootCode[Offset++] = 10;
  1591. strcpy(BootCode+Offset,BootMsgPressKey);
  1592. Offset += strlen(BootMsgPressKey);
  1593. BootCode[Offset++] = 13;
  1594. BootCode[Offset++] = 10;
  1595. BootCode[Offset] = 0;
  1596. return((BOOLEAN)(Offset < OffsetOffset));
  1597. }
  1598. #endif // NEC_98
  1599. #if NEC_98
  1600. #else // NEC_98
  1601. BOOLEAN
  1602. PatchMessagesIntoBootCode(
  1603. VOID
  1604. )
  1605. {
  1606. return((BOOLEAN)(DoPatchBootMessages(FatBootCode,507) && DoPatchBootMessages(Fat32BootCode,505)));
  1607. }
  1608. #endif // NEC_98
  1609. #if NEC_98
  1610. VOID
  1611. RestoreBootcode(VOID)
  1612. /*++
  1613. Routine Description:
  1614. On floppyless setup if user have canceled setup or setup be stopped by error
  1615. occurred,previous OS can't boot to be written boot code and boot loader.
  1616. Arguments:
  1617. None.
  1618. Return Value:
  1619. None.
  1620. --*/
  1621. {
  1622. CHAR DriveLetter;
  1623. CHAR Drive;
  1624. PCHAR Buffer;
  1625. PCHAR FileName;
  1626. int h;
  1627. CHAR i;
  1628. unsigned line = 0;
  1629. unsigned count;
  1630. UCHAR chDeviceName[127];
  1631. UCHAR TargetPass[127];
  1632. CHAR BootsectDosName[] = "?:\\BOOTSECT.DOS";
  1633. CHAR FloppylessDir[] = "?:\\$WIN_NT$.~BT";
  1634. CHAR Current_Drv[] = "?:\0";
  1635. PCHAR DeleteFilesList[] = {"TXTSETUP.SIF","$LDR$","NTDETECT.COM","NTLDR","BOOT.INI"};
  1636. Buffer = MALLOC(2*1024,TRUE);
  1637. memset(Buffer,0,sizeof(2*1024));
  1638. if(DngTargetDriveLetter == 0){ return; }
  1639. DriveLetter = (CHAR)toupper(DngTargetDriveLetter);
  1640. BootsectDosName[0] = DriveLetter;
  1641. FloppylessDir[0] = DriveLetter;
  1642. if(!DngFloppyless && !(access(FloppylessDir,00) == 0)){ return; }
  1643. if(access(BootsectDosName,00) == 0) {
  1644. _dos_setfileattr(BootsectDosName,_A_NORMAL);
  1645. _dos_open(BootsectDosName,O_RDONLY,&h);
  1646. _dos_read(h,Buffer,512,&count);
  1647. _dos_close(h);
  1648. Drive = (CHAR)(DriveLetter - (unsigned)'A');
  1649. //
  1650. // Recopy bootsect.dos -> Target drive
  1651. //
  1652. DnAbsoluteSectorIo(Drive,0L,1,Buffer,TRUE);
  1653. remove(BootsectDosName); // Delete bootsect.dos
  1654. }
  1655. //
  1656. // Delete Root Files($LDR$,NTLDR,etc..)
  1657. //
  1658. for(i=0; i < 5; i++){
  1659. //
  1660. // Delete Root Files($LDR$,NTLDR,etc..)
  1661. //
  1662. memset(chDeviceName,0,sizeof(chDeviceName));
  1663. sprintf(chDeviceName,"%c:\\",DriveLetter);
  1664. strcpy(chDeviceName+3,DeleteFilesList[i]);
  1665. if(access(chDeviceName,00) == 0) {
  1666. _dos_setfileattr(chDeviceName,_A_NORMAL);
  1667. remove(chDeviceName);
  1668. }
  1669. }
  1670. //
  1671. // Check: Exist $WIN_NT$.~BU Directry.
  1672. //
  1673. memset(chDeviceName,0,sizeof(chDeviceName));
  1674. chDeviceName[0] = (UCHAR)DriveLetter;
  1675. chDeviceName[1] = (UCHAR)(':');
  1676. strcpy(chDeviceName+2,"\\$WIN_NT$.~BU");
  1677. if(access(chDeviceName,00) == 0) {
  1678. //
  1679. // Copy: $WIN_NT$.~BU -> Root Directry
  1680. //
  1681. Current_Drv[0] = DriveLetter;
  1682. DnCopyFilesInSection(NULL, DnfBackupFiles_PC98,chDeviceName,Current_Drv);
  1683. //
  1684. // Set root files Attribute.
  1685. //
  1686. while(FileName = DnGetSectionLineIndex(DngInfHandle,DnfBackupFiles_PC98,line++,0)) {
  1687. memset(TargetPass,0,sizeof(TargetPass));
  1688. sprintf(TargetPass,"%c:\\",DriveLetter);
  1689. strcpy(TargetPass+3,FileName);
  1690. _dos_setfileattr(TargetPass,_A_ARCH | _A_HIDDEN | _A_RDONLY | _A_SYSTEM);
  1691. FREE (FileName);
  1692. }
  1693. DnDelnode(chDeviceName);
  1694. remove(chDeviceName);
  1695. }
  1696. DnDelnode(FloppylessDir);
  1697. }
  1698. #endif // NEC_98