/*++ 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 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 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; u0; 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 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); }