/*++ Copyright (c) 1993 Microsoft Corporation Module Name: dnflop.c Abstract: Floppy-disk creation routines for 32-bit winnt setup. Author: Ted Miller (tedm) 19-December-1993 Revision History: --*/ #include "precomp.h" #pragma hdrstop #ifdef _X86_ #include "msg.h" // // This header file contains an array of 512 bytes // representing the NT FAT boot code, in a variable // of type unsigned char[] called FatBootCode. // #include #pragma pack(1) // // Define bpb structure. // 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; #pragma pack() // // Marco for accessing unaligned ushorts in the above structure. // Not strictly needed on x86 but if this code is ever portable // then this is necessary. // #define U_USHORT(x) (*(USHORT UNALIGNED *)&(x)) // Macro to align a buffer. // #define ALIGN(p,val) \ \ (PVOID)((((ULONG)(p) + (val) - 1)) & (~((val) - 1))) BOOL DnCopyOemBootFiles( HWND hdlg, PTSTR TargetPath ) { ULONG Count; DWORD d; DWORD ec; DWORD BytesWritten; UINT SrcNo = 0; UINT SourceIndex[MAX_SOURCES]; PTSTR SourceDirectory = WINNT_OEM_TEXTMODE_DIR; TCHAR SourceFilename[MAX_PATH]; TCHAR TargetFilename[MAX_PATH]; for( Count = 0; Count < OemBootFilesCount; Count++ ) { // // Form full paths. For secondary files (ie, files getting copied // to boot floppies/local boot dir) we want to pick one of the // sources and not just use the same source over and over. // for(d=0; dBytesPerSector) != 512) || ( (Bpb->SectorsPerCluster != 1) && (Bpb->SectorsPerCluster != 2)) // for 2.88M disks || (U_USHORT(Bpb->ReservedSectors) != 1) || (Bpb->FatCount != 2) || !U_USHORT(Bpb->SectorCountSmall) // should be < 32M || (Bpb->MediaDescriptor == 0xf8) // hard disk || (U_USHORT(Bpb->HeadCount) != 2) || !U_USHORT(Bpb->RootDirectoryEntries)) { ErrorId = MSG_FLOPPY_BAD_FORMAT; } else { if(GetDiskFreeSpace(TEXT("A:\\"),&spc,&bps,&freeclus,&totclus)) { FreeSpace = freeclus * spc * bps; if(FreeSpace < FLOPPY_CAPACITY) { ErrorId = MSG_FLOPPY_NOT_BLANK; } } else { ErrorId = MSG_FLOPPY_CANT_GET_SPACE; } } } // // If there is a problem with the disk, inform the user. // if(ErrorId) { UiMessageBox( hdlg, ErrorId, IDS_ERROR, MB_OK | MB_ICONEXCLAMATION ); } } while(ErrorId); return(TRUE); } BOOL DoCreateBootFloppies( IN HWND hdlg, IN PTSTR Floppy0Name, IN PTSTR Floppy1Name, IN PTSTR Floppy2Name ) /*++ Routine Description: Create the winnt boot floppies by copying files listed in three sections of dosnet.inf to 3 separate floppies, and preparing one of the floppies to boot the setup boot loader. If we are in floppyless operation, we will instead copy the files into a special directory on the system partition (usually C:). This routine is expecting to be the entry point of a separate thread to perform this action. Arguments: hdlg - supplies handle to dialog currently displayed. Return Value: FALSE if the program should end (critical error). TRUE otherwise. --*/ { int i; DWORD ErrorId; UCHAR SectorBuffer[512]; TCHAR TextBuffer[1024]; MY_BPB Bpb; BOOL b; BOOL rc = TRUE; DWORD ec; TCHAR BootRoot[64]; PTSTR System32Dir; if(FloppylessOperation) { BootRoot[0] = SystemPartitionDrive; BootRoot[1] = ':'; lstrcpy(BootRoot+2,FloppylessBootDirectory); // // Create the boot dir. First get rid of any file by that name. // SetFileAttributes(BootRoot,FILE_ATTRIBUTE_NORMAL); DeleteFile(BootRoot); CreateDirectory(BootRoot,NULL); RetreiveAndFormatMessageIntoBuffer( MSG_PREPARING_FLOPPYLESS, TextBuffer, SIZECHARS(TextBuffer) ); } else { RetreiveAndFormatMessageIntoBuffer( CreateLocalSource ? MSG_PREPARING_FLOPPY_ALSO : MSG_PREPARING_FLOPPY, TextBuffer, SIZECHARS(TextBuffer), Floppy2Name ); lstrcpy(BootRoot,TEXT("A:")); } System32Dir = MALLOC((lstrlen(BootRoot)*sizeof(TCHAR))+sizeof(TEXT("\\SYSTEM32"))); lstrcpy(System32Dir,BootRoot); lstrcat(System32Dir,TEXT("\\SYSTEM32")); // // Get a floppy in the drive -- this will be "Windows NT Setup Disk #3" // if(FloppylessOperation) { b = TRUE; } else { b = DnPromptAndInspectFloppy( MSG_FIRST_FLOPPY_PROMPT, MSG_GENERIC_FLOPPY_PROMPT, &Bpb, hdlg, Floppy2Name, Floppy0Name, Floppy1Name, Floppy2Name ); } if(!b || bCancelled) { rc = FALSE; goto flop1; } AuxillaryStatus(hdlg,TextBuffer); // // Copy files to the disk. // ec = CopySectionOfFilesToCopy( hdlg, INF_FLOPPYFILES2, BootRoot, 0, FALSE ); if(ec == (DWORD)(-1) || bCancelled) { AuxillaryStatus(hdlg,NULL); rc = FALSE; goto flop1; } if(!FloppylessOperation) { RetreiveAndFormatMessageIntoBuffer( CreateLocalSource ? MSG_PREPARING_FLOPPY_ALSO : MSG_PREPARING_FLOPPY, TextBuffer, SIZECHARS(TextBuffer), Floppy1Name ); } do { // // Get a floppy in the drive -- this will be "Windows NT Setup Disk #2" // if(FloppylessOperation) { b = TRUE; } else { b = DnPromptAndInspectFloppy( MSG_GENERIC_FLOPPY_PROMPT, MSG_GENERIC_FLOPPY_PROMPT, &Bpb, hdlg, Floppy1Name, Floppy0Name, Floppy1Name, Floppy2Name ); } if(!b || bCancelled) { rc = FALSE; goto flop1; } AuxillaryStatus(hdlg,TextBuffer); // // Hack: create system32 directory on the floppy. // SetFileAttributes(System32Dir,FILE_ATTRIBUTE_NORMAL); DeleteFile(System32Dir); CreateDirectory(System32Dir,NULL); // // Copy files to the disk. // ec = CopySectionOfFilesToCopy( hdlg, INF_FLOPPYFILES1, BootRoot, 0, FALSE ); if(ec == (DWORD)(-1) || bCancelled) { AuxillaryStatus(hdlg,NULL); rc = FALSE; goto flop1; } // // Unless we're creating retail boot disks, put a small file // on the disk indicating that it's a winnt setup. // if(FloppyOption != OnlyRetailFloppies) { b = DnIndicateWinnt(hdlg,BootRoot,NULL,NULL); AuxillaryStatus(hdlg,NULL); if(!b) { UiMessageBox( hdlg, MSG_CANT_WRITE_FLOPPY, IDS_ERROR, MB_OK | MB_ICONEXCLAMATION ); } } } while(!b); if(!FloppylessOperation) { RetreiveAndFormatMessageIntoBuffer( CreateLocalSource ? MSG_PREPARING_FLOPPY_ALSO : MSG_PREPARING_FLOPPY, TextBuffer, SIZECHARS(TextBuffer), Floppy0Name ); } do { ErrorId = 0; // // Get a floppy in the drive -- this will be "Windows NT Setup Boot Disk" // if(FloppylessOperation) { b = TRUE; } else { b = DnPromptAndInspectFloppy( MSG_GENERIC_FLOPPY_PROMPT, MSG_GENERIC_FLOPPY_PROMPT, &Bpb, hdlg, Floppy0Name, Floppy0Name, Floppy1Name, Floppy2Name ); } if(!b || bCancelled) { rc = FALSE; goto flop1; } AuxillaryStatus(hdlg,TextBuffer); if(!FloppylessOperation) { CopyMemory(SectorBuffer,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(SectorBuffer+3,"MSDOS5.0",8); CopyMemory(SectorBuffer+11,&Bpb,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(SectorBuffer+28,10); // // Extended BPB signature // SectorBuffer[38] = 41; // // Serial number // *(DWORD UNALIGNED *)(SectorBuffer+39) = ((GetTickCount() << 12) | ((GetTickCount() >> 4) & 0xfff)); // // volume label/system id // strncpy(SectorBuffer+43,"NO NAME ",11); strncpy(SectorBuffer+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 ",SectorBuffer+i,11)) { strncpy(SectorBuffer+i,"SETUPLDRBIN",11); break; } } } // // Write the boot sector. // if(FloppylessOperation || MyWriteBootSector(SectorBuffer)) { // // Copy files into the disk. // ec = CopySectionOfFilesToCopy( hdlg, INF_FLOPPYFILES0, BootRoot, 0, FALSE ); AuxillaryStatus(hdlg,NULL); if(ec == (DWORD)(-1) || bCancelled) { rc = FALSE; goto flop1; } } else { AuxillaryStatus(hdlg,NULL); ErrorId = MSG_FLOPPY_WRITE_BS; } if(ErrorId) { UiMessageBox( hdlg, ErrorId, IDS_ERROR, MB_OK | MB_ICONEXCLAMATION ); } } while(ErrorId); // // Additionally in the floppyless case, we need to copy some files // from the boot directory to the root of the system partition drive. // if(FloppylessOperation && rc) { TCHAR DriveRootPath[] = TEXT("?:\\"); BOOL b, ForceNoComp = FALSE; DWORD DontCare; DWORD FsFlags; AuxillaryStatus(hdlg,TextBuffer); DriveRootPath[0] = SystemPartitionDrive; b = GetVolumeInformation( DriveRootPath, NULL,0, // don't care about volume label... NULL, // ...or serial number &DontCare, // .. or max component length &FsFlags, // want fs flags NULL,0 // don't care about fs name ); if(b && (FsFlags & FS_FILE_COMPRESSION)) { ForceNoComp = TRUE; } ec = CopySectionOfFilesToCopy( hdlg, INF_FLOPPYFILESX, BootRoot, 0, FALSE ); AuxillaryStatus(hdlg,NULL); if(ec == (DWORD)(-1) || bCancelled) { rc = FALSE; goto flop1; } AuxillaryStatus(hdlg,TextBuffer); System32Dir[0] = BootRoot[0]; System32Dir[1] = TEXT(':'); System32Dir[2] = 0; rc = DnCopyFilesInSection(hdlg, INF_ROOTBOOTFILES, BootRoot, System32Dir, ForceNoComp ); AuxillaryStatus(hdlg,NULL); if(rc && !bCancelled) { AuxillaryStatus(hdlg,TextBuffer); if(rc = DnMungeBootIni(hdlg)) { rc = DnLayAuxBootSector(hdlg); } AuxillaryStatus(hdlg,NULL); if(rc && !bCancelled && OemPreInstall) { TCHAR OemBootDir[MAX_PATH]; AuxillaryStatus(hdlg,TextBuffer); lstrcpy( OemBootDir, BootRoot ); DnConcatenatePaths(OemBootDir,WINNT_OEM_DIR,MAX_PATH); if( DnpCreateOneDirectory( OemBootDir, hdlg ) ) { rc = DnCopyOemBootFiles( hdlg, OemBootDir ); } AuxillaryStatus(hdlg,NULL); } } } flop1: FREE(System32Dir); return(rc); } DWORD ThreadAuxilliaryAction( IN PVOID ThreadParameter ) { HWND hdlg; BOOL b; PTSTR Floppy0Name,Floppy1Name; PTSTR Floppy2Name; hdlg = (HWND)ThreadParameter; try { if(CreateFloppies || FloppylessOperation) { Floppy0Name = MyLoadString(ServerProduct ? IDS_SFLOPPY0_NAME : IDS_WFLOPPY0_NAME); Floppy1Name = MyLoadString(ServerProduct ? IDS_SFLOPPY1_NAME : IDS_WFLOPPY1_NAME); Floppy2Name = MyLoadString(ServerProduct ? IDS_SFLOPPY2_NAME : IDS_WFLOPPY2_NAME); b = DoCreateBootFloppies( hdlg, Floppy0Name, Floppy1Name, Floppy2Name ); FREE(Floppy0Name); FREE(Floppy1Name); FREE(Floppy2Name); if(!b) { // // If the user has cancelled winnt32, do not post IDCANCEL massage. // Otherwise, winnt32 will start a second instance of ThreadRestoreComputer, // and due to a race condition between the two instances of the thread, // the temporary directory $win_nt$.~ls will not be deleted. // if( !bCancelled ) { PostMessage(hdlg, WM_COMMAND, IDCANCEL, 0); } } } else { b = TRUE; } PostMessage(hdlg,WMX_AUXILLIARY_ACTION_DONE,b,0); } except(EXCEPTION_EXECUTE_HANDLER) { MessageBoxFromMessage( hdlg, MSG_GENERIC_EXCEPTION, AppTitleStringId, MB_ICONSTOP | MB_OK | MB_SETFOREGROUND, GetExceptionCode() ); b = FALSE; PostMessage(hdlg,WMX_AUXILLIARY_ACTION_DONE,b,0); } ExitThread(b); return(b); } UINT DlgProcSysPartSpaceWarn( IN HWND hdlg, IN UINT msg, IN WPARAM wParam, IN LPARAM lParam ) { switch(msg) { case WM_INITDIALOG: { TCHAR Buffer[4096]; PTSTR p; p = MyLoadString(AppTitleStringId); SetWindowText(hdlg,p); FREE(p); // // // Center the dialog on the screen and bring it to the top. // CenterDialog(hdlg); SetForegroundWindow(hdlg); MessageBeep(MB_ICONQUESTION); // // Set the icon to be the warning exclamation // SendDlgItemMessage( hdlg, IDC_EXCLAIM, STM_SETICON, (WPARAM)LoadIcon(NULL, IDI_EXCLAMATION), 0 ); RetreiveAndFormatMessageIntoBuffer( MSG_SYSPART_LOW_X86, Buffer, SIZECHARS(Buffer), SystemPartitionDrive ); SetDlgItemText(hdlg,IDC_TEXT1,Buffer); return(FALSE); } case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: case IDCANCEL: EndDialog(hdlg, (UINT)LOWORD(wParam)); break; case ID_HELP: MyWinHelp(hdlg, IDD_SYSPART_LOW_X86); break; default: return(FALSE); } break; default: return(FALSE); } return(TRUE); } VOID CheckAColon( VOID ) { #ifndef ALLOW_525 HANDLE h; BOOL b; UCHAR Buffer[2048]; DWORD Size; PDISK_GEOMETRY Geometry; unsigned i,Count; AColonIsAcceptable = FALSE; // // Open A: device // h = CreateFile( TEXT("\\\\.\\A:"), FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if(h != INVALID_HANDLE_VALUE) { b = DeviceIoControl( h, IOCTL_DISK_GET_MEDIA_TYPES, NULL, 0, Buffer, sizeof(Buffer), &Size, NULL ); if(b) { Geometry = (PDISK_GEOMETRY)Buffer; Count = Size/sizeof(DISK_GEOMETRY); for(i=0; !AColonIsAcceptable && (i