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.

597 lines
16 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. bootflop.c
  5. Abstract:
  6. Routines to create setup boot floppies.
  7. Author:
  8. Ted Miller (tedm) 21 November 1996
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Define bpb structure.
  15. //
  16. #include <pshpack1.h>
  17. typedef struct _MY_BPB {
  18. USHORT BytesPerSector;
  19. UCHAR SectorsPerCluster;
  20. USHORT ReservedSectors;
  21. UCHAR FatCount;
  22. USHORT RootDirectoryEntries;
  23. USHORT SectorCountSmall;
  24. UCHAR MediaDescriptor;
  25. USHORT SectorsPerFat;
  26. USHORT SectorsPerTrack;
  27. USHORT HeadCount;
  28. } MY_BPB, *PMY_BPB;
  29. #include <poppack.h>
  30. BOOL
  31. pFloppyGetDiskInDrive(
  32. IN HWND ParentWindow,
  33. IN LPCTSTR FloppyName,
  34. IN BOOL SpecialFirstPrompt,
  35. IN BOOL WriteNtBootSector,
  36. IN BOOL MoveParamsFileToFloppy
  37. );
  38. UINT
  39. FloppyGetTotalFileCount(
  40. VOID
  41. )
  42. /*++
  43. Routine Description:
  44. Determine how many files total are to be copied to all boot floppies,
  45. based on count of lines in [FloppyFiles.x] sections in dosnet.inf.
  46. Arguments:
  47. None.
  48. Return Value:
  49. Count of files.
  50. --*/
  51. {
  52. TCHAR SectionName[100];
  53. UINT u;
  54. UINT Count;
  55. LONG l;
  56. Count = 0;
  57. for(u=0; u<FLOPPY_COUNT; u++) {
  58. wsprintf(SectionName,TEXT("FloppyFiles.%u"),u);
  59. l = InfGetSectionLineCount(MainInf,SectionName);
  60. if(l != -1) {
  61. Count += (UINT)l;
  62. }
  63. }
  64. return(Count);
  65. }
  66. DWORD
  67. FloppyWorkerThread(
  68. IN PVOID ThreadParameter
  69. )
  70. /*++
  71. Routine Description:
  72. Create setup boot floppies.
  73. Arguments:
  74. Standard thread routine arguments.
  75. Return Value:
  76. Nothing meaningful.
  77. --*/
  78. {
  79. TCHAR SectionName[100];
  80. TCHAR FloppyName[200];
  81. TCHAR Buffer[150];
  82. TCHAR SourceName[MAX_PATH];
  83. TCHAR TargetName[MAX_PATH];
  84. TCHAR CompressedSourceName[MAX_PATH];
  85. WIN32_FIND_DATA FindData;
  86. HANDLE FindHandle;
  87. LPCTSTR Directory;
  88. LPCTSTR p,q;
  89. LPTSTR r;
  90. UINT Floppy;
  91. LONG Count;
  92. LONG Line;
  93. DWORD d;
  94. HWND ParentWindow;
  95. BOOL FirstPrompt;
  96. BOOL TryCompressedFirst;
  97. ParentWindow = (HWND)ThreadParameter;
  98. FirstPrompt = TRUE;
  99. TryCompressedFirst = FALSE;
  100. //
  101. // Do the floppies backwards so the boot floppy is in the drive
  102. // when we're done.
  103. //
  104. for(Floppy=FLOPPY_COUNT; Floppy>0; Floppy--) {
  105. wsprintf(SectionName,TEXT("FloppyFiles.%u"),Floppy-1);
  106. //
  107. // Special case the name of the first floppy.
  108. //
  109. if(Floppy>1) {
  110. LoadString(
  111. hInst,
  112. Server ? IDS_FLOPPY_N_SRV : IDS_FLOPPY_N_WKS,
  113. Buffer,
  114. sizeof(Buffer)/sizeof(TCHAR)
  115. );
  116. wsprintf(FloppyName,Buffer,Floppy);
  117. } else {
  118. LoadString(
  119. hInst,
  120. Server ? IDS_BOOTFLOP_SRV : IDS_BOOTFLOP_WKS,
  121. FloppyName,
  122. sizeof(FloppyName)/sizeof(TCHAR)
  123. );
  124. }
  125. //
  126. // Get the floppy in the drive.
  127. //
  128. if(!pFloppyGetDiskInDrive(ParentWindow,FloppyName,FirstPrompt,Floppy==1,Floppy==1)) {
  129. PropSheet_PressButton(GetParent(ParentWindow),PSBTN_CANCEL);
  130. return(FALSE);
  131. }
  132. //
  133. // Create the file that contains drive letter information (migrate.inf)
  134. //
  135. if((Floppy == 1) && ISNT()){
  136. if(!GetAndSaveNTFTInfo(ParentWindow)) {
  137. PropSheet_PressButton(GetParent(ParentWindow),PSBTN_CANCEL);
  138. return(FALSE);
  139. }
  140. }
  141. FirstPrompt = FALSE;
  142. Count = InfGetSectionLineCount(MainInf,SectionName);
  143. if(Count == -1) {
  144. continue;
  145. }
  146. //
  147. // Do each file in the list for this floppy.
  148. // Since the target is a floppy, we don't bother with multithread copies,
  149. // all files come from source 0.
  150. //
  151. for(Line=0; Line<Count; Line++) {
  152. Directory = InfGetFieldByIndex(MainInf,SectionName,Line,0);
  153. p = InfGetFieldByIndex(MainInf,SectionName,Line,1);
  154. if(p && (Directory = InfGetFieldByKey(MainInf,TEXT("Directories"),Directory,0))) {
  155. lstrcpy(SourceName,SourcePaths[0]);
  156. ConcatenatePaths(SourceName,Directory,MAX_PATH);
  157. ConcatenatePaths(SourceName,p,MAX_PATH);
  158. q = InfGetFieldByIndex(MainInf,SectionName,Line,2);
  159. TargetName[0] = FirstFloppyDriveLetter;
  160. TargetName[1] = TEXT(':');
  161. TargetName[2] = 0;
  162. ConcatenatePaths(TargetName,q ? q : p,MAX_PATH);
  163. //
  164. // Create any subdirectory if necessary
  165. //
  166. if((r = _tcsrchr(TargetName,TEXT('\\'))) && ((r-TargetName) > 3)) {
  167. *r = 0;
  168. d = CreateMultiLevelDirectory(TargetName);
  169. *r = TEXT('\\');
  170. } else {
  171. d = NO_ERROR;
  172. }
  173. if(d == NO_ERROR) {
  174. if(TryCompressedFirst) {
  175. GenerateCompressedName(SourceName,CompressedSourceName);
  176. FindHandle = FindFirstFile(CompressedSourceName,&FindData);
  177. if(FindHandle != INVALID_HANDLE_VALUE) {
  178. FindClose(FindHandle);
  179. lstrcpy(SourceName,CompressedSourceName);
  180. GenerateCompressedName(TargetName,FindData.cFileName);
  181. lstrcpy(TargetName,FindData.cFileName);
  182. } else {
  183. FindHandle = FindFirstFile(SourceName,&FindData);
  184. if(FindHandle != INVALID_HANDLE_VALUE) {
  185. FindClose(FindHandle);
  186. TryCompressedFirst = FALSE;
  187. }
  188. }
  189. } else {
  190. FindHandle = FindFirstFile(SourceName,&FindData);
  191. if(FindHandle != INVALID_HANDLE_VALUE) {
  192. FindClose(FindHandle);
  193. } else {
  194. GenerateCompressedName(SourceName,CompressedSourceName);
  195. FindHandle = FindFirstFile(CompressedSourceName,&FindData);
  196. if(FindHandle != INVALID_HANDLE_VALUE) {
  197. FindClose(FindHandle);
  198. lstrcpy(SourceName,CompressedSourceName);
  199. GenerateCompressedName(TargetName,FindData.cFileName);
  200. lstrcpy(TargetName,FindData.cFileName);
  201. }
  202. }
  203. }
  204. d = CopyFile(SourceName,TargetName,FALSE) ? NO_ERROR : GetLastError();
  205. //
  206. // Retry once to overcome transient net glitches.
  207. //
  208. if((d != NO_ERROR) && (d != ERROR_FILE_NOT_FOUND)
  209. && (d != ERROR_PATH_NOT_FOUND) && (d != ERROR_WRITE_PROTECT)) {
  210. Sleep(350);
  211. d = CopyFile(SourceName,TargetName,FALSE) ? NO_ERROR : GetLastError();
  212. }
  213. }
  214. if(d == NO_ERROR) {
  215. //
  216. // Tell main thread that another file is done.
  217. //
  218. SendMessage(ParentWindow,WMX_COPYPROGRESS,0,0);
  219. } else {
  220. switch(FileCopyError(ParentWindow,SourceName,TargetName,d,FALSE)) {
  221. case COPYERR_SKIP:
  222. //
  223. // Tell main thread that another file is done.
  224. //
  225. SendMessage(ParentWindow,WMX_COPYPROGRESS,0,0);
  226. break;
  227. case COPYERR_EXIT:
  228. //
  229. // We're outta here.
  230. //
  231. PropSheet_PressButton(GetParent(ParentWindow),PSBTN_CANCEL);
  232. return(FALSE);
  233. break;
  234. case COPYERR_RETRY:
  235. //
  236. // Little hack to retry the current line.
  237. //
  238. Line--;
  239. break;
  240. }
  241. }
  242. }
  243. }
  244. }
  245. //
  246. // Send message indicating completion.
  247. //
  248. SendMessage(ParentWindow,WMX_COPYPROGRESS,0,1);
  249. return(TRUE);
  250. }
  251. BOOL
  252. pFloppyGetDiskInDrive(
  253. IN HWND ParentWindow,
  254. IN LPCTSTR FloppyName,
  255. IN BOOL SpecialFirstPrompt,
  256. IN BOOL WriteNtBootSector,
  257. IN BOOL MoveParamsFileToFloppy
  258. )
  259. /*++
  260. Routine Description:
  261. This routine prompts the user to insert a floppy disk and verifies that
  262. the disk is blank, etc.
  263. Arguments:
  264. ParentWindow - supplies the window handle of the window to be the
  265. owner/parent for ui that this routine will display.
  266. FloppyName - supplies human-readable name of the floppy, used in prompting.
  267. SpecialFirstPrompt - if TRUE then this routine assumes that a special prompt
  268. should be used, that is suitable to be the first prompt the user sees
  269. for any floppies.
  270. WriteNtBootSector - if TRUE then an NT boot sector is written to the disk.
  271. Return Value:
  272. TRUE if the disk is in the drive. FALSE means the program should exit.
  273. --*/
  274. {
  275. int i;
  276. BOOL b;
  277. BYTE BootSector[512];
  278. BYTE NewBootSector[512];
  279. TCHAR SourceName[MAX_PATH];
  280. TCHAR TargetName[MAX_PATH];
  281. DWORD d;
  282. PMY_BPB p;
  283. DWORD spc,bps,freeclus,totclus;
  284. //
  285. // Issue the prompt.
  286. //
  287. reprompt:
  288. i = MessageBoxFromMessage(
  289. ParentWindow,
  290. SpecialFirstPrompt ? MSG_FIRST_FLOPPY_PROMPT : MSG_GENERIC_FLOPPY_PROMPT,
  291. FALSE,
  292. AppTitleStringId,
  293. MB_OKCANCEL | MB_ICONEXCLAMATION,
  294. FloppyName,
  295. FLOPPY_COUNT
  296. );
  297. if(i == IDCANCEL) {
  298. //
  299. // Confirm.
  300. //
  301. i = MessageBoxFromMessage(
  302. ParentWindow,
  303. MSG_SURE_EXIT,
  304. FALSE,
  305. AppTitleStringId,
  306. MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2
  307. );
  308. if(i == IDYES) {
  309. Cancelled = TRUE;
  310. return(FALSE);
  311. }
  312. goto reprompt;
  313. }
  314. //
  315. // Inspect the floppy. Start by reading the boot sector off the disk.
  316. //
  317. b = ReadDiskSectors(FirstFloppyDriveLetter,0,1,512,BootSector);
  318. if(!b) {
  319. d = GetLastError();
  320. if((d == ERROR_SHARING_VIOLATION) || (d == ERROR_ACCESS_DENIED)) {
  321. //
  322. // Another app is using the drive.
  323. //
  324. MessageBoxFromMessage(
  325. ParentWindow,
  326. MSG_FLOPPY_BUSY,
  327. FALSE,
  328. AppTitleStringId,
  329. MB_OK | MB_ICONWARNING
  330. );
  331. } else {
  332. //
  333. // Read error -- assume no floppy is inserted or it's unformatted
  334. //
  335. MessageBoxFromMessage(
  336. ParentWindow,
  337. MSG_FLOPPY_BAD_FORMAT,
  338. FALSE,
  339. AppTitleStringId,
  340. MB_OK | MB_ICONWARNING
  341. );
  342. }
  343. goto reprompt;
  344. }
  345. //
  346. // Sanity check on the boot sector. Note that on PC98 there is no
  347. // 55aa sig on a disk formatted by DOS5.0.
  348. //
  349. p = (PMY_BPB)&BootSector[11];
  350. if((BootSector[0] != 0xeb) || (BootSector[2] != 0x90)
  351. || (!IsNEC98() && ((BootSector[510] != 0x55) || (BootSector[511] != 0xaa)))
  352. || (p->BytesPerSector != 512)
  353. || ((p->SectorsPerCluster != 1) && (p->SectorsPerCluster != 2)) // 2.88M disks have 2 spc
  354. || (p->ReservedSectors != 1)
  355. || (p->FatCount != 2)
  356. || !p->SectorCountSmall // <32M uses the 16-bit count
  357. || (p->MediaDescriptor != 0xf0)
  358. || (p->HeadCount != 2)
  359. || !p->RootDirectoryEntries) {
  360. MessageBoxFromMessage(
  361. ParentWindow,
  362. MSG_FLOPPY_BAD_FORMAT,
  363. FALSE,
  364. AppTitleStringId,
  365. MB_OK | MB_ICONWARNING
  366. );
  367. goto reprompt;
  368. }
  369. //
  370. // Get the free space on the disk. Make sure it's blank, by which we mean
  371. // that is has as much free space on it as a 1.44MB floppy would usually have
  372. // immediately after formatting.
  373. //
  374. SourceName[0] = FirstFloppyDriveLetter;
  375. SourceName[1] = TEXT(':');
  376. SourceName[2] = TEXT('\\');
  377. SourceName[3] = 0;
  378. if(!GetDiskFreeSpace(SourceName,&spc,&bps,&freeclus,&totclus)) {
  379. MessageBoxFromMessage(
  380. ParentWindow,
  381. MSG_FLOPPY_CANT_GET_SPACE,
  382. FALSE,
  383. AppTitleStringId,
  384. MB_OK | MB_ICONWARNING
  385. );
  386. goto reprompt;
  387. }
  388. if((freeclus * spc * bps) < 1457664) {
  389. MessageBoxFromMessage(
  390. ParentWindow,
  391. MSG_FLOPPY_NOT_BLANK,
  392. FALSE,
  393. AppTitleStringId,
  394. MB_OK | MB_ICONWARNING
  395. );
  396. goto reprompt;
  397. }
  398. if(WriteNtBootSector) {
  399. extern BYTE FatBootCode[512];
  400. extern BYTE PC98FatBootCode[512];
  401. CopyMemory(NewBootSector,IsNEC98() ? PC98FatBootCode : FatBootCode,512);
  402. //
  403. // Copy the BPB we retreived for the disk into the bootcode template.
  404. // We only care about the original BPB fields, through the head count
  405. // field. We will fill in the other fields ourselves.
  406. //
  407. strncpy(NewBootSector+3,"MSDOS5.0",8);
  408. CopyMemory(NewBootSector+11,BootSector+11,sizeof(MY_BPB));
  409. //
  410. // Set up other fields in the bootsector/BPB/xBPB.
  411. //
  412. // Large sector count (4 bytes)
  413. // Hidden sector count (4 bytes)
  414. // current head (1 byte, not necessary to set this, but what the heck)
  415. // physical disk# (1 byte)
  416. //
  417. ZeroMemory(NewBootSector+28,10);
  418. //
  419. // Extended BPB signature
  420. //
  421. NewBootSector[38] = 41;
  422. //
  423. // Serial number
  424. //
  425. *(DWORD UNALIGNED *)(NewBootSector+39) = ((GetTickCount() << 12)
  426. | ((GetTickCount() >> 4) & 0xfff));
  427. //
  428. // volume label/system id
  429. //
  430. strncpy(NewBootSector+43,"NO NAME ",11);
  431. strncpy(NewBootSector+54,"FAT12 ",8);
  432. //
  433. // Overwrite the 'ntldr' string with 'setupldr.bin' so the right file gets
  434. // loaded when the floppy is booted.
  435. //
  436. for(i=499; i>0; --i) {
  437. if(!memcmp("NTLDR ",NewBootSector+i,11)) {
  438. strncpy(NewBootSector+i,"SETUPLDRBIN",11);
  439. break;
  440. }
  441. }
  442. //
  443. // Write it out.
  444. //
  445. b = WriteDiskSectors(FirstFloppyDriveLetter,0,1,512,NewBootSector);
  446. if(!b) {
  447. MessageBoxFromMessage(
  448. ParentWindow,
  449. MSG_CANT_WRITE_FLOPPY,
  450. FALSE,
  451. AppTitleStringId,
  452. MB_OK | MB_ICONWARNING
  453. );
  454. goto reprompt;
  455. }
  456. }
  457. if(MoveParamsFileToFloppy) {
  458. wsprintf(SourceName,TEXT("%c:\\%s"),SystemPartitionDriveLetter,WINNT_SIF_FILE);
  459. wsprintf(TargetName,TEXT("%c:\\%s"),FirstFloppyDriveLetter,WINNT_SIF_FILE);
  460. SetFileAttributes(TargetName,FILE_ATTRIBUTE_NORMAL);
  461. DeleteFile(TargetName);
  462. if(!MoveFile(SourceName,TargetName)) {
  463. MessageBoxFromMessageAndSystemError(
  464. ParentWindow,
  465. MSG_CANT_MOVE_FILE_TO_FLOPPY,
  466. GetLastError(),
  467. AppTitleStringId,
  468. MB_OK | MB_ICONERROR,
  469. SystemPartitionDriveLetter,
  470. WINNT_SIF_FILE
  471. );
  472. goto reprompt;
  473. }
  474. }
  475. //
  476. // Floppy seems OK.
  477. //
  478. return(TRUE);
  479. }