Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3454 lines
84 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. winnt.c
  5. Abstract:
  6. Top level file for DOS based NT installation program.
  7. Author:
  8. Ted Miller (tedm) 30-March-1992
  9. Revision History:
  10. --*/
  11. /*
  12. NOTES:
  13. The function of this program is to pull down a complete Windows NT
  14. installation source onto a local partition, and create a setup boot
  15. floppy. The machine is then rebooted, starting a Windows NT Setup
  16. just as if the user had used the real setup floppies or CD-ROM.
  17. The following assumptions are made:
  18. - The floppy must be provided by the user and already formatted.
  19. - The files on the network source are in the same directory layout
  20. structure that will be created in the temp directory on the local
  21. source (ie, as far as winnt is concerned, the source and target
  22. directory layout is the same).
  23. The inf file is expected to be formatted as follows:
  24. [SpaceRequirements]
  25. # BootDrive is the # bytes required free on C:.
  26. # NtDrive is the # bytes required free on the drive chosen by
  27. # the user to contain Windows NT.
  28. BootDrive =
  29. NtDrive =
  30. [Miscellaneous]
  31. # misc junk that goes nowhere else.
  32. [Directories]
  33. # Specification of the source directory structure. All directories
  34. # are relative to the directory where dos2nt.inf was found on the
  35. # remote source or the temp directory on the local source.
  36. # Loading and trailing backslashes are ignored -- to specify the root,
  37. # leave the dirctory field blank or use \.
  38. d1 =
  39. d2 = os2
  40. .
  41. .
  42. .
  43. [Files]
  44. # List of files to be copied to the local source directory.
  45. # Format is <srcdir>,<filename> where <srcdir> matches an entry in the
  46. # Directories section, and <filename> should not contain any path
  47. # characters.
  48. d1,ntoskrnl.exe
  49. d1,ntdll.dll
  50. .
  51. .
  52. .
  53. [FloppyFiles]
  54. # List of files that are to be placed on the floppy that Setup creates.
  55. # Format is same as for lines in the [Files] sections except the directory
  56. # is only used for the source -- the target path is always a:\.
  57. d1,aha154x.sys
  58. .
  59. .
  60. .
  61. */
  62. #include "winnt.h"
  63. #include <errno.h>
  64. #include <string.h>
  65. #include <dos.h>
  66. #include <stdlib.h>
  67. #include <direct.h>
  68. #include <fcntl.h>
  69. #include <ctype.h>
  70. #include <process.h>
  71. #if NEC_98
  72. #include <signal.h>
  73. #include <io.h>
  74. #endif // NEC_98
  75. #include "SetupSxs.h"
  76. //
  77. // define name of default inf file and default source path
  78. //
  79. #define DEFAULT_INF_NAME "dosnet.inf"
  80. PCHAR DrvindexInfName = "drvindex.inf";
  81. #if NEC_98
  82. //
  83. // Boot Device Information.(for /b)
  84. //
  85. typedef struct _BOOTDISKINF {
  86. UCHAR PartitionPosition; // 0-F
  87. UCHAR DA_UA; // SASI/IDE 80, SCSI A0
  88. USHORT DiskSector; // Device Format Sector Size
  89. } BOOTDISKINF, *PBOOTDISKINF;
  90. PBOOTDISKINF BootDiskInfo; // Boot Device Information of Pointer(for /b).
  91. BOOLEAN CursorOnFlag = FALSE; // For Cursor OFF
  92. USHORT Cylinders; // For Dos 3.x format
  93. UCHAR TargetDA_UA;
  94. //
  95. // Make File Pointer.
  96. //
  97. #define MAKE_FP(p,a) FP_SEG(p) = (unsigned short)((a) >> 4) & 0xffff; FP_OFF(p) = (unsigned short)((a) & 0x0f)
  98. //
  99. // Connect Device DA_UA.
  100. //
  101. typedef struct _CONNECTDAUA {
  102. UCHAR DA_UA; // SASI/IDE 80, SCSI A0
  103. } CONNECTDAUA, *PCONNECTDAUA;
  104. PCONNECTDAUA DiskDAUA; // Connect DA_UA of Pointer.
  105. PUCHAR LPTable; // DOS System of LPTable.
  106. UCHAR SupportDosVersion = 5; // LPTable Support Dos version;
  107. BOOLEAN SupportDos = TRUE;
  108. #define FLOPPY_SIZE 1457664L
  109. //
  110. // Search First Floppy Disk Drive ( 0:None Drive / 1-26:Drive# )
  111. //
  112. USHORT FirstFD;
  113. #endif // NEC_98
  114. //
  115. // Command line arguments
  116. //
  117. PCHAR CmdLineSource,CmdLineTarget,CmdLineInf,CmdLineDelete;
  118. BOOLEAN SourceGiven,TargetGiven,InfGiven,DeleteGiven;
  119. //
  120. // If the user gives a script file on the command line,
  121. // if will be appended to winnt.sif.
  122. //
  123. PCHAR DngScriptFile = NULL;
  124. //
  125. // DngSourceRootPath is the drivespec and path to the root of the source,
  126. // and never ends in \ (will be length 2 if source is the root).
  127. //
  128. // Examples: D:\foo\bar D:\foo D:
  129. //
  130. PCHAR DngSourceRootPath;
  131. PCHAR UserSpecifiedOEMShare = 0;
  132. CHAR DngTargetDriveLetter;
  133. CHAR DngSwapDriveLetter;
  134. PVOID DngInfHandle;
  135. PVOID DngDrvindexInfHandle;
  136. PCHAR LocalSourceDirName = LOCAL_SOURCE_DIRECTORY;
  137. #if NEC_98
  138. PCHAR x86DirName = "\\NEC98";
  139. #else // NEC_98
  140. PCHAR x86DirName = "\\I386";
  141. #endif // NEC_98
  142. //
  143. // If this flag is TRUE, then verify the files that are copied to
  144. // the floppy. If it is FALSE, don't. The /f switch overrides.
  145. //
  146. BOOLEAN DngFloppyVerify = TRUE;
  147. //
  148. // If this is FALSE, suppress creation of the boot floppies.
  149. //
  150. BOOLEAN DngCreateFloppies = TRUE;
  151. BOOLEAN DngFloppiesOnly = FALSE;
  152. //
  153. // If TRUE, create winnt floppies.
  154. // If FALSE, create cd/floppy floppies (no winnt.sif)
  155. //
  156. BOOLEAN DngWinntFloppies = TRUE;
  157. //
  158. // If this flag is TRUE, then check the free space on the floppy disk
  159. // before accepting it. Otherwise don't check free space.
  160. //
  161. BOOLEAN DngCheckFloppySpace = TRUE;
  162. //
  163. // Current drive when program invoked, saved so we can restore it
  164. // if the user exits early.
  165. //
  166. unsigned DngOriginalCurrentDrive;
  167. //
  168. // If this is true, we do floppyless operation,
  169. // installing an nt boot on the system partition (C:)
  170. // and starting setup from there.
  171. //
  172. BOOLEAN DngFloppyless = FALSE;
  173. //
  174. // Unattended mode, ie, skip final reboot screen.
  175. //
  176. BOOLEAN DngUnattended = FALSE;
  177. BOOLEAN DngServer = FALSE;
  178. //
  179. // Flag that indicates that we are running on Windows
  180. // (ie, not bare DOS).
  181. //
  182. BOOLEAN DngWindows = FALSE;
  183. //
  184. // Flag that indicates we want to see the accessiblity options
  185. //
  186. BOOLEAN DngAccessibility = FALSE;
  187. BOOLEAN DngMagnifier = FALSE;
  188. BOOLEAN DngTalker = FALSE;
  189. BOOLEAN DngKeyboard = FALSE;
  190. //
  191. // Flag for the 2nd CD enhancements to setup
  192. //
  193. BOOLEAN DngCopyOnlyD1TaggedFiles = TRUE;
  194. //
  195. // Flag that indicates that we are running OEM preinstall
  196. //
  197. BOOLEAN DngOemPreInstall = FALSE;
  198. PCHAR OemSystemDirectory = WINNT_OEM_DIR;
  199. PCHAR OemOptionalDirectory = WINNT_OEM_OPTIONAL_DIR;
  200. PCHAR UniquenessDatabaseFile;
  201. PCHAR UniquenessId;
  202. //
  203. // Command to execute at the end of GUI setup
  204. //
  205. PCHAR CmdToExecuteAtEndOfGui = NULL;
  206. //
  207. // Keep track of any optional dirs that the user wants
  208. // to copy
  209. //
  210. unsigned OptionalDirCount;
  211. CHAR *OptionalDirs[MAX_OPTIONALDIRS];
  212. unsigned OptionalDirFlags[MAX_OPTIONALDIRS];
  213. unsigned OptionalDirFileCount;
  214. //
  215. // Keep track of any OEM boot file specified on [OemBootFiles]
  216. // in the script file
  217. //
  218. unsigned OemBootFilesCount;
  219. CHAR *OemBootFiles[MAX_OEMBOOTFILES];
  220. //
  221. // Define the minimum disk space needed in order to copy the temporary
  222. // directories to drives formatted with all possible cluster sizes
  223. //
  224. SPACE_REQUIREMENT SpaceRequirements[] = { { "TempDirSpace512", (unsigned) 512, 0 },
  225. { "TempDirSpace1K", (unsigned) 1024, 0 },
  226. { "TempDirSpace2K", (unsigned) 2048, 0 },
  227. { "TempDirSpace4K", (unsigned) 4096, 0 },
  228. { "TempDirSpace8K", (unsigned) 8192, 0 },
  229. { "TempDirSpace16K", (unsigned)16384, 0 },
  230. { "TempDirSpace32K", (unsigned)32768, 0 }
  231. };
  232. #define TEDM
  233. #ifdef TEDM
  234. BOOLEAN DngAllowNt = FALSE;
  235. #endif
  236. VOID
  237. DnpFetchArguments(
  238. VOID
  239. );
  240. BOOLEAN
  241. DnpParseArguments(
  242. IN int argc,
  243. IN char *argv[]
  244. );
  245. VOID
  246. DnpGetAccessibilityOptions(
  247. VOID
  248. );
  249. VOID
  250. DnpValidateAndConnectToShare(
  251. FILE **InfFileHandle,
  252. FILE **DrvindexInfFileHandle
  253. );
  254. VOID
  255. DnpValidateAndInspectTarget(
  256. VOID
  257. );
  258. VOID
  259. DnpCheckMemory(
  260. VOID
  261. );
  262. VOID
  263. DnpCheckSmartdrv(
  264. VOID
  265. );
  266. BOOLEAN
  267. DnpIsValidSwapDrive(
  268. IN CHAR Drive,
  269. IN ULONG SpaceRequired
  270. );
  271. BOOLEAN
  272. DnpIsValidLocalSource(
  273. IN CHAR Drive,
  274. IN BOOLEAN CheckLocalSource,
  275. IN BOOLEAN CheckBootFiles
  276. );
  277. VOID
  278. DnpDetermineLocalSourceDrive(
  279. VOID
  280. );
  281. VOID
  282. DnpDetermineSwapDrive(
  283. VOID
  284. );
  285. #if 0
  286. BOOLEAN
  287. DnpConstructLocalSourceList(
  288. OUT PCHAR DriveList
  289. );
  290. #endif
  291. ULONG
  292. DnGetMinimumRequiredSpace(
  293. IN CHAR DriveLetter
  294. );
  295. VOID
  296. DnpReadInf(
  297. IN FILE *InfFileHandle,
  298. IN FILE *DrvindexInfFileHandle
  299. );
  300. VOID
  301. DnpCheckEnvironment(
  302. VOID
  303. );
  304. BOOLEAN
  305. RememberOptionalDir(
  306. IN PCHAR Dir,
  307. IN unsigned Flags
  308. );
  309. void
  310. _far
  311. DnInt24(
  312. unsigned deverror,
  313. unsigned errcode,
  314. unsigned _far *devhdr
  315. );
  316. VOID
  317. StartLog(
  318. VOID
  319. );
  320. // in cpu.asm
  321. #if NEC_98
  322. extern
  323. USHORT
  324. HwGetProcessorType(
  325. VOID
  326. );
  327. #else // NEC_98
  328. USHORT
  329. HwGetProcessorType(
  330. VOID
  331. );
  332. #endif // NEC_98
  333. #if NEC_98
  334. VOID
  335. CheckTargetDrive(
  336. VOID
  337. );
  338. VOID
  339. SetAutoReboot(
  340. VOID
  341. );
  342. USHORT
  343. GetSectorValue(
  344. IN UCHAR CheckDA_UA
  345. );
  346. BOOLEAN
  347. DiskSectorReadWrite(
  348. IN USHORT HDSector,
  349. IN UCHAR ReadWriteDA_UA,
  350. IN BOOLEAN ReadFlag,
  351. IN PSHORT ReadBuffer
  352. );
  353. VOID
  354. GetLPTable(
  355. IN PCHAR pLPTable
  356. );
  357. VOID
  358. ClearBootFlag(
  359. VOID
  360. );
  361. VOID
  362. BootPartitionData(
  363. VOID
  364. );
  365. BOOLEAN
  366. CheckBootDosVersion(
  367. IN UCHAR SupportDosVersion
  368. );
  369. VOID
  370. GetDaUa(VOID);
  371. VOID
  372. SearchFirstFDD(VOID);
  373. extern
  374. ULONG
  375. DnpCopyOneFile(
  376. IN PCHAR SourceName,
  377. IN PCHAR DestName,
  378. IN BOOLEAN Verify
  379. );
  380. extern
  381. PCHAR
  382. DnGetSectionLineIndex (
  383. IN PVOID INFHandle,
  384. IN PCHAR SectionName,
  385. IN unsigned LineIndex,
  386. IN unsigned ValueIndex
  387. );
  388. VOID
  389. DummyRoutine(
  390. VOID
  391. );
  392. #endif // NEC_98
  393. VOID
  394. main(
  395. IN int argc,
  396. IN char *argv[]
  397. )
  398. {
  399. FILE *f, *drvindex;
  400. #ifdef LCP
  401. USHORT codepage;
  402. #endif // def LCP
  403. #if NEC_98
  404. DngTargetDriveLetter = 0;
  405. //
  406. // CTRL + C Hook
  407. //
  408. signal(SIGINT,DummyRoutine);
  409. #else // NEC_98
  410. #ifdef LCP
  411. // Determine the local code page
  412. _asm {
  413. mov ax,06601h
  414. int 21h
  415. jnc ok
  416. xor bx,bx
  417. ok: mov codepage, bx
  418. }
  419. // If codepage does not correspond to winnt.exe's language,
  420. // start US Winnt.exe (winntus.exe)
  421. // Czech
  422. #if CS
  423. #define LANGCP (852)
  424. #else
  425. // Greek
  426. #if EL
  427. #define LANGCP (737)
  428. #else
  429. // Japanese
  430. #if JAPAN
  431. #define LANGCP (932)
  432. #else
  433. // Russian
  434. #if RU
  435. #define LANGCP (866)
  436. #else
  437. // Polish
  438. #if PL
  439. #define LANGCP (852)
  440. #else
  441. // Hungarian
  442. #if HU
  443. #define LANGCP (852)
  444. #else
  445. // Turkish
  446. #if TR
  447. #define LANGCP (857)
  448. #else
  449. // Pseudo
  450. #if PSU
  451. #define LANGCP (857)
  452. #else
  453. #error Unable to define LANGCP as no matching language was found.
  454. #endif // PSU
  455. #endif // TR
  456. #endif // HU
  457. #endif // PL
  458. #endif // RU
  459. #endif // JAPAN
  460. #endif // EL
  461. #endif // CS
  462. if (codepage != LANGCP) {
  463. argv[0] = "winntus";
  464. execv("winntus", argv);
  465. return;
  466. }
  467. #endif // def LCP
  468. #endif // NEC_98
  469. //
  470. // Parse arguments
  471. //
  472. if(!DnpParseArguments(argc,argv)) {
  473. PCHAR *p;
  474. //
  475. // Bad args. Print usage message and exit.
  476. //
  477. // If user specified /D, display message informing that the
  478. // switch is no longer supported
  479. //
  480. for( (p = DeleteGiven ? DntUsageNoSlashD : DntUsage);
  481. *p;
  482. p++) {
  483. puts(*p);
  484. }
  485. return;
  486. }
  487. //
  488. // establish int 24 handler
  489. //
  490. _harderr(DnInt24);
  491. //
  492. // determine current drive
  493. //
  494. _dos_getdrive(&DngOriginalCurrentDrive);
  495. //
  496. // Initialize screen
  497. //
  498. DnInitializeDisplay();
  499. #if NEC_98
  500. #else
  501. //
  502. // Patch boot code with translated messages.
  503. //
  504. if(!PatchMessagesIntoBootCode()) {
  505. DnFatalError(&DnsBootMsgsTooLarge);
  506. }
  507. #endif
  508. DnWriteString(DntStandardHeader);
  509. DnpDetermineSwapDrive ();
  510. if(DngUnattended) {
  511. //
  512. // Check to see if we should process the contents of
  513. // the script file.
  514. // Note that we need to process the contents of the script file
  515. // only after the video is initialized. Otherwise, we won't be able
  516. // to report fatal errors.
  517. //
  518. if (DngScriptFile) {
  519. DnpFetchArguments();
  520. }
  521. }
  522. #if 0
  523. //
  524. // /D is no longer supported
  525. //
  526. if(DeleteGiven) {
  527. DnDeleteNtTree(CmdLineDelete);
  528. }
  529. #endif
  530. DnpCheckEnvironment();
  531. #if NEC_98
  532. LPTable = MALLOC(96,TRUE);
  533. SupportDos = CheckBootDosVersion(SupportDosVersion);
  534. GetLPTable(LPTable);
  535. SearchFirstFDD();
  536. #endif // NEC_98
  537. DnpValidateAndConnectToShare(&f, &drvindex);
  538. DnpReadInf(f, drvindex);
  539. fclose(f);
  540. fclose(drvindex);
  541. if(DngAccessibility) {
  542. DnpGetAccessibilityOptions();
  543. }
  544. DnpCheckMemory();
  545. DnpCheckSmartdrv ();
  546. if(!DngFloppiesOnly) {
  547. DnpDetermineLocalSourceDrive();
  548. }
  549. #if NEC_98
  550. if(!DngFloppiesOnly) {
  551. BootDiskInfo = MALLOC(sizeof(BOOTDISKINF),TRUE);
  552. BootPartitionData();
  553. CheckTargetDrive();
  554. }
  555. #endif // NEC_98
  556. if(!DngAllowNt && DngCreateFloppies) {
  557. DnCreateBootFloppies();
  558. }
  559. if(!DngFloppiesOnly) {
  560. DnCopyFiles();
  561. #if NEC_98
  562. //
  563. // Set Auto Reboot Flag
  564. //
  565. if(DngFloppyless) {
  566. ClearBootFlag();
  567. SetAutoReboot();
  568. }
  569. FREE(BootDiskInfo);
  570. FREE(LPTable);
  571. #endif // NEC_98
  572. DnFreeINFBuffer (DngInfHandle);
  573. DnFreeINFBuffer (DngDrvindexInfHandle);
  574. DnToNtSetup();
  575. }
  576. DnFreeINFBuffer (DngInfHandle);
  577. DnFreeINFBuffer (DngDrvindexInfHandle);
  578. DnExit(0);
  579. }
  580. BOOLEAN
  581. RememberOptionalDir(
  582. IN PCHAR Dir,
  583. IN unsigned Flags
  584. )
  585. {
  586. unsigned u;
  587. for (u = 0; u < OptionalDirCount; u++) {
  588. if(!stricmp(OptionalDirs[u],Dir)) {
  589. OptionalDirFlags[u] = Flags;
  590. return (TRUE);
  591. }
  592. }
  593. //
  594. // Not already in there
  595. //
  596. if (OptionalDirCount < MAX_OPTIONALDIRS) {
  597. OptionalDirs[OptionalDirCount] = Dir;
  598. OptionalDirFlags[OptionalDirCount] = Flags;
  599. OptionalDirCount++;
  600. return (TRUE);
  601. }
  602. return (FALSE);
  603. }
  604. BOOLEAN
  605. RememberOemBootFile(
  606. IN PCHAR File
  607. )
  608. {
  609. unsigned u;
  610. for (u = 0; u < OemBootFilesCount; u++) {
  611. if(!stricmp(OemBootFiles[u],File)) {
  612. return (TRUE);
  613. }
  614. }
  615. //
  616. // Not already in there
  617. //
  618. if (OemBootFilesCount < MAX_OEMBOOTFILES) {
  619. OemBootFiles[OemBootFilesCount] = File;
  620. OemBootFilesCount++;
  621. return (TRUE);
  622. }
  623. return (FALSE);
  624. }
  625. VOID
  626. DnpFetchArguments(
  627. VOID
  628. )
  629. {
  630. PCHAR WinntSetupP = WINNT_SETUPPARAMS;
  631. PCHAR WinntYes = WINNT_A_YES;
  632. PCHAR WinntNo = WINNT_A_NO;
  633. FILE *FileHandle;
  634. int Status;
  635. PVOID ScriptHandle;
  636. PCHAR WinntUnattended = WINNT_UNATTENDED;
  637. PCHAR WinntOemPreinstall = WINNT_OEMPREINSTALL;
  638. unsigned LineNumber;
  639. //
  640. // First open the script file as a dos file
  641. //
  642. FileHandle = fopen(DngScriptFile,"rt");
  643. if(FileHandle == NULL) {
  644. //
  645. // fatal error.
  646. //
  647. DnFatalError(&DnsOpenReadScript);
  648. }
  649. //
  650. // Now open it as a INF file
  651. //
  652. LineNumber = 0;
  653. Status = DnInitINFBuffer (FileHandle, &ScriptHandle, &LineNumber);
  654. fclose(FileHandle);
  655. if(Status == ENOMEM) {
  656. DnFatalError(&DnsOutOfMemory);
  657. } else if(Status) {
  658. DnFatalError(&DnsParseScriptFile, DngScriptFile, LineNumber);
  659. }
  660. //
  661. // Find out if this is an OEM preinstall
  662. //
  663. if (DnSearchINFSection(ScriptHandle,WinntUnattended)) {
  664. if (DnGetSectionKeyExists(ScriptHandle,WinntUnattended,WinntOemPreinstall)) {
  665. PCHAR Ptr;
  666. //
  667. // OEM preinstall key exists
  668. //
  669. Ptr = DnGetSectionKeyIndex(ScriptHandle,WinntUnattended,WinntOemPreinstall,0);
  670. if (Ptr != NULL) {
  671. if (stricmp(Ptr,WinntYes) == 0) {
  672. //
  673. // This is an OEM pre-install
  674. //
  675. DngOemPreInstall = TRUE;
  676. } else {
  677. //
  678. // Assume this is not an OEM pre-install
  679. //
  680. DngOemPreInstall = FALSE;
  681. }
  682. FREE (Ptr);
  683. }
  684. }
  685. //
  686. // See if the user specified a network (or any secondary) path
  687. // for the $OEM$ files.
  688. //
  689. if( DngOemPreInstall ) {
  690. if (DnGetSectionKeyExists(ScriptHandle,WinntUnattended,WINNT_OEM_DIRLOCATION)) {
  691. PCHAR Ptr;
  692. unsigned i;
  693. //
  694. // WINNT_OEM_DIRLOCATION preinstall key exists
  695. //
  696. Ptr = DnGetSectionKeyIndex(ScriptHandle,WinntUnattended,WINNT_OEM_DIRLOCATION,0);
  697. //
  698. // Now take care of the case whether or not
  699. // the user actually appended $OEM$ onto the path.
  700. // For the case of winnt.exe, we don't want it. We
  701. // need to remove it if it's there.
  702. UserSpecifiedOEMShare = DnDupString( Ptr );
  703. FREE (Ptr);
  704. for( i = 0; i < strlen(UserSpecifiedOEMShare); i++ ) {
  705. UserSpecifiedOEMShare[i] = (UCHAR) toupper(UserSpecifiedOEMShare[i]);
  706. }
  707. Ptr = strstr( UserSpecifiedOEMShare, "$OEM$" );
  708. if( Ptr ) {
  709. //
  710. // Whack the end off...
  711. //
  712. *Ptr = 0;
  713. }
  714. }
  715. }
  716. if( DngOemPreInstall ) {
  717. //
  718. // Always add to the list of optional directories the directory
  719. // $OEM$
  720. //
  721. RememberOptionalDir(OemSystemDirectory, OPTDIR_OEMSYS);
  722. //
  723. // If this an OEM pre-install, build a list with the name of all
  724. // OEM optional directories.
  725. //
  726. if (DnSearchINFSection(ScriptHandle, WINNT_OEMOPTIONAL)) {
  727. unsigned KeyIndex;
  728. PCHAR DirName;
  729. //
  730. // Add the temporary OEM directories to the array of
  731. // temporary directories.
  732. //
  733. for( KeyIndex = 0;
  734. ((DirName = DnGetKeyName(ScriptHandle,WINNT_OEMOPTIONAL,KeyIndex)) != NULL );
  735. KeyIndex++ ) {
  736. //
  737. // We have a valid directory name
  738. //
  739. PCHAR p;
  740. if((p = DnDupString(DirName)) == NULL) {
  741. DnFatalError(&DnsOutOfMemory);
  742. }
  743. RememberOptionalDir(p, OPTDIR_OEMOPT);
  744. FREE (DirName);
  745. }
  746. }
  747. //
  748. // If this an OEM pre-install, build a list with the name of all
  749. // OEM boot files.
  750. //
  751. if (DnSearchINFSection(ScriptHandle, WINNT_OEMBOOTFILES)) {
  752. unsigned LineIndex;
  753. PCHAR FileName;
  754. //
  755. // Add the OEM boot files to the array of
  756. // OEM boot files.
  757. //
  758. for( LineIndex = 0;
  759. ((FileName = DnGetSectionLineIndex(ScriptHandle,WINNT_OEMBOOTFILES,LineIndex,0)) != NULL );
  760. LineIndex++ ) {
  761. PCHAR q;
  762. if((q = DnDupString(FileName)) == NULL) {
  763. DnFatalError(&DnsOutOfMemory);
  764. }
  765. RememberOemBootFile(q);
  766. FREE (FileName);
  767. }
  768. }
  769. }
  770. }
  771. //
  772. // We are done with the ScriptHandle for now
  773. //
  774. DnFreeINFBuffer(ScriptHandle);
  775. }
  776. BOOLEAN
  777. DnpParseArguments(
  778. IN int argc,
  779. IN char *argv[]
  780. )
  781. /*++
  782. Routine Description:
  783. Parse arguments passed to the program. Perform syntactic validation
  784. and fill in defaults where necessary.
  785. Valid arguments:
  786. /d:path - specify installation to remove
  787. (not supported anymore)
  788. /s:sharepoint[path] - specify source sharepoint and path on it
  789. /t:drive[:] - specify temporary local source drive
  790. /i:filename - specify name of inf file
  791. /o - create boot floppies only
  792. (not supported anymore)
  793. /f - turn floppy verification off
  794. (not supported anymore)
  795. /c - suppress free-space check on the floppy
  796. (not supported anymore)
  797. /x - suppress creation of the floppy altogether
  798. /b - floppyless operation
  799. (not supported anymore)
  800. /u - unattended (skip final reboot screen)
  801. /w - [undoc'ed] must be specifed when running
  802. under windows, chicago, etc.
  803. /a - enable accessibility options
  804. /2 - copy the entire source locally - all files irrespective
  805. of the d1/d2 tags. Default is only d1 tagged files.
  806. Introduced for the 2 CD install that is required tablets.
  807. Arguments:
  808. argc - # arguments
  809. argv - array of pointers to arguments
  810. Return Value:
  811. None.
  812. --*/
  813. {
  814. PCHAR arg;
  815. CHAR swit;
  816. PCHAR ArgSwitches[] = { "E", "D", "T", "I", "RX", "R", "S", NULL };
  817. PCHAR RestOfSwitch;
  818. int i;
  819. int l;
  820. //
  821. // Set the variables that are no longer
  822. // settable via the command line.
  823. //
  824. DngFloppyless = TRUE;
  825. DngCreateFloppies = FALSE;
  826. //
  827. // Skip program name
  828. //
  829. argv++;
  830. DeleteGiven = SourceGiven = TargetGiven = FALSE;
  831. OptionalDirCount = 0;
  832. CmdLineTarget = CmdLineInf = NULL;
  833. while(--argc) {
  834. if((**argv == '-') || (**argv == '/')) {
  835. swit = argv[0][1];
  836. //
  837. // Process switches that take no arguments here.
  838. //
  839. switch(swit) {
  840. case '?':
  841. return(FALSE); // force usage
  842. #if 0
  843. case 'f':
  844. case 'F':
  845. argv++;
  846. DngFloppyVerify = FALSE;
  847. continue;
  848. #endif
  849. #if 0
  850. case 'c':
  851. case 'C':
  852. argv++;
  853. DngCheckFloppySpace = FALSE;
  854. continue;
  855. #endif
  856. #if 0
  857. case 'x':
  858. case 'X':
  859. argv++;
  860. DngCreateFloppies = FALSE;
  861. continue;
  862. #endif
  863. #ifdef LOGGING
  864. case 'l':
  865. case 'L':
  866. argv++;
  867. StartLog();
  868. continue;
  869. #endif
  870. #if 0
  871. case 'o':
  872. case 'O':
  873. //
  874. // check for /Ox. /O* is a secret switch that replaces the old /o.
  875. //
  876. switch(argv[0][2]) {
  877. case 'x':
  878. case 'X':
  879. DngWinntFloppies = FALSE;
  880. case '*':
  881. break;
  882. default:
  883. return(FALSE);
  884. }
  885. argv++;
  886. DngFloppiesOnly = TRUE;
  887. continue;
  888. #endif
  889. #if 0
  890. case 'b':
  891. case 'B':
  892. argv++;
  893. DngFloppyless = TRUE;
  894. continue;
  895. #endif
  896. case 'u':
  897. case 'U':
  898. if(((argv[0][2] == 'd') || (argv[0][2] == 'D'))
  899. && ((argv[0][3] == 'f') || (argv[0][3] == 'F'))) {
  900. if((argv[0][4] == ':') && argv[0][5]) {
  901. if((arg = strchr(&argv[0][5],',')) == NULL) {
  902. arg = strchr(&argv[0][5],0);
  903. }
  904. l = arg - &argv[0][5];
  905. UniquenessId = MALLOC(l+2,TRUE);
  906. memcpy(UniquenessId,&argv[0][5],l);
  907. UniquenessId[l] = 0;
  908. if(*arg++) {
  909. if(*arg) {
  910. //
  911. // Now the rest of the param is the filename of
  912. // the uniqueness database
  913. //
  914. UniquenessDatabaseFile = DnDupString(arg);
  915. UniquenessId[l] = '*';
  916. UniquenessId[l+1] = 0;
  917. } else {
  918. return(FALSE);
  919. }
  920. }
  921. } else {
  922. return(FALSE);
  923. }
  924. } else {
  925. DngUnattended = TRUE;
  926. //
  927. // User can say -u:<file> also
  928. //
  929. if(argv[0][2] == ':') {
  930. if(argv[0][3] == 0) {
  931. return(FALSE);
  932. }
  933. if((DngScriptFile = DnDupString(&argv[0][3])) == NULL) {
  934. DnFatalError(&DnsOutOfMemory);
  935. }
  936. }
  937. }
  938. argv++;
  939. continue;
  940. case 'w':
  941. case 'W':
  942. //
  943. // This flag used to force us to run under Windows,
  944. // when doing a 386 stepping check could crash the system.
  945. // Now we don't support 386, so this check is never done.
  946. //
  947. // However we accept the arg to force us into Windows mode on DOS,
  948. // which allows someone to avoid the final reboot.
  949. //
  950. DngWindows = TRUE;
  951. argv++;
  952. continue;
  953. case 'a':
  954. case 'A':
  955. argv++;
  956. DngAccessibility = TRUE;
  957. continue;
  958. #ifdef TEDM
  959. case 'i':
  960. case 'I':
  961. if(!stricmp(argv[0]+1,"I_am_TedM")) {
  962. argv++;
  963. DngAllowNt = TRUE;
  964. continue;
  965. }
  966. #endif
  967. case '2':
  968. argv++;
  969. DngCopyOnlyD1TaggedFiles = FALSE;
  970. //_LOG(("Going to copy files irrespective of the directory tag\n"));
  971. continue;
  972. }
  973. //
  974. // Process switches that take arguments here.
  975. //
  976. //
  977. // This code taken from winnt32.c. It has the
  978. // purpose of validating the switch and determining
  979. // where the next argument lines
  980. //
  981. for (i=0; ArgSwitches[i]; i++) {
  982. l = strlen(ArgSwitches[i]);
  983. if (!strnicmp(ArgSwitches[i],&argv[0][1],l)) {
  984. //
  985. // we have a match. Next char of arg must either
  986. // be : or nul. If it's : then arg immediately
  987. // follows. Otherwise, if it's null, then arg must
  988. // be next argument
  989. //
  990. if (argv[0][1+l] == ':') {
  991. arg = &argv[0][2+l];
  992. if (*arg == '\0') {
  993. return (FALSE);
  994. }
  995. RestOfSwitch = &argv[0][2];
  996. break;
  997. } else {
  998. if (argv[0][1+l] == '\0') {
  999. if (argc <= 1) {
  1000. //
  1001. // no arguments left
  1002. //
  1003. return (FALSE);
  1004. }
  1005. RestOfSwitch = &argv[0][2];
  1006. argc--;
  1007. arg = argv[1];
  1008. argv++;
  1009. break;
  1010. } else {
  1011. //
  1012. // Do nothing here
  1013. //
  1014. NULL;
  1015. } // if ... else
  1016. } // if ... else
  1017. } // if ...
  1018. } // for
  1019. //
  1020. // Check termination condition
  1021. //
  1022. if (!ArgSwitches[i]) {
  1023. return (FALSE);
  1024. }
  1025. switch(swit) {
  1026. case 'r':
  1027. case 'R':
  1028. RememberOptionalDir(
  1029. DnDupString(arg),
  1030. ( (RestOfSwitch[0] == 'X' || RestOfSwitch[0] == 'x') ?
  1031. OPTDIR_TEMPONLY : 0 ) );
  1032. break;
  1033. case 'd':
  1034. case 'D':
  1035. //
  1036. // /D is no longer supported
  1037. //
  1038. DeleteGiven = TRUE;
  1039. return(FALSE);
  1040. #if 0
  1041. case 'd':
  1042. case 'D':
  1043. if(DeleteGiven) {
  1044. return(FALSE);
  1045. } else {
  1046. if((CmdLineDelete = DnDupString(arg)) == NULL) {
  1047. DnFatalError(&DnsOutOfMemory);
  1048. }
  1049. DeleteGiven = TRUE;
  1050. }
  1051. break;
  1052. #endif
  1053. case 's':
  1054. case 'S':
  1055. if(SourceGiven) {
  1056. return(FALSE);
  1057. } else {
  1058. if((CmdLineSource = DnDupString(arg)) == NULL) {
  1059. DnFatalError(&DnsOutOfMemory);
  1060. }
  1061. SourceGiven = TRUE;
  1062. }
  1063. break;
  1064. case 't':
  1065. case 'T':
  1066. if(TargetGiven) {
  1067. return(FALSE);
  1068. } else {
  1069. if((CmdLineTarget = DnDupString(arg)) == NULL) {
  1070. DnFatalError(&DnsOutOfMemory);
  1071. }
  1072. TargetGiven = TRUE;
  1073. }
  1074. break;
  1075. case 'i':
  1076. case 'I':
  1077. if(InfGiven) {
  1078. return(FALSE);
  1079. } else {
  1080. if((CmdLineInf = DnDupString(arg)) == NULL) {
  1081. DnFatalError(&DnsOutOfMemory);
  1082. }
  1083. InfGiven = TRUE;
  1084. }
  1085. break;
  1086. case 'E':
  1087. case 'e':
  1088. if(CmdToExecuteAtEndOfGui) {
  1089. return(FALSE);
  1090. } else {
  1091. if((CmdToExecuteAtEndOfGui = DnDupString(arg)) == NULL) {
  1092. DnFatalError(&DnsOutOfMemory);
  1093. }
  1094. }
  1095. break;
  1096. default:
  1097. return(FALSE);
  1098. }
  1099. } else {
  1100. return(FALSE);
  1101. }
  1102. argv++;
  1103. }
  1104. //
  1105. // If /u was specified, make sure /s was also given
  1106. // and force /b.
  1107. //
  1108. if(DngUnattended) {
  1109. if(!SourceGiven) {
  1110. return(FALSE);
  1111. }
  1112. DngFloppyless = TRUE;
  1113. }
  1114. if(DngFloppyless) {
  1115. //
  1116. // Force us into the floppy creation code.
  1117. //
  1118. DngCreateFloppies = TRUE;
  1119. DngWinntFloppies = TRUE;
  1120. }
  1121. return(TRUE);
  1122. }
  1123. VOID
  1124. DnpGetAccessibilityOptions(
  1125. VOID
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. Ask the user which accessibility utilities to install for GUI Setup.
  1130. Arguments:
  1131. None.
  1132. Return Value:
  1133. None.
  1134. --*/
  1135. {
  1136. ULONG ValidKey[4];
  1137. ULONG Key;
  1138. CHAR Mark;
  1139. //
  1140. // Make sure the setup boot floppy we created is in the drive
  1141. // if necessary.
  1142. //
  1143. DnClearClientArea();
  1144. DnDisplayScreen(&DnsAccessibilityOptions);
  1145. DnWriteStatusText(DntEnterEqualsContinue);
  1146. ValidKey[0] = ASCI_CR;
  1147. ValidKey[1] = DN_KEY_F1;
  1148. ValidKey[2] = DN_KEY_F2;
  1149. ValidKey[3] = 0;
  1150. while((Key = DnGetValidKey(ValidKey)) != ASCI_CR) {
  1151. switch(Key) {
  1152. case DN_KEY_F1:
  1153. DngMagnifier = (BOOLEAN)!DngMagnifier;
  1154. Mark = DngMagnifier ? RADIO_ON : RADIO_OFF;
  1155. DnPositionCursor(4,7);
  1156. break;
  1157. case DN_KEY_F2:
  1158. DngTalker = (BOOLEAN)!DngTalker;
  1159. Mark = DngTalker ? RADIO_ON : RADIO_OFF;
  1160. DnPositionCursor(4,8);
  1161. break;
  1162. #if 0
  1163. case DN_KEY_F3:
  1164. DngKeyboard = (BOOLEAN)!DngKeyboard;
  1165. Mark = DngKeyboard ? RADIO_ON : RADIO_OFF;
  1166. DnPositionCursor(4,9);
  1167. break;
  1168. #endif
  1169. }
  1170. DnWriteChar(Mark);
  1171. }
  1172. }
  1173. VOID
  1174. DnpValidateAndConnectToShare(
  1175. FILE **InfFileHandle,
  1176. FILE **DrvindexInfFileHandle
  1177. )
  1178. /*++
  1179. Routine Description:
  1180. Split the source given by the user into drive and path
  1181. components. If the user did not specify a source, prompt him
  1182. for one. Look for dos2nt.inf on the source (ie, validate the
  1183. source) and keep prompting the user for a share until he enters
  1184. one which appears to be valid.
  1185. Arguments:
  1186. Return Value:
  1187. None.
  1188. --*/
  1189. {
  1190. CHAR UserString[256];
  1191. PCHAR InfFullName, DrvindexInfFullName;
  1192. PCHAR q;
  1193. BOOLEAN ValidSourcePath;
  1194. unsigned len;
  1195. DnClearClientArea();
  1196. DnWriteStatusText(NULL);
  1197. //
  1198. // Use default inf file if none specified.
  1199. //
  1200. if(!InfGiven) {
  1201. CmdLineInf = DEFAULT_INF_NAME;
  1202. }
  1203. //
  1204. // If the user did not enter a source, prompt him for one.
  1205. //
  1206. if(SourceGiven) {
  1207. strcpy(UserString,CmdLineSource);
  1208. } else {
  1209. #if NEC_98
  1210. CursorOnFlag = TRUE;
  1211. #endif // NEC_98
  1212. DnDisplayScreen(&DnsNoShareGiven);
  1213. DnWriteStatusText("%s %s",DntEnterEqualsContinue,DntF3EqualsExit);
  1214. if(getcwd(UserString,sizeof(UserString)-1) == NULL) {
  1215. UserString[0] = '\0';
  1216. }
  1217. #if NEC_98
  1218. CursorOnFlag = FALSE;
  1219. #endif // NEC_98
  1220. DnGetString(UserString,NO_SHARE_X,NO_SHARE_Y,NO_SHARE_W);
  1221. }
  1222. ValidSourcePath = FALSE;
  1223. do {
  1224. DnWriteStatusText(DntOpeningInfFile);
  1225. //
  1226. // Make a copy of the path the user typed leaving extra room.
  1227. //
  1228. DngSourceRootPath = MALLOC(256,TRUE);
  1229. if(len = strlen(UserString)) {
  1230. strcpy(DngSourceRootPath,UserString);
  1231. //
  1232. // If the user typed something like x:, then we want to
  1233. // change that to x:. so this does what he expects.
  1234. // Doing so also lets the canonicalize routine work.
  1235. //
  1236. if((DngSourceRootPath[1] == ':') && !DngSourceRootPath[2]) {
  1237. DngSourceRootPath[2] = '.';
  1238. DngSourceRootPath[3] = 0;
  1239. }
  1240. //
  1241. // Now attempt to canonicalize the name. If this doesn't work,
  1242. // then it's definitely not a valid path.
  1243. //
  1244. if(DnCanonicalizePath(DngSourceRootPath,UserString)) {
  1245. strcpy(DngSourceRootPath,UserString);
  1246. //
  1247. // If the path doesn't end with a backslash,
  1248. // append a backslash before appending the inf filename.
  1249. //
  1250. len = strlen(DngSourceRootPath);
  1251. if(DngSourceRootPath[len-1] != '\\') {
  1252. DngSourceRootPath[len] = '\\';
  1253. DngSourceRootPath[len+1] = 0;
  1254. len++;
  1255. }
  1256. InfFullName = MALLOC(len + strlen(CmdLineInf) + 1,TRUE);
  1257. strcpy(InfFullName,DngSourceRootPath);
  1258. strcat(InfFullName,CmdLineInf);
  1259. DrvindexInfFullName = MALLOC(len + strlen(DrvindexInfName) + 1,TRUE);
  1260. strcpy(DrvindexInfFullName,DngSourceRootPath);
  1261. strcat(DrvindexInfFullName,DrvindexInfName);
  1262. //
  1263. // Attempt to open the inf file on the source.
  1264. // If that fails look for it in the i386 subdirectory.
  1265. //
  1266. //_LOG(("Validate source path: trying %s\n",InfFullName));
  1267. //_LOG(("Validate source path: trying %s\n",DrvindexInfFullName));
  1268. if((*InfFileHandle = fopen(InfFullName,"rt")) != NULL){
  1269. if((*DrvindexInfFileHandle = fopen(DrvindexInfFullName,"rt")) != NULL){
  1270. ValidSourcePath = TRUE;
  1271. }
  1272. else
  1273. fclose( *InfFileHandle );
  1274. }
  1275. if(*InfFileHandle != NULL ){
  1276. //_LOG(("%s opened successfully\n",InfFullName));
  1277. }
  1278. if(*DrvindexInfFileHandle != NULL ){
  1279. //_LOG(("%s opened successfully\n",DrvindexInfFullName));
  1280. }
  1281. FREE(InfFullName);
  1282. FREE(DrvindexInfFullName);
  1283. if(!ValidSourcePath) {
  1284. InfFullName = MALLOC(len+strlen(CmdLineInf)+strlen(x86DirName)+1,TRUE);
  1285. DrvindexInfFullName = MALLOC(len+strlen(DrvindexInfName)+strlen(x86DirName)+1,TRUE);
  1286. strcpy(InfFullName,DngSourceRootPath);
  1287. strcat(InfFullName,x86DirName+1);
  1288. strcat(InfFullName,"\\");
  1289. strcpy(DrvindexInfFullName, InfFullName);
  1290. strcat(InfFullName,CmdLineInf);
  1291. strcat(DrvindexInfFullName,DrvindexInfName);
  1292. //_LOG(("Validate source path: trying %s\n",InfFullName));
  1293. if((*InfFileHandle = fopen(InfFullName,"rt")) != NULL){
  1294. if((*DrvindexInfFileHandle = fopen(DrvindexInfFullName,"rt")) != NULL){
  1295. ValidSourcePath = TRUE;
  1296. }
  1297. else
  1298. fclose( *InfFileHandle );
  1299. }
  1300. if(*InfFileHandle != NULL ){
  1301. //_LOG(("%s opened successfully\n",InfFullName));
  1302. }
  1303. if(*DrvindexInfFileHandle != NULL ){
  1304. //_LOG(("%s opened successfully\n",DrvindexInfFullName));
  1305. }
  1306. FREE(InfFullName);
  1307. FREE(DrvindexInfFullName);
  1308. if(ValidSourcePath) {
  1309. //
  1310. // Change the source to the i386 subdirectory.
  1311. //
  1312. q = DngSourceRootPath;
  1313. DngSourceRootPath = MALLOC(strlen(q)+strlen(x86DirName),TRUE);
  1314. strcpy(DngSourceRootPath,q);
  1315. strcat(DngSourceRootPath,x86DirName+1);
  1316. FREE(q);
  1317. }
  1318. }
  1319. }
  1320. }
  1321. if(!ValidSourcePath) {
  1322. FREE(DngSourceRootPath);
  1323. DnClearClientArea();
  1324. #if NEC_98
  1325. CursorOnFlag = TRUE;
  1326. #endif // NEC_98
  1327. DnDisplayScreen(&DnsBadSource);
  1328. DnWriteStatusText("%s %s",DntEnterEqualsContinue,DntF3EqualsExit);
  1329. #if NEC_98
  1330. CursorOnFlag = FALSE;
  1331. #endif // NEC_98
  1332. DnGetString(UserString,NO_SHARE_X,BAD_SHARE_Y,NO_SHARE_W);
  1333. }
  1334. } while(!ValidSourcePath);
  1335. //
  1336. // Make sure DngSourceRootPath does not end with a backslash.
  1337. // and trim the buffer down to size.
  1338. //
  1339. len = strlen(DngSourceRootPath);
  1340. if(DngSourceRootPath[len-1] == '\\') {
  1341. DngSourceRootPath[len-1] = 0;
  1342. }
  1343. if(q = DnDupString(DngSourceRootPath)) {
  1344. FREE(DngSourceRootPath);
  1345. DngSourceRootPath = q;
  1346. }
  1347. _LOG(("Source root path is %s\n",DngSourceRootPath));
  1348. }
  1349. VOID
  1350. DnRemoveTrailingSlashes(
  1351. PCHAR Path
  1352. )
  1353. {
  1354. if (Path != NULL && Path[0] != 0) {
  1355. int Length = strlen(Path);
  1356. while (Path[Length - 1] == '\\' || Path[Length - 1] == '/') {
  1357. Length -= 1;
  1358. }
  1359. Path[Length] = 0;
  1360. }
  1361. }
  1362. VOID
  1363. DnRemoveLastPathElement(
  1364. PCHAR Path
  1365. )
  1366. {
  1367. PCHAR LastBackSlash = strrchr(Path, '\\');
  1368. if (LastBackSlash != NULL) {
  1369. *(LastBackSlash + 1) = 0;
  1370. }
  1371. }
  1372. VOID
  1373. DnpReadInf(
  1374. IN FILE *InfFileHandle,
  1375. IN FILE *DrvindexInfFileHandle
  1376. )
  1377. /*++
  1378. Routine Description:
  1379. Read the INF file. Does not return if error.
  1380. Arguments:
  1381. None.
  1382. Return Value:
  1383. None.
  1384. --*/
  1385. {
  1386. int Status;
  1387. PCHAR p;
  1388. PCHAR pchHeader;
  1389. unsigned LineNumber, DLineNumber;
  1390. DnWriteStatusText(DntReadingInf,CmdLineInf);
  1391. DnClearClientArea();
  1392. LineNumber = 0;
  1393. Status = DnInitINFBuffer (InfFileHandle, &DngInfHandle, &LineNumber);
  1394. if(Status == ENOMEM) {
  1395. DnFatalError(&DnsOutOfMemory);
  1396. } else if(Status) {
  1397. DnFatalError(&DnsBadInf);
  1398. }
  1399. DLineNumber = 0;
  1400. Status = DnInitINFBuffer (DrvindexInfFileHandle, &DngDrvindexInfHandle, &DLineNumber);
  1401. if(Status == ENOMEM) {
  1402. DnFatalError(&DnsOutOfMemory);
  1403. } else if(Status) {
  1404. DnFatalError(&DnsBadInf);
  1405. }
  1406. //
  1407. // Determine product type (workstation/server)
  1408. //
  1409. p = DnGetSectionKeyIndex(DngInfHandle,DnfMiscellaneous,"ProductType",0);
  1410. pchHeader = DntWorkstationHeader; // default to workstation
  1411. if(p && atoi(p)) {
  1412. switch(atoi(p)) {
  1413. case 4:
  1414. pchHeader = DntPersonalHeader;
  1415. break;
  1416. case 1: //server
  1417. case 2: //enterprise
  1418. case 3: //datacenter
  1419. default:
  1420. pchHeader = DntServerHeader;
  1421. DngServer = TRUE;
  1422. break;
  1423. }
  1424. }
  1425. if (p) {
  1426. FREE (p);
  1427. }
  1428. DnPositionCursor(0,0);
  1429. DnWriteString(pchHeader);
  1430. //
  1431. // Get mandatory optional components
  1432. //
  1433. LineNumber = 0;
  1434. while(p = DnGetSectionLineIndex(DngInfHandle,"OptionalSrcDirs",LineNumber++,0)) {
  1435. PCHAR q;
  1436. if((q = DnDupString(p)) == NULL) {
  1437. DnFatalError(&DnsOutOfMemory);
  1438. }
  1439. RememberOptionalDir(q, OPTDIR_TEMPONLY);
  1440. FREE (p);
  1441. }
  1442. //
  1443. // get Fusion Side By Side Assemblies ("sxs_" here for searching)
  1444. //
  1445. {
  1446. //
  1447. // first get the asms directory
  1448. //
  1449. struct find_t FindData;
  1450. unsigned InfSectionLineNumber = 0;
  1451. PCHAR InfValue;
  1452. unsigned optdirFlags;
  1453. CHAR SourceDir[DOS_MAX_PATH];
  1454. PCHAR DupInfValue;
  1455. PCHAR FreeInfValue;
  1456. while(InfValue = DnGetSectionLineIndex(DngInfHandle, DnfAssemblyDirectories, InfSectionLineNumber++, 0)) {
  1457. //
  1458. // convention introduced specifically for side by side, so that
  1459. // x86 files on ia64 might come from \i386\asms instead of \ia64\asms\i386,
  1460. // depending on what dosnet.inf and syssetup.inf say:
  1461. // a path that does not start with a slash is appended to \$win_nt$.~ls\processor;
  1462. // a path that does start with a slash is appended to \$win_nt$.~ls
  1463. //
  1464. // We honor it in x86-only winnt.exe in case anyone decides to use it
  1465. // for other reasons, to keep parity in this area between winnt and winnt32.exe.
  1466. optdirFlags = OPTDIR_TEMPONLY;
  1467. strcpy(SourceDir, DngSourceRootPath); // includes trailing i386
  1468. FreeInfValue = InfValue;
  1469. if (InfValue[0] == '\\' || InfValue[0] == '/') {
  1470. optdirFlags |= OPTDIR_PLATFORM_INDEP;
  1471. // remove trailing i386
  1472. DnRemoveTrailingSlashes(SourceDir);
  1473. DnRemoveLastPathElement(SourceDir);
  1474. // remove leading slash
  1475. InfValue += 1;
  1476. }
  1477. DnpConcatPaths(SourceDir, InfValue);
  1478. //
  1479. // The asms directory is optional because there might just be asms*.cab.
  1480. //
  1481. if (_dos_findfirst(SourceDir, _A_HIDDEN|_A_SYSTEM|_A_SUBDIR, &FindData) == 0
  1482. && (FindData.attrib & _A_SUBDIR)) {
  1483. if((DupInfValue = DnDupString(InfValue)) == NULL) {
  1484. DnFatalError(&DnsOutOfMemory);
  1485. }
  1486. RememberOptionalDir(DupInfValue, optdirFlags);
  1487. FREE(FreeInfValue);
  1488. }
  1489. }
  1490. }
  1491. }
  1492. VOID
  1493. DnpCheckEnvironment(
  1494. VOID
  1495. )
  1496. /*++
  1497. Routine Description:
  1498. Verify that the following are true:
  1499. - DOS major version 5 or greater
  1500. - there is a floppy drive at a: that is 1.2 meg or greater
  1501. If any of the above are not true, abort with a fatal error.
  1502. Arguments:
  1503. None.
  1504. Return Value:
  1505. None.
  1506. --*/
  1507. {
  1508. UCHAR DeviceParams[256];
  1509. unsigned char _near * pDeviceParams = DeviceParams;
  1510. DnWriteStatusText(DntInspectingComputer);
  1511. DeviceParams[0] = 0; // get default device params
  1512. _asm {
  1513. //
  1514. // Check if we're on NT.
  1515. // The true version on NT is 5.50.
  1516. //
  1517. mov ax,3306h
  1518. sub bx,bx
  1519. int 21h
  1520. cmp bx,3205h // check for v. 5.50
  1521. jne checkwin
  1522. #ifdef TEDM
  1523. cmp DngAllowNt,1
  1524. je checkflop
  1525. #endif
  1526. bados:
  1527. push seg DnsCantRunOnNt
  1528. push offset DnsCantRunOnNt
  1529. call DnFatalError // doesn't return
  1530. checkwin:
  1531. //
  1532. // The /w switch used to be necessary since we could crash Windows
  1533. // checking the CPU stepping on a 386. However since we don't support
  1534. // 386 any more, we never do that check and we can simply detect
  1535. // whether we're on Windows. The /w switch is not necessary.
  1536. //
  1537. mov ax,1600h
  1538. int 2fh
  1539. test al,7fh
  1540. jz checkcpu
  1541. mov DngWindows,1
  1542. //
  1543. // Now check Win95. Issue int2f func 4a33.
  1544. // If ax comes back as 0 then it's win95.
  1545. //
  1546. push ds
  1547. push si
  1548. push dx
  1549. push bx
  1550. mov ax,4a33h
  1551. int 2fh
  1552. pop bx
  1553. pop dx
  1554. pop si
  1555. pop ds
  1556. cmp ax,0
  1557. jz bados
  1558. checkcpu:
  1559. //
  1560. // Check CPU type. Fail if not greater than 386.
  1561. //
  1562. call HwGetProcessorType
  1563. cmp ax,3
  1564. ja checkflop
  1565. push seg DnsRequires486
  1566. push offset DnsRequires486
  1567. call DnFatalError // doesn't return
  1568. checkflop:
  1569. //
  1570. // If this is not a floppyless installation, check for 1.2MB
  1571. // or greater A:. Get the default device params for drive A:
  1572. // and check the device type field.
  1573. //
  1574. #if NEC_98
  1575. #else // NEC_98
  1576. cmp DngFloppyless,1 // floppyless installation?
  1577. je checkdosver // yes, no floppy drive required
  1578. mov ax,440dh // ioctl
  1579. mov bl,1 // drive a:
  1580. mov cx,860h // category disk, func get params
  1581. mov dx,pDeviceParams // ds is already correct
  1582. int 21h
  1583. jnc gotdevparams
  1584. flopperr:
  1585. push seg DnsRequiresFloppy
  1586. push offset DnsRequiresFloppy
  1587. call DnFatalError // doesn't return
  1588. gotdevparams:
  1589. //
  1590. // Check to make sure that the device is removable and perform
  1591. // checks on the media type
  1592. //
  1593. mov si,pDeviceParams
  1594. test [si+2],1 // bit 0 clear if removable
  1595. jnz flopperr
  1596. #ifdef ALLOW_525
  1597. cmp [si+1],1 // media type = 1.2meg floppy?
  1598. jz checkdosver
  1599. #endif
  1600. cmp [si+1],7 // media type = 1.4meg floppy
  1601. jb flopperr // or greater?
  1602. checkdosver:
  1603. #endif // NEC_98
  1604. //
  1605. // Check DOS version >= 5.0
  1606. //
  1607. mov ax,3000h // function 30h -- get DOS version
  1608. int 21h
  1609. cmp al,5
  1610. jae checkdone // >= 5.0
  1611. //
  1612. // version < 5
  1613. //
  1614. push seg DnsBadDosVersion
  1615. push offset DnsBadDosVersion
  1616. call DnFatalError
  1617. checkdone:
  1618. }
  1619. }
  1620. VOID
  1621. DnpCheckMemory(
  1622. VOID
  1623. )
  1624. /*++
  1625. Routine Description:
  1626. Verify that enough memory is installed in the machine.
  1627. Arguments:
  1628. None.
  1629. Return Value:
  1630. None. Does not return in there's not enough memory.
  1631. --*/
  1632. {
  1633. USHORT MemoryK;
  1634. ULONG TotalMemory,RequiredMemory;
  1635. PCHAR RequiredMemoryStr;
  1636. //
  1637. // Now that servers require so much memory (64Mb), just remove this check.
  1638. // We'll catch him in textmode.
  1639. // -matth
  1640. //
  1641. return;
  1642. DnWriteStatusText(DntInspectingComputer);
  1643. //
  1644. // I cannot figure out a reliable way to determine the amount of
  1645. // memory in the machine. Int 15 func 88 is likely to be hooked by
  1646. // himem.sys or some other memory manager to return 0. DOS maintains
  1647. // the original amount of extended memory but to get to this value
  1648. // you have to execute the sysvars undocumented int21 ah=52 call, and
  1649. // even then what about versions previous to dos 4? Calling himem to
  1650. // ask for the total amount of xms memory does not give you the total
  1651. // amount of extended memory, just the amount of xms memory.
  1652. // So we'll short-circuit the memory check code by always deciding that
  1653. // there's 50MB of extended memory. This should always be big enough,
  1654. // and this way the rest of the code stays intact, ready to work if
  1655. // we figure out a way to make the memory determination. Just replace
  1656. // the following line with the check, and make sure MemoryK is set to
  1657. // the amount of extended memory in K.
  1658. //
  1659. // Update: one might be able to get the amount of extended memory by
  1660. // looking in CMOS. See the code below.
  1661. // The only problem with this is that it cannot detect more than 63MB
  1662. // of extended memory. This should be good for now, since this is
  1663. // enough even for NT server.
  1664. //
  1665. _asm {
  1666. //
  1667. // This code access to I/O ports 70H and 71H.
  1668. // But these port are different feature on NEC98.
  1669. // The 70H port is Character Display controller's port.
  1670. // So, if this code running(out 70h, 18h) on NEC98, display
  1671. // setting will be broken and garbage characters displayed.
  1672. //
  1673. #if NEC_98
  1674. push ax
  1675. push es
  1676. mov ax, 40h
  1677. mov es, ax
  1678. xor ax, ax
  1679. mov al, es:[1] // 1M - 16M memories(per 128K)
  1680. shr ax, 3 // convert MB
  1681. add ax, es:[194h] // Over 16M memories(per 1M)
  1682. mov MemoryK,ax
  1683. pop es
  1684. pop ax
  1685. #else // NEC_98
  1686. push ax
  1687. cli
  1688. mov al, 18h // get extended memory high
  1689. out 70h, al
  1690. jmp short $+2
  1691. in al, 71H
  1692. shl ax, 08H
  1693. mov al, 17H // get extended memory low
  1694. out 70H, al
  1695. jmp short $+2
  1696. in al, 71H
  1697. mov MemoryK,ax
  1698. sti
  1699. pop ax
  1700. #endif // NEC_98
  1701. }
  1702. //
  1703. // Account for conventional memory. Simplistic, but good enough.
  1704. //
  1705. #if NEC_98
  1706. MemoryK *= 1024;
  1707. MemoryK += 640;
  1708. #else // NEC_98
  1709. MemoryK += 1024;
  1710. #endif // NEC_98
  1711. TotalMemory = (ULONG)MemoryK * 1024L;
  1712. RequiredMemoryStr = DnGetSectionKeyIndex( DngInfHandle,
  1713. DnfMiscellaneous,
  1714. DnkMinimumMemory,
  1715. 0
  1716. );
  1717. //
  1718. // If the required memory is not specified in the inf, force an error
  1719. // to get someone's attention so we can fix dosnet.inf.
  1720. //
  1721. RequiredMemory = RequiredMemoryStr ? (ULONG)atol(RequiredMemoryStr) : 0xffffffff;
  1722. if (RequiredMemoryStr) {
  1723. FREE (RequiredMemoryStr);
  1724. }
  1725. if(TotalMemory < RequiredMemory) {
  1726. CHAR Decimal[10];
  1727. ULONG r;
  1728. CHAR Line1[100],Line2[100];
  1729. r = ((RequiredMemory % (1024L*1024L)) * 100L) / (1024L*1024L);
  1730. if(r) {
  1731. sprintf(Decimal,".%lu",r);
  1732. } else {
  1733. Decimal[0] = 0;
  1734. }
  1735. snprintf(Line1,sizeof(Line1),DnsNotEnoughMemory.Strings[NOMEM_LINE1],RequiredMemory/(1024L*1024L),Decimal);
  1736. DnsNotEnoughMemory.Strings[NOMEM_LINE1] = Line1;
  1737. r = ((TotalMemory % (1024L*1024L)) * 100L) / (1024L*1024L);
  1738. if(r) {
  1739. sprintf(Decimal,".%lu",r);
  1740. } else {
  1741. Decimal[0] = 0;
  1742. }
  1743. snprintf(Line2,sizeof(Line2),DnsNotEnoughMemory.Strings[NOMEM_LINE2],TotalMemory/(1024L*1024L),Decimal);
  1744. DnsNotEnoughMemory.Strings[NOMEM_LINE2] = Line2;
  1745. DnFatalError(&DnsNotEnoughMemory);
  1746. }
  1747. }
  1748. VOID
  1749. DnpCheckSmartdrv(
  1750. VOID
  1751. )
  1752. /*++
  1753. Routine Description:
  1754. Verify that SMARTDRV is installed in the machine.
  1755. Arguments:
  1756. None.
  1757. Return Value:
  1758. None. If SMARTDRV is not installed we recommend the user to install it.
  1759. They have a chance to quit setup or to go on without SMARTDRV.
  1760. --*/
  1761. {
  1762. ULONG ValidKey[3];
  1763. ULONG c;
  1764. USHORT sinst = 0;
  1765. if (!DngUnattended) {
  1766. _asm {
  1767. push ax
  1768. push bx
  1769. push cx
  1770. push dx
  1771. push di
  1772. push si
  1773. push bp
  1774. mov ax, 4a10h
  1775. xor bx, bx
  1776. mov cx, 0ebabh
  1777. int 2fh
  1778. cmp ax, 0babeh
  1779. jne final
  1780. pop bp
  1781. mov sinst, 1
  1782. push bp
  1783. final:
  1784. pop bp
  1785. pop si
  1786. pop di
  1787. pop dx
  1788. pop cx
  1789. pop bx
  1790. pop ax
  1791. }
  1792. if (!sinst) {
  1793. ValidKey[0] = ASCI_CR;
  1794. ValidKey[1] = DN_KEY_F3;
  1795. ValidKey[2] = 0;
  1796. DnClearClientArea();
  1797. DnDisplayScreen(&DnsNoSmartdrv);
  1798. DnWriteStatusText("%s %s",DntEnterEqualsContinue,DntF3EqualsExit);
  1799. while(1) {
  1800. c = DnGetValidKey(ValidKey);
  1801. if(c == ASCI_CR) {
  1802. break;
  1803. }
  1804. if(c == DN_KEY_F3) {
  1805. DnExitDialog();
  1806. }
  1807. }
  1808. DnClearClientArea();
  1809. }
  1810. }
  1811. }
  1812. void
  1813. _far
  1814. DnInt24(
  1815. unsigned deverror,
  1816. unsigned errcode,
  1817. unsigned _far *devhdr
  1818. )
  1819. /*++
  1820. Routine Description:
  1821. Int24 handler. We do not perform any special actions on a hard error;
  1822. rather we just return FAIL so the caller of the failing api will get
  1823. back an error code and take appropriate action itself.
  1824. This function should never be invoked directly.
  1825. Arguments:
  1826. deverror - supplies the device error code.
  1827. errcode - the DI register passed by MS-DOS to int 24 handlers.
  1828. devhdr - supplies pointer to the device header for the device on which
  1829. the hard error occured.
  1830. Return Value:
  1831. None.
  1832. --*/
  1833. {
  1834. _hardresume(_HARDERR_FAIL);
  1835. }
  1836. VOID
  1837. DnpDetermineSwapDrive(
  1838. VOID
  1839. )
  1840. /*++
  1841. Routine Description:
  1842. Determine the swap drive. We need to be able to write on that drive and
  1843. we need at least 500K free disk space.
  1844. Arguments:
  1845. None.
  1846. Return Value:
  1847. None. Sets the global variable DngSwapDriveLetter.
  1848. --*/
  1849. {
  1850. ULONG CheckingDrive;
  1851. CHAR SystemPartitionDriveLetter, TheDrive, DriveLetter;
  1852. DngSwapDriveLetter = '?';
  1853. #if NEC_98
  1854. SystemPartitionDriveLetter = 'A';
  1855. #else
  1856. SystemPartitionDriveLetter = 'C';
  1857. #endif
  1858. TheDrive = 0;
  1859. for( CheckingDrive = SystemPartitionDriveLetter - 'A'; CheckingDrive < ('Z' - 'A'); CheckingDrive++ ) {
  1860. DriveLetter = (CHAR)('A' + CheckingDrive);
  1861. if (DnpIsValidSwapDrive (DriveLetter, 1L * 1024 * 1024)) {
  1862. TheDrive = (CHAR)('A' + CheckingDrive);
  1863. break;
  1864. }
  1865. }
  1866. if( TheDrive == 0 ) {
  1867. //
  1868. // If there is no valid drive for the swap file, put an error message
  1869. //
  1870. DnFatalError (&DnsNoSwapDrive);
  1871. } else {
  1872. DngSwapDriveLetter = TheDrive;
  1873. }
  1874. }
  1875. BOOLEAN
  1876. DnpIsValidSwapDrive(
  1877. IN CHAR Drive,
  1878. IN ULONG SpaceRequired
  1879. )
  1880. /*++
  1881. Routine Description:
  1882. Determine if a drive is valid as a swap drive.
  1883. To be valid a drive must be extant, non-removable, local, and have
  1884. enough free space on it (as much as SpaceNeeded specifies).
  1885. Arguments:
  1886. Drive - drive letter of drive to check.
  1887. Return Value:
  1888. TRUE if Drive is valid as a swap drive. FALSE otherwise.
  1889. --*/
  1890. {
  1891. unsigned d = (unsigned)toupper(Drive) - (unsigned)'A' + 1;
  1892. struct diskfree_t DiskSpace;
  1893. ULONG SpaceAvailable;
  1894. if( DnIsDriveValid(d)
  1895. && !DnIsDriveRemote(d,NULL)
  1896. && !DnIsDriveRemovable(d))
  1897. {
  1898. //
  1899. // Check free space on the drive.
  1900. //
  1901. if(!_dos_getdiskfree(d,&DiskSpace)) {
  1902. SpaceAvailable = (ULONG)DiskSpace.avail_clusters
  1903. * (ULONG)DiskSpace.sectors_per_cluster
  1904. * (ULONG)DiskSpace.bytes_per_sector;
  1905. return( (BOOLEAN)(SpaceAvailable >= SpaceRequired) );
  1906. }
  1907. }
  1908. return(FALSE);
  1909. }
  1910. VOID
  1911. DnpDetermineLocalSourceDrive(
  1912. VOID
  1913. )
  1914. /*++
  1915. Routine Description:
  1916. Determine the local source drive, ie, the drive that will contain the
  1917. local copy of the windows nt setup source tree. The local source could
  1918. have been passed on the command line, in which case we will validate it.
  1919. If there was no drive specified, examine each drive in the system looking
  1920. for a local, fixed drive with enough free space on it (as specified in
  1921. the inf file).
  1922. Arguments:
  1923. None.
  1924. Return Value:
  1925. None. Sets the global variable DngTargetDriveLetter.
  1926. --*/
  1927. {
  1928. ULONG RequiredSpace;
  1929. ULONG CheckWhichDrives = 0, CheckingDrive;
  1930. CHAR SystemPartitionDriveLetter, TheDrive, DriveLetter;
  1931. DnRemoveLocalSourceTrees();
  1932. DnRemovePagingFiles();
  1933. //
  1934. // Get the space requirements for the main retail files
  1935. //
  1936. DnDetermineSpaceRequirements( SpaceRequirements,
  1937. sizeof( SpaceRequirements ) / sizeof( SPACE_REQUIREMENT ) );
  1938. //
  1939. // Determine the space requirements for the optional directories
  1940. // Note that DnpIterateOptionalDirs() will initialize the global variables
  1941. // TotalOptionalFileCount and TotalOptionalFileCount in dncopy.c with the
  1942. // total number of files in optional directory, and the total number of
  1943. // optional directories, respectively.
  1944. //
  1945. DngTargetDriveLetter = '?';
  1946. DnpIterateOptionalDirs(CPY_VALIDATION_PASS,
  1947. 0,
  1948. SpaceRequirements,
  1949. sizeof( SpaceRequirements ) / sizeof( SPACE_REQUIREMENT ));
  1950. DnAdjustSpaceRequirements( SpaceRequirements,
  1951. sizeof( SpaceRequirements ) / sizeof( SPACE_REQUIREMENT ));
  1952. //
  1953. // Which drives do we need to examine?
  1954. //
  1955. if( DngFloppyless ) {
  1956. //
  1957. // Need to determine the system partition. It is usually C:
  1958. // but if C: is compressed we need to find the host drive.
  1959. //
  1960. unsigned HostDrive;
  1961. if(!DngAllowNt && DnIsDriveCompressedVolume(3,&HostDrive)) {
  1962. CheckWhichDrives |= (0x1 << (HostDrive - 1));
  1963. SystemPartitionDriveLetter = (CHAR)('A' + (HostDrive - 1));
  1964. } else {
  1965. CheckWhichDrives |= (0x1 << 2);
  1966. #if NEC_98
  1967. SystemPartitionDriveLetter = 'A';
  1968. #else
  1969. SystemPartitionDriveLetter = 'C';
  1970. #endif
  1971. }
  1972. }
  1973. if( TargetGiven ) {
  1974. if( DngAllowNt ) {
  1975. DngTargetDriveLetter = (UCHAR) toupper(*CmdLineTarget);
  1976. return;
  1977. }
  1978. CheckWhichDrives |= (0x1 << ((unsigned)toupper(*CmdLineTarget) - 'A'));
  1979. } else {
  1980. CheckWhichDrives = 0xFFFFFFFF;
  1981. }
  1982. TheDrive = 0;
  1983. for( CheckingDrive = 0; CheckingDrive < ('Z' - 'A'); CheckingDrive++ ) {
  1984. //
  1985. // Do we even need to look at this drive?
  1986. //
  1987. if( !(CheckWhichDrives & (0x1 << CheckingDrive))) {
  1988. continue;
  1989. }
  1990. DriveLetter = (CHAR)('A' + CheckingDrive);
  1991. if( DnpIsValidLocalSource( DriveLetter,
  1992. TRUE, // Check for LocalSource
  1993. (BOOLEAN)(DriveLetter == SystemPartitionDriveLetter) ) ) {
  1994. if( TargetGiven ) {
  1995. if( DriveLetter == (CHAR)toupper(*CmdLineTarget) ) {
  1996. TheDrive = DriveLetter;
  1997. }
  1998. } else {
  1999. if( !TheDrive ) {
  2000. //
  2001. // Take the first catch.
  2002. //
  2003. TheDrive = DriveLetter;
  2004. }
  2005. }
  2006. if( TheDrive ) {
  2007. //
  2008. // We found a suitable drive. But are we really done?
  2009. //
  2010. if( (DngFloppyless) &&
  2011. (DriveLetter < SystemPartitionDriveLetter) ) {
  2012. //
  2013. // We will be writing some boot files and we haven't checked
  2014. // the system partition yet. Cut to the chase.
  2015. //
  2016. CheckWhichDrives = (0x1 << (SystemPartitionDriveLetter - 'A'));
  2017. } else {
  2018. break;
  2019. }
  2020. }
  2021. } else {
  2022. //
  2023. // We need to special-handle failures on the system partition.
  2024. // See if he's capable of at least taking the system boot
  2025. // files.
  2026. //
  2027. if( (DriveLetter == SystemPartitionDriveLetter) &&
  2028. (DngFloppyless) ) {
  2029. if( !DnpIsValidLocalSource( DriveLetter,
  2030. FALSE,
  2031. TRUE )) {
  2032. //
  2033. // Consider ourselves slumped over.
  2034. //
  2035. TheDrive = 0;
  2036. break;
  2037. }
  2038. }
  2039. }
  2040. }
  2041. if( TheDrive == 0 ) {
  2042. //
  2043. // If there is no valid drive for the local source, put an error
  2044. // message with the minimum space required for C:
  2045. //
  2046. if( TargetGiven ) {
  2047. RequiredSpace = DnGetMinimumRequiredSpace(*CmdLineTarget);
  2048. } else {
  2049. #if NEC_98
  2050. RequiredSpace = DnGetMinimumRequiredSpace('A');
  2051. #else
  2052. RequiredSpace = DnGetMinimumRequiredSpace('C');
  2053. #endif
  2054. }
  2055. DnFatalError(
  2056. &DnsNoLocalSrcDrives,
  2057. (unsigned)(RequiredSpace/(1024L*1024L)),
  2058. RequiredSpace
  2059. );
  2060. } else {
  2061. //
  2062. // Use the first drive on the list.
  2063. //
  2064. DngTargetDriveLetter = TheDrive;
  2065. return;
  2066. }
  2067. }
  2068. BOOLEAN
  2069. DnpIsValidLocalSource(
  2070. IN CHAR Drive,
  2071. IN BOOLEAN CheckLocalSource,
  2072. IN BOOLEAN CheckBootFiles
  2073. )
  2074. /*++
  2075. Routine Description:
  2076. Determine if a drive is valid as a local source.
  2077. To be valid a drive must be extant, non-removable, local, and have
  2078. enough free space on it.
  2079. Arguments:
  2080. Drive - drive letter of drive to check.
  2081. Return Value:
  2082. TRUE if Drive is valid as a local source. FALSE otherwise.
  2083. --*/
  2084. {
  2085. unsigned d = (unsigned)toupper(Drive) - (unsigned)'A' + 1;
  2086. struct diskfree_t DiskSpace;
  2087. ULONG SpaceAvailable, SpaceRequired, ClusterSize;
  2088. unsigned DontCare, i;
  2089. if( DnIsDriveValid(d)
  2090. && !DnIsDriveRemote(d,NULL)
  2091. && !DnIsDriveRemovable(d)
  2092. && !DnIsDriveCompressedVolume(d,&DontCare))
  2093. {
  2094. //
  2095. // Check free space on the drive.
  2096. //
  2097. if(!_dos_getdiskfree(d,&DiskSpace)) {
  2098. SpaceAvailable = (ULONG)DiskSpace.avail_clusters
  2099. * (ULONG)DiskSpace.sectors_per_cluster
  2100. * (ULONG)DiskSpace.bytes_per_sector;
  2101. ClusterSize = (ULONG)DiskSpace.sectors_per_cluster *
  2102. (ULONG)DiskSpace.bytes_per_sector;
  2103. SpaceRequired = 0;
  2104. if( CheckLocalSource ) {
  2105. for( i = 0;
  2106. i < sizeof( SpaceRequirements ) / sizeof( SPACE_REQUIREMENT );
  2107. i++ ) {
  2108. if( SpaceRequirements[i].ClusterSize == (unsigned)ClusterSize ) {
  2109. #if NEC_98
  2110. SpaceRequired += (SpaceRequirements[i].Clusters * ClusterSize + 3L * FLOPPY_SIZE);
  2111. #else
  2112. SpaceRequired += (SpaceRequirements[i].Clusters * ClusterSize);
  2113. #endif
  2114. break;
  2115. }
  2116. }
  2117. }
  2118. if( CheckBootFiles ) {
  2119. CHAR TmpBuffer[32];
  2120. PCHAR p;
  2121. sprintf( TmpBuffer, "TempDirSpace%uK", ClusterSize );
  2122. if( p = DnGetSectionKeyIndex( DngInfHandle,
  2123. DnfSpaceRequirements,
  2124. TmpBuffer,
  2125. 1 ) ) {
  2126. SpaceRequired += (ULONG)atol(p);
  2127. FREE (p);
  2128. } else {
  2129. // We missed. Fudge...
  2130. ULONG FudgeSpace = 7;
  2131. FudgeSpace *= 1024;
  2132. FudgeSpace *= 1024;
  2133. SpaceRequired += FudgeSpace;
  2134. }
  2135. }
  2136. return( (BOOLEAN)(SpaceAvailable >= SpaceRequired) );
  2137. }
  2138. }
  2139. return(FALSE);
  2140. }
  2141. #if 0
  2142. BOOLEAN
  2143. DnpConstructLocalSourceList(
  2144. OUT PCHAR DriveList
  2145. )
  2146. /*++
  2147. Routine Description:
  2148. Construct a list of drives that are valid for use as a local source.
  2149. To be valid a drive must be extant, non-removable, local, and have
  2150. enough free space on it.
  2151. The 'list' is a string with a character for each valid drive, terminated
  2152. by a nul character, ie,
  2153. CDE0
  2154. Arguments:
  2155. DriveList - receives the string in the above format.
  2156. Return Value:
  2157. FALSE if no valid drives were found. TRUE if at least one was.
  2158. --*/
  2159. {
  2160. PCHAR p = DriveList;
  2161. BOOLEAN b = FALSE;
  2162. CHAR Drive;
  2163. #if NEC_98
  2164. for(Drive='A'; Drive<='Z'; Drive++) {
  2165. #else // NEC_98
  2166. for(Drive='C'; Drive<='Z'; Drive++) {
  2167. #endif // NEC_98
  2168. if(DnpIsValidLocalSource(Drive)) {
  2169. *p++ = Drive;
  2170. b = TRUE;
  2171. }
  2172. }
  2173. *p = 0;
  2174. return(b);
  2175. }
  2176. #endif
  2177. #ifdef LOGGING
  2178. // FILE *_LogFile;
  2179. BOOLEAN LogEnabled = TRUE;
  2180. VOID
  2181. StartLog(
  2182. VOID
  2183. )
  2184. {
  2185. LogEnabled = TRUE;
  2186. }
  2187. #if 0
  2188. VOID
  2189. EndLog(
  2190. VOID
  2191. )
  2192. {
  2193. if(_LogFile) {
  2194. fclose(_LogFile);
  2195. _LogFile = NULL;
  2196. }
  2197. }
  2198. #endif
  2199. VOID
  2200. __LOG(
  2201. IN PCHAR FormatString,
  2202. ...
  2203. )
  2204. {
  2205. FILE *LogFile;
  2206. va_list arglist;
  2207. if(LogEnabled) {
  2208. LogFile = fopen("c:\\$winnt.log","at");
  2209. va_start(arglist,FormatString);
  2210. vfprintf(LogFile,FormatString,arglist);
  2211. va_end(arglist);
  2212. fclose(LogFile);
  2213. }
  2214. }
  2215. #endif // def LOGGING
  2216. ULONG
  2217. DnGetMinimumRequiredSpace(
  2218. IN CHAR DriveLetter
  2219. )
  2220. /*++
  2221. Routine Description:
  2222. Determine the minimum required free space for the local source, on a
  2223. particular drive.
  2224. Arguments:
  2225. DriveLetter - Indicates the letter of a particular drive.
  2226. Return Value:
  2227. Returns the minimum required space on the specified drive.
  2228. --*/
  2229. {
  2230. struct diskfree_t DiskFree;
  2231. unsigned ClusterSize;
  2232. unsigned i;
  2233. _dos_getdiskfree(toupper(DriveLetter)-'A'+1,&DiskFree);
  2234. ClusterSize = DiskFree.sectors_per_cluster * DiskFree.bytes_per_sector;
  2235. for( i = 0;
  2236. i < sizeof( SpaceRequirements ) / sizeof( SPACE_REQUIREMENT );
  2237. i++ ) {
  2238. if( ClusterSize == SpaceRequirements[i].ClusterSize ) {
  2239. return( ClusterSize * SpaceRequirements[i].Clusters );
  2240. }
  2241. }
  2242. //
  2243. // Return the size assuming 16k cluster
  2244. //
  2245. return ( SpaceRequirements[5].ClusterSize * SpaceRequirements[5].Clusters );
  2246. }
  2247. #if NEC_98
  2248. VOID
  2249. DummyRoutine(
  2250. VOID
  2251. )
  2252. /*++
  2253. This Founction is Dummy Routine.(CTRL + C Signal Hook Routine)
  2254. --*/
  2255. {
  2256. //
  2257. // It's Dummy Statement
  2258. //
  2259. while(TRUE){
  2260. break;
  2261. }
  2262. }
  2263. VOID
  2264. SearchFirstFDD(VOID)
  2265. {
  2266. UCHAR index;
  2267. UCHAR ReadPoint = 0;
  2268. UCHAR ReadCount = 1;
  2269. //
  2270. // Setting Read Data position.
  2271. //
  2272. if(SupportDos) {
  2273. ReadPoint = 27;
  2274. ReadCount = 2;
  2275. }
  2276. //
  2277. // Search First FDD.
  2278. //
  2279. FirstFD = 0;
  2280. for(index=0; index < 26; index++) {
  2281. if(LPTable[ReadPoint+index*ReadCount] == 0x90){
  2282. FirstFD = index + 1;
  2283. break;
  2284. }
  2285. }
  2286. if(FirstFD == 0) { DnFatalError(&DnsRequiresFloppy); }
  2287. return;
  2288. }
  2289. VOID
  2290. CheckTargetDrive(VOID)
  2291. {
  2292. UCHAR Pattern[127];
  2293. UCHAR TempBuf[1000];
  2294. UCHAR Current_Drv[3];
  2295. UCHAR chDeviceName[127];
  2296. UCHAR TargetPass[127];
  2297. CHAR Target_Drv[] = "?:\0";
  2298. unsigned line;
  2299. ULONG ValidKey[2];
  2300. ULONG c;
  2301. PCHAR FileName;
  2302. FILE *fileHandle;
  2303. BOOLEAN ExistNt = TRUE; // For Back up Directry Flag
  2304. ValidKey[0] = DN_KEY_F3;
  2305. ValidKey[1] = 0;
  2306. //
  2307. // C Drive(Current drive number)
  2308. //
  2309. sprintf(Current_Drv,"%c\0",DngTargetDriveLetter);
  2310. sprintf(TempBuf,DnsNtBootSect.Strings[2] ,Current_Drv);
  2311. strcpy(DnsNtBootSect.Strings[2] ,TempBuf);
  2312. Target_Drv[0] = DngTargetDriveLetter;
  2313. if(BootDiskInfo[0].DiskSector == (USHORT)256) {
  2314. DnClearClientArea();
  2315. DnDisplayScreen(&FormatError);
  2316. DnWriteStatusText("%s",DntF3EqualsExit);
  2317. while(1) {
  2318. c = DnGetValidKey(ValidKey);
  2319. if(c == DN_KEY_F3) {
  2320. FREE(BootDiskInfo);
  2321. DnExitDialog();
  2322. }
  2323. }
  2324. }
  2325. if(DngFloppyless) {
  2326. //
  2327. // Clear $WIN_NT$.~BT
  2328. //
  2329. chDeviceName[0] = (UCHAR)DngTargetDriveLetter;
  2330. chDeviceName[1] = (UCHAR)(':');
  2331. strcpy(chDeviceName+2,FLOPPYLESS_BOOT_ROOT);
  2332. if(access(chDeviceName,00) == 0) {
  2333. strcpy(Pattern,chDeviceName);
  2334. DnDelnode(Pattern);
  2335. remove(Pattern);
  2336. }
  2337. //
  2338. // Clear $WIN_NT$.~BU
  2339. //
  2340. memset(chDeviceName,0,sizeof(chDeviceName));
  2341. chDeviceName[0] = (UCHAR)DngTargetDriveLetter;
  2342. chDeviceName[1] = (UCHAR)(':');
  2343. strcpy(chDeviceName+2,"\\$WIN_NT$.~BU");
  2344. if(access(chDeviceName,00) == 0) {
  2345. //
  2346. // copy : \$WIN_NT$.~BU -> root directry
  2347. //
  2348. DnCopyFilesInSectionForFDless(DnfBackupFiles_PC98,chDeviceName,Target_Drv);
  2349. strcpy(Pattern,chDeviceName);
  2350. DnDelnode(Pattern);
  2351. remove(Pattern);
  2352. }
  2353. //
  2354. // Check Root Directry Files.
  2355. //
  2356. line = 0;
  2357. while(FileName = DnGetSectionLineIndex(DngInfHandle,DnfBackupFiles_PC98,line++,0)) {
  2358. memset(chDeviceName,0,sizeof(chDeviceName));
  2359. chDeviceName[0] = (UCHAR)DngTargetDriveLetter;
  2360. chDeviceName[1] = (UCHAR)(':');
  2361. chDeviceName[2] = (UCHAR)('\\');
  2362. strcpy(chDeviceName+3,FileName);
  2363. _dos_setfileattr(chDeviceName,_A_NORMAL);
  2364. if(fileHandle = fopen(chDeviceName,"r")) {
  2365. fclose(fileHandle);
  2366. } else {
  2367. ExistNt = FALSE;
  2368. FREE (FileName);
  2369. break;
  2370. }
  2371. FREE (FileName);
  2372. }
  2373. //
  2374. // Create $WIN_NT$.~BU
  2375. //
  2376. if(ExistNt) {
  2377. memset(chDeviceName,0,sizeof(chDeviceName));
  2378. sprintf(chDeviceName,"%c:\\$WIN_NT$.~BU",(UCHAR)DngTargetDriveLetter);
  2379. mkdir(chDeviceName);
  2380. //
  2381. // copy : root directry -> \$WIN_NT$.~BU
  2382. //
  2383. DnCopyFilesInSectionForFDless(DnfBackupFiles_PC98,Target_Drv,chDeviceName);
  2384. //
  2385. // Set files Attribute.
  2386. //
  2387. line = 0;
  2388. while(FileName = DnGetSectionLineIndex(DngInfHandle,DnfBackupFiles_PC98,line++,0)) {
  2389. memset(TargetPass,0,sizeof(TargetPass));
  2390. sprintf(TargetPass,"%c:\\$WIN_NT$.~BU\\",(UCHAR)DngTargetDriveLetter);
  2391. strcpy(TargetPass+16,FileName);
  2392. _dos_setfileattr(TargetPass,
  2393. _A_ARCH | _A_HIDDEN | _A_RDONLY | _A_SYSTEM
  2394. );
  2395. FREE (FileName);
  2396. }
  2397. }
  2398. }
  2399. }
  2400. VOID
  2401. GetLPTable(
  2402. IN PCHAR pLPTable
  2403. )
  2404. /*
  2405. Get LPTable in the Dos system.
  2406. */
  2407. {
  2408. _asm{
  2409. push ax
  2410. push bx
  2411. push cx
  2412. push dx
  2413. push ds
  2414. mov cx,13h
  2415. push si
  2416. lds si,pLPTable
  2417. mov dx,si
  2418. pop si
  2419. int 0dch
  2420. pop ds
  2421. pop dx
  2422. pop cx
  2423. pop bx
  2424. pop ax
  2425. }
  2426. }
  2427. VOID
  2428. ClearBootFlag(
  2429. VOID
  2430. )
  2431. {
  2432. USHORT SectorSize;
  2433. PSHORT pReadBuffer;
  2434. UCHAR CNT;
  2435. (PUCHAR)DiskDAUA = MALLOC(sizeof(CONNECTDAUA)*12,TRUE);
  2436. for(CNT = 0; CNT < 12; CNT++) {
  2437. DiskDAUA[CNT].DA_UA = (UCHAR)0x00;
  2438. }
  2439. //
  2440. // Get boot device number.
  2441. //
  2442. GetDaUa();
  2443. for(CNT=0;DiskDAUA[CNT].DA_UA != 0;CNT++) {
  2444. //
  2445. // Get Device sector size.
  2446. //
  2447. SectorSize = GetSectorValue(DiskDAUA[CNT].DA_UA);
  2448. if(SectorSize == 0) {
  2449. continue;
  2450. }
  2451. pReadBuffer = (PSHORT)MALLOC(SectorSize*2,TRUE);
  2452. DiskSectorReadWrite(SectorSize,
  2453. DiskDAUA[CNT].DA_UA,
  2454. TRUE,
  2455. pReadBuffer
  2456. );
  2457. pReadBuffer[(SectorSize-6)/2] = 0x0000;
  2458. DiskSectorReadWrite(SectorSize,
  2459. DiskDAUA[CNT].DA_UA,
  2460. FALSE,
  2461. pReadBuffer
  2462. );
  2463. FREE(pReadBuffer);
  2464. }
  2465. FREE(DiskDAUA);
  2466. }
  2467. VOID
  2468. BootPartitionData(
  2469. VOID
  2470. )
  2471. /*
  2472. Setting Boot Drive Infomation for BootDiskInfo.
  2473. */
  2474. {
  2475. UCHAR ActivePartition;
  2476. PSHORT ReadBuffers;
  2477. UCHAR SystemID;
  2478. UCHAR BootPartitionNo,CheckDosNo;
  2479. UCHAR CNT;
  2480. UCHAR ReadPoint = 0;
  2481. UCHAR ReadCount = 1;
  2482. UCHAR EndRoop = 16;
  2483. //
  2484. // Setting Read Data position.
  2485. //
  2486. if(SupportDos) {
  2487. ReadPoint = 27;
  2488. ReadCount = 2;
  2489. EndRoop = 52;
  2490. }
  2491. //
  2492. // Set Boot Device DA_UA Data value.
  2493. //
  2494. BootDiskInfo[0].DA_UA = LPTable[ReadPoint+(toupper(DngTargetDriveLetter) - 0x41)*ReadCount];
  2495. //
  2496. // Set Boot Device Sector Size.
  2497. //
  2498. BootDiskInfo[0].DiskSector = GetSectorValue(BootDiskInfo[0].DA_UA);
  2499. //
  2500. // Set Boot Drive Disk Partition Position.
  2501. //
  2502. for(CNT=ActivePartition=0;(LPTable[ReadPoint+CNT] != 0) && (CNT < EndRoop); CNT+=ReadCount) {
  2503. if(CNT > (UCHAR)(toupper(DngTargetDriveLetter)-0x41)*ReadCount)
  2504. { break; }
  2505. if((UCHAR)LPTable[ReadPoint+CNT] == BootDiskInfo[0].DA_UA) {
  2506. ActivePartition++;
  2507. }
  2508. }
  2509. ReadBuffers = (PSHORT)MALLOC(BootDiskInfo[0].DiskSector*2,TRUE);
  2510. DiskSectorReadWrite(BootDiskInfo[0].DiskSector,
  2511. BootDiskInfo[0].DA_UA,
  2512. TRUE,
  2513. ReadBuffers
  2514. );
  2515. BootPartitionNo = CheckDosNo =0;
  2516. for(CNT=0; (CNT < 16) && (ActivePartition > CheckDosNo); CNT++) {
  2517. SystemID = *((PCHAR)ReadBuffers+(BootDiskInfo[0].DiskSector+1+32*CNT));
  2518. if( (SystemID == 0x81) || // FAT12
  2519. (SystemID == 0x91) || // FAT16
  2520. (SystemID == 0xe1) || // FAT32
  2521. ((SystemID == 0xa1) && // Large partition
  2522. SupportDos))
  2523. {
  2524. CheckDosNo++;
  2525. }
  2526. BootPartitionNo++;
  2527. }
  2528. TargetDA_UA = BootDiskInfo[0].DA_UA;
  2529. Cylinders =(USHORT)*(ReadBuffers+((BootDiskInfo[0].DiskSector+10+32*(CNT-1))/2));
  2530. FREE(ReadBuffers);
  2531. BootDiskInfo[0].PartitionPosition = (UCHAR)(BootPartitionNo - 1);
  2532. }
  2533. VOID
  2534. SetAutoReboot(
  2535. VOID
  2536. )
  2537. /*++
  2538. Set Auto Reboot Flag.
  2539. --*/
  2540. {
  2541. PSHORT pReadBuffer;
  2542. pReadBuffer = (PSHORT)MALLOC(BootDiskInfo[0].DiskSector*2,TRUE);
  2543. DiskSectorReadWrite(BootDiskInfo[0].DiskSector,
  2544. BootDiskInfo[0].DA_UA,
  2545. TRUE,
  2546. pReadBuffer
  2547. );
  2548. (UCHAR)*((PCHAR)pReadBuffer+BootDiskInfo[0].DiskSector-6) = 0x80;
  2549. *((PCHAR)pReadBuffer+BootDiskInfo[0].DiskSector-5) = BootDiskInfo[0].PartitionPosition;
  2550. *((PCHAR)pReadBuffer+BootDiskInfo[0].DiskSector+32 *
  2551. BootDiskInfo[0].PartitionPosition) |= 0x80;
  2552. DiskSectorReadWrite(BootDiskInfo[0].DiskSector,
  2553. BootDiskInfo[0].DA_UA,
  2554. FALSE,
  2555. pReadBuffer
  2556. );
  2557. FREE(pReadBuffer);
  2558. }
  2559. BOOLEAN
  2560. CheckBootDosVersion(
  2561. IN UCHAR SupportDosVersion
  2562. )
  2563. /*
  2564. Get Dos Version.
  2565. */
  2566. {
  2567. union REGS inregs,outregs;
  2568. int AXValue;
  2569. inregs.x.ax = (unsigned int)0;
  2570. inregs.x.bx = (unsigned int)0;
  2571. inregs.x.cx = (unsigned int)0;
  2572. inregs.x.dx = (unsigned int)0;
  2573. outregs.x.ax = (unsigned int)0;
  2574. outregs.x.bx = (unsigned int)0;
  2575. outregs.x.cx = (unsigned int)0;
  2576. outregs.x.dx = (unsigned int)0;
  2577. inregs.h.ah = (UCHAR)0x30;
  2578. AXValue = 0;
  2579. AXValue = intdos(&inregs,&outregs);
  2580. AXValue &= 0x00ff;
  2581. if(SupportDosVersion > (UCHAR)AXValue) {
  2582. return(FALSE);
  2583. } else {
  2584. return(TRUE);
  2585. }
  2586. }
  2587. USHORT
  2588. GetSectorValue(
  2589. IN UCHAR CheckDA_UA
  2590. )
  2591. /*++
  2592. Get Sector Value.
  2593. --*/
  2594. {
  2595. USHORT PhysicalSectorSize;
  2596. UCHAR ErrFlg;
  2597. _asm{
  2598. push ax
  2599. push bx
  2600. push cx
  2601. push dx
  2602. mov ah,84h
  2603. mov al,CheckDA_UA
  2604. int 1bh
  2605. mov PhysicalSectorSize,bx
  2606. cmp ah,00h
  2607. je break0
  2608. and ax,0f000h
  2609. cmp ax,0000h
  2610. je break0
  2611. mov ErrFlg,01h
  2612. jmp break1
  2613. break0:
  2614. mov ErrFlg,00h
  2615. break1:
  2616. pop dx
  2617. pop cx
  2618. pop bx
  2619. pop ax
  2620. }
  2621. if(ErrFlg == 0) {
  2622. return(PhysicalSectorSize);
  2623. } else {
  2624. return((USHORT)0);
  2625. }
  2626. }
  2627. BOOLEAN
  2628. DiskSectorReadWrite(
  2629. IN USHORT HDSector,
  2630. IN UCHAR ReadWriteDA_UA,
  2631. IN BOOLEAN ReadFlag,
  2632. IN PSHORT OrigReadBuffer
  2633. )
  2634. {
  2635. UCHAR ahreg = 0x06;
  2636. UCHAR ErrorFlag;
  2637. USHORT ReadSectorSize;
  2638. BOOLEAN HDStatus = TRUE;
  2639. UCHAR far *pTmp;
  2640. ULONG pAddr;
  2641. PSHORT ReadBuffer, p;
  2642. ReadSectorSize = HDSector * 2;
  2643. //
  2644. // INT 1BH does not allow the buffer that beyond 64KB boundary.
  2645. // So we must prepare particular buffer for INT 1BH. Once allocate
  2646. // double size buffer and use half of them that does not on
  2647. // boundary.
  2648. //
  2649. p = MALLOC(ReadSectorSize * 2, TRUE);
  2650. pTmp = (UCHAR far *)p;
  2651. pAddr = (FP_SEG(pTmp)<<4 + FP_OFF(pTmp) & 0xffff);
  2652. //
  2653. // Check half part of buffer is on 64KB boundary.
  2654. //
  2655. if (pAddr > ((pAddr + ReadSectorSize) & 0xffff)){
  2656. ReadBuffer = p + ReadSectorSize; // Use last half part.
  2657. } else {
  2658. ReadBuffer = p; // Use first half part.
  2659. }
  2660. if(!ReadFlag) {
  2661. ahreg = 0x05;
  2662. memcpy(ReadBuffer, OrigReadBuffer, ReadSectorSize);
  2663. }
  2664. _asm{
  2665. push ax
  2666. push bx
  2667. push cx
  2668. push dx
  2669. push es
  2670. push di
  2671. ;
  2672. ; If we're running under Chicago, and we're going to be
  2673. ; writing, then we have to lock the volume before attempting
  2674. ; absolute disk I/O
  2675. ;
  2676. cmp ReadFlag,1 ; are we reading?
  2677. jae locked ; if so, skip locking step
  2678. ;
  2679. ; Make sure were running under Chicago.
  2680. ;
  2681. mov ah,30h
  2682. int 21h
  2683. cmp al,7h
  2684. jb locked ; not Chicago
  2685. ;
  2686. ; We're sure we're under Chicago, so issue new
  2687. ; Lock Logical Volume IOCTL
  2688. ;
  2689. mov ax,440dh
  2690. mov bh,1 ; level 1 lock
  2691. mov bl,ReadWriteDA_UA ; fetch drive to lock
  2692. mov cx,084bh ; Lock Logical Volume for disk category
  2693. mov dx,1 ; set permission to allow reads and writes
  2694. int 21h
  2695. ;jc locked ; ignore failure - any errors are caught below
  2696. ;mov word ptr [bp-12],1 ; we successfully locked, so we must unlock
  2697. locked:
  2698. mov bx,ReadSectorSize
  2699. mov cx,0000h
  2700. mov dx,0000h
  2701. mov ax,0000h
  2702. mov ah,ahreg
  2703. mov al,ReadWriteDA_UA
  2704. push bp
  2705. push es
  2706. push ds
  2707. pop es
  2708. les di,ReadBuffer
  2709. mov bp,di
  2710. int 1bh
  2711. pop es
  2712. pop bp
  2713. jnc warp0 ;No error
  2714. cmp ah,00h
  2715. je warp0
  2716. add ax,0f000h
  2717. cmp ax,0000h
  2718. je warp0
  2719. mov ErrorFlag,01h
  2720. jmp warp1
  2721. warp0:
  2722. mov ErrorFlag,00h
  2723. warp1:
  2724. ;unlock?
  2725. cmp ReadFlag,1 ; do we need to unlock?
  2726. jae done ; if not, then done.
  2727. mov ax,440dh
  2728. mov bl,ReadWriteDA_UA ; fetch drive to lock
  2729. ;mov bh,0
  2730. ;inc bl ; (this IOCTL uses 1-based drive numbers)
  2731. mov cx,086bh ; Unlock Logical Volume for disk category
  2732. mov dx,0
  2733. int 21h ; ignore error (hope it never happens)
  2734. done:
  2735. pop di
  2736. pop es
  2737. pop dx
  2738. pop cx
  2739. pop bx
  2740. pop ax
  2741. }
  2742. if(ReadFlag) {
  2743. memcpy(OrigReadBuffer, ReadBuffer, ReadSectorSize);
  2744. }
  2745. FREE(p);
  2746. if(ErrorFlag != 0) {
  2747. HDStatus = FALSE;
  2748. }
  2749. return(HDStatus);
  2750. }
  2751. VOID
  2752. GetDaUa(VOID)
  2753. {
  2754. UCHAR count, i = 0;
  2755. UCHAR far *ConnectEquip;
  2756. UCHAR ConnectDevice;
  2757. //
  2758. // IDE/SASI Disk Check Routine
  2759. //
  2760. MAKE_FP(ConnectEquip,(USHORT)0x55d);
  2761. ConnectDevice = *ConnectEquip;
  2762. for(count=0;count < 4;count++) {
  2763. if(ConnectDevice & (1 << count)) {
  2764. DiskDAUA[i].DA_UA = (UCHAR)(0x80 + count);
  2765. i++;
  2766. }
  2767. }
  2768. //
  2769. // SCSI Disk Check Routine
  2770. //
  2771. MAKE_FP(ConnectEquip,(USHORT)0x482);
  2772. ConnectDevice = *ConnectEquip;
  2773. for(count=0;count < 7;count++) {
  2774. if(ConnectDevice & (1 << count)) {
  2775. DiskDAUA[i].DA_UA = (UCHAR)(0xa0 + count);
  2776. i++;
  2777. }
  2778. }
  2779. }
  2780. #endif // NEC_98