|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
bootflop.c
Abstract:
Routines to create setup boot floppies.
Author:
Ted Miller (tedm) 21 November 1996
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Define bpb structure.
//
#include <pshpack1.h>
typedef struct _MY_BPB { USHORT BytesPerSector; UCHAR SectorsPerCluster; USHORT ReservedSectors; UCHAR FatCount; USHORT RootDirectoryEntries; USHORT SectorCountSmall; UCHAR MediaDescriptor; USHORT SectorsPerFat; USHORT SectorsPerTrack; USHORT HeadCount; } MY_BPB, *PMY_BPB; #include <poppack.h>
BOOL pFloppyGetDiskInDrive( IN HWND ParentWindow, IN LPCTSTR FloppyName, IN BOOL SpecialFirstPrompt, IN BOOL WriteNtBootSector, IN BOOL MoveParamsFileToFloppy );
UINT FloppyGetTotalFileCount( VOID )
/*++
Routine Description:
Determine how many files total are to be copied to all boot floppies, based on count of lines in [FloppyFiles.x] sections in dosnet.inf.
Arguments:
None.
Return Value:
Count of files.
--*/
{ TCHAR SectionName[100]; UINT u; UINT Count; LONG l;
Count = 0; for(u=0; u<FLOPPY_COUNT; u++) {
wsprintf(SectionName,TEXT("FloppyFiles.%u"),u);
l = InfGetSectionLineCount(MainInf,SectionName); if(l != -1) { Count += (UINT)l; } }
return(Count); }
DWORD FloppyWorkerThread( IN PVOID ThreadParameter )
/*++
Routine Description:
Create setup boot floppies.
Arguments:
Standard thread routine arguments.
Return Value:
Nothing meaningful.
--*/
{ TCHAR SectionName[100]; TCHAR FloppyName[200]; TCHAR Buffer[150]; TCHAR SourceName[MAX_PATH]; TCHAR TargetName[MAX_PATH]; TCHAR CompressedSourceName[MAX_PATH]; WIN32_FIND_DATA FindData; HANDLE FindHandle; LPCTSTR Directory; LPCTSTR p,q; LPTSTR r; UINT Floppy; LONG Count; LONG Line; DWORD d; HWND ParentWindow; BOOL FirstPrompt; BOOL TryCompressedFirst;
ParentWindow = (HWND)ThreadParameter; FirstPrompt = TRUE; TryCompressedFirst = FALSE;
//
// Do the floppies backwards so the boot floppy is in the drive
// when we're done.
//
for(Floppy=FLOPPY_COUNT; Floppy>0; Floppy--) {
wsprintf(SectionName,TEXT("FloppyFiles.%u"),Floppy-1);
//
// Special case the name of the first floppy.
//
if(Floppy>1) { LoadString( hInst, Server ? IDS_FLOPPY_N_SRV : IDS_FLOPPY_N_WKS, Buffer, sizeof(Buffer)/sizeof(TCHAR) );
wsprintf(FloppyName,Buffer,Floppy);
} else { LoadString( hInst, Server ? IDS_BOOTFLOP_SRV : IDS_BOOTFLOP_WKS, FloppyName, sizeof(FloppyName)/sizeof(TCHAR) ); }
//
// Get the floppy in the drive.
//
if(!pFloppyGetDiskInDrive(ParentWindow,FloppyName,FirstPrompt,Floppy==1,Floppy==1)) { PropSheet_PressButton(GetParent(ParentWindow),PSBTN_CANCEL); return(FALSE); }
//
// Create the file that contains drive letter information (migrate.inf)
//
if((Floppy == 1) && ISNT()){ if(!GetAndSaveNTFTInfo(ParentWindow)) { PropSheet_PressButton(GetParent(ParentWindow),PSBTN_CANCEL); return(FALSE); } }
FirstPrompt = FALSE;
Count = InfGetSectionLineCount(MainInf,SectionName); if(Count == -1) { continue; }
//
// Do each file in the list for this floppy.
// Since the target is a floppy, we don't bother with multithread copies,
// all files come from source 0.
//
for(Line=0; Line<Count; Line++) {
Directory = InfGetFieldByIndex(MainInf,SectionName,Line,0); p = InfGetFieldByIndex(MainInf,SectionName,Line,1); if(p && (Directory = InfGetFieldByKey(MainInf,TEXT("Directories"),Directory,0))) {
lstrcpy(SourceName,SourcePaths[0]); ConcatenatePaths(SourceName,Directory,MAX_PATH); ConcatenatePaths(SourceName,p,MAX_PATH);
q = InfGetFieldByIndex(MainInf,SectionName,Line,2);
TargetName[0] = FirstFloppyDriveLetter; TargetName[1] = TEXT(':'); TargetName[2] = 0; ConcatenatePaths(TargetName,q ? q : p,MAX_PATH);
//
// Create any subdirectory if necessary
//
if((r = _tcsrchr(TargetName,TEXT('\\'))) && ((r-TargetName) > 3)) { *r = 0; d = CreateMultiLevelDirectory(TargetName); *r = TEXT('\\'); } else { d = NO_ERROR; }
if(d == NO_ERROR) {
if(TryCompressedFirst) {
GenerateCompressedName(SourceName,CompressedSourceName);
FindHandle = FindFirstFile(CompressedSourceName,&FindData);
if(FindHandle != INVALID_HANDLE_VALUE) { FindClose(FindHandle); lstrcpy(SourceName,CompressedSourceName); GenerateCompressedName(TargetName,FindData.cFileName); lstrcpy(TargetName,FindData.cFileName); } else { FindHandle = FindFirstFile(SourceName,&FindData); if(FindHandle != INVALID_HANDLE_VALUE) { FindClose(FindHandle); TryCompressedFirst = FALSE; } } } else {
FindHandle = FindFirstFile(SourceName,&FindData);
if(FindHandle != INVALID_HANDLE_VALUE) { FindClose(FindHandle); } else { GenerateCompressedName(SourceName,CompressedSourceName); FindHandle = FindFirstFile(CompressedSourceName,&FindData); if(FindHandle != INVALID_HANDLE_VALUE) {
FindClose(FindHandle); lstrcpy(SourceName,CompressedSourceName); GenerateCompressedName(TargetName,FindData.cFileName); lstrcpy(TargetName,FindData.cFileName); } } }
d = CopyFile(SourceName,TargetName,FALSE) ? NO_ERROR : GetLastError();
//
// Retry once to overcome transient net glitches.
//
if((d != NO_ERROR) && (d != ERROR_FILE_NOT_FOUND) && (d != ERROR_PATH_NOT_FOUND) && (d != ERROR_WRITE_PROTECT)) {
Sleep(350); d = CopyFile(SourceName,TargetName,FALSE) ? NO_ERROR : GetLastError(); } }
if(d == NO_ERROR) { //
// Tell main thread that another file is done.
//
SendMessage(ParentWindow,WMX_COPYPROGRESS,0,0);
} else {
switch(FileCopyError(ParentWindow,SourceName,TargetName,d,FALSE)) {
case COPYERR_SKIP: //
// Tell main thread that another file is done.
//
SendMessage(ParentWindow,WMX_COPYPROGRESS,0,0); break;
case COPYERR_EXIT: //
// We're outta here.
//
PropSheet_PressButton(GetParent(ParentWindow),PSBTN_CANCEL); return(FALSE); break;
case COPYERR_RETRY: //
// Little hack to retry the current line.
//
Line--; break; } } } }
}
//
// Send message indicating completion.
//
SendMessage(ParentWindow,WMX_COPYPROGRESS,0,1); return(TRUE); }
BOOL pFloppyGetDiskInDrive( IN HWND ParentWindow, IN LPCTSTR FloppyName, IN BOOL SpecialFirstPrompt, IN BOOL WriteNtBootSector, IN BOOL MoveParamsFileToFloppy )
/*++
Routine Description:
This routine prompts the user to insert a floppy disk and verifies that the disk is blank, etc.
Arguments:
ParentWindow - supplies the window handle of the window to be the owner/parent for ui that this routine will display.
FloppyName - supplies human-readable name of the floppy, used in prompting.
SpecialFirstPrompt - if TRUE then this routine assumes that a special prompt should be used, that is suitable to be the first prompt the user sees for any floppies.
WriteNtBootSector - if TRUE then an NT boot sector is written to the disk.
Return Value:
TRUE if the disk is in the drive. FALSE means the program should exit.
--*/
{ int i; BOOL b; BYTE BootSector[512]; BYTE NewBootSector[512]; TCHAR SourceName[MAX_PATH]; TCHAR TargetName[MAX_PATH]; DWORD d; PMY_BPB p; DWORD spc,bps,freeclus,totclus;
//
// Issue the prompt.
//
reprompt: i = MessageBoxFromMessage( ParentWindow, SpecialFirstPrompt ? MSG_FIRST_FLOPPY_PROMPT : MSG_GENERIC_FLOPPY_PROMPT, FALSE, AppTitleStringId, MB_OKCANCEL | MB_ICONEXCLAMATION, FloppyName, FLOPPY_COUNT );
if(i == IDCANCEL) { //
// Confirm.
//
i = MessageBoxFromMessage( ParentWindow, MSG_SURE_EXIT, FALSE, AppTitleStringId, MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 );
if(i == IDYES) { Cancelled = TRUE; return(FALSE); } goto reprompt; }
//
// Inspect the floppy. Start by reading the boot sector off the disk.
//
b = ReadDiskSectors(FirstFloppyDriveLetter,0,1,512,BootSector); if(!b) { d = GetLastError(); if((d == ERROR_SHARING_VIOLATION) || (d == ERROR_ACCESS_DENIED)) { //
// Another app is using the drive.
//
MessageBoxFromMessage( ParentWindow, MSG_FLOPPY_BUSY, FALSE, AppTitleStringId, MB_OK | MB_ICONWARNING ); } else { //
// Read error -- assume no floppy is inserted or it's unformatted
//
MessageBoxFromMessage( ParentWindow, MSG_FLOPPY_BAD_FORMAT, FALSE, AppTitleStringId, MB_OK | MB_ICONWARNING ); }
goto reprompt; }
//
// Sanity check on the boot sector. Note that on PC98 there is no
// 55aa sig on a disk formatted by DOS5.0.
//
p = (PMY_BPB)&BootSector[11]; if((BootSector[0] != 0xeb) || (BootSector[2] != 0x90) || (!IsNEC98() && ((BootSector[510] != 0x55) || (BootSector[511] != 0xaa))) || (p->BytesPerSector != 512) || ((p->SectorsPerCluster != 1) && (p->SectorsPerCluster != 2)) // 2.88M disks have 2 spc
|| (p->ReservedSectors != 1) || (p->FatCount != 2) || !p->SectorCountSmall // <32M uses the 16-bit count
|| (p->MediaDescriptor != 0xf0) || (p->HeadCount != 2) || !p->RootDirectoryEntries) {
MessageBoxFromMessage( ParentWindow, MSG_FLOPPY_BAD_FORMAT, FALSE, AppTitleStringId, MB_OK | MB_ICONWARNING );
goto reprompt; }
//
// Get the free space on the disk. Make sure it's blank, by which we mean
// that is has as much free space on it as a 1.44MB floppy would usually have
// immediately after formatting.
//
SourceName[0] = FirstFloppyDriveLetter; SourceName[1] = TEXT(':'); SourceName[2] = TEXT('\\'); SourceName[3] = 0; if(!GetDiskFreeSpace(SourceName,&spc,&bps,&freeclus,&totclus)) { MessageBoxFromMessage( ParentWindow, MSG_FLOPPY_CANT_GET_SPACE, FALSE, AppTitleStringId, MB_OK | MB_ICONWARNING );
goto reprompt; }
if((freeclus * spc * bps) < 1457664) { MessageBoxFromMessage( ParentWindow, MSG_FLOPPY_NOT_BLANK, FALSE, AppTitleStringId, MB_OK | MB_ICONWARNING );
goto reprompt; }
if(WriteNtBootSector) { extern BYTE FatBootCode[512]; extern BYTE PC98FatBootCode[512];
CopyMemory(NewBootSector,IsNEC98() ? PC98FatBootCode : FatBootCode,512);
//
// Copy the BPB we retreived for the disk into the bootcode template.
// We only care about the original BPB fields, through the head count
// field. We will fill in the other fields ourselves.
//
strncpy(NewBootSector+3,"MSDOS5.0",8); CopyMemory(NewBootSector+11,BootSector+11,sizeof(MY_BPB));
//
// Set up other fields in the bootsector/BPB/xBPB.
//
// Large sector count (4 bytes)
// Hidden sector count (4 bytes)
// current head (1 byte, not necessary to set this, but what the heck)
// physical disk# (1 byte)
//
ZeroMemory(NewBootSector+28,10);
//
// Extended BPB signature
//
NewBootSector[38] = 41;
//
// Serial number
//
*(DWORD UNALIGNED *)(NewBootSector+39) = ((GetTickCount() << 12) | ((GetTickCount() >> 4) & 0xfff));
//
// volume label/system id
//
strncpy(NewBootSector+43,"NO NAME ",11); strncpy(NewBootSector+54,"FAT12 ",8);
//
// Overwrite the 'ntldr' string with 'setupldr.bin' so the right file gets
// loaded when the floppy is booted.
//
for(i=499; i>0; --i) { if(!memcmp("NTLDR ",NewBootSector+i,11)) { strncpy(NewBootSector+i,"SETUPLDRBIN",11); break; } }
//
// Write it out.
//
b = WriteDiskSectors(FirstFloppyDriveLetter,0,1,512,NewBootSector); if(!b) { MessageBoxFromMessage( ParentWindow, MSG_CANT_WRITE_FLOPPY, FALSE, AppTitleStringId, MB_OK | MB_ICONWARNING );
goto reprompt; } }
if(MoveParamsFileToFloppy) {
wsprintf(SourceName,TEXT("%c:\\%s"),SystemPartitionDriveLetter,WINNT_SIF_FILE); wsprintf(TargetName,TEXT("%c:\\%s"),FirstFloppyDriveLetter,WINNT_SIF_FILE);
SetFileAttributes(TargetName,FILE_ATTRIBUTE_NORMAL); DeleteFile(TargetName); if(!MoveFile(SourceName,TargetName)) {
MessageBoxFromMessageAndSystemError( ParentWindow, MSG_CANT_MOVE_FILE_TO_FLOPPY, GetLastError(), AppTitleStringId, MB_OK | MB_ICONERROR, SystemPartitionDriveLetter, WINNT_SIF_FILE );
goto reprompt; } }
//
// Floppy seems OK.
//
return(TRUE); }
|