304 lines
6.8 KiB
C++
304 lines
6.8 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 2001 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
sys.cpp
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Writes WinME boot sector to local hard disk.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Adrian Cosma (acosma)
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
July 11, 2001 - Created
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include <new.h> // for MyNewHandler
|
||
|
#include <iostream>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
#include <9xboot32.h>
|
||
|
#include <bootf32.h>
|
||
|
#include "sys.h"
|
||
|
|
||
|
|
||
|
//
|
||
|
// Define a function to be called if new fails to allocate memory.
|
||
|
//
|
||
|
int __cdecl MyNewHandler( size_t size )
|
||
|
{
|
||
|
wprintf(L"Memory allocation failed. Exiting program.\n");
|
||
|
|
||
|
// Exit program
|
||
|
//
|
||
|
throw new W32Error();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// usage
|
||
|
//
|
||
|
std::wstring Usage = TEXT("sys.exe [/?] [/xp] drive-letter:\nExample: sys.exe c:");
|
||
|
|
||
|
|
||
|
//
|
||
|
// Invalid arguments
|
||
|
//
|
||
|
struct ProgramUsage : public ProgramException {
|
||
|
std::wstring PrgUsage;
|
||
|
|
||
|
ProgramUsage(const std::wstring &Usg) : PrgUsage(Usg) {}
|
||
|
|
||
|
const char *what() const throw() {
|
||
|
return "Program Usage exception";
|
||
|
}
|
||
|
|
||
|
void Dump(std::ostream &os) {
|
||
|
os << Usage << std::endl;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Missing files
|
||
|
//
|
||
|
struct FileMissing : public ProgramException {
|
||
|
std::wstring Message;
|
||
|
|
||
|
FileMissing(std::wstring Msg) : Message(Msg) {}
|
||
|
|
||
|
const char *what() const throw() {
|
||
|
return "File missing exception";
|
||
|
}
|
||
|
|
||
|
void Dump(std::ostream &os) {
|
||
|
os << TEXT("Error: ") << Message << std::endl;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
//
|
||
|
// Wrong filesystem.
|
||
|
//
|
||
|
struct FileSystem : public ProgramException {
|
||
|
std::wstring Message;
|
||
|
|
||
|
FileSystem(std::wstring Msg) : Message(Msg) {}
|
||
|
|
||
|
const char *what() const throw() {
|
||
|
return "Unsupported filesystem exception";
|
||
|
}
|
||
|
|
||
|
void Dump(std::ostream &os) {
|
||
|
os << Message << std::endl;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// Argument cracker
|
||
|
//
|
||
|
struct ProgramArguments
|
||
|
{
|
||
|
std::wstring DriveLetter;
|
||
|
bool bXPBootSector; // TRUE for XP boot sector, FALSE for 9x boot sector.
|
||
|
|
||
|
ProgramArguments(int Argc, wchar_t *Argv[])
|
||
|
{
|
||
|
bool ValidArgs = true;
|
||
|
|
||
|
bXPBootSector = false;
|
||
|
|
||
|
for (ULONG Index = 1; ValidArgs && (Index < Argc); Index++)
|
||
|
{
|
||
|
ValidArgs = false;
|
||
|
|
||
|
// Find all the arguments that start with "/"
|
||
|
//
|
||
|
if ( TEXT('/') == Argv[Index][0] )
|
||
|
{
|
||
|
if ( !bXPBootSector && !_wcsicmp(Argv[Index], TEXT("/xp")) )
|
||
|
{
|
||
|
bXPBootSector = true;
|
||
|
ValidArgs = true;
|
||
|
}
|
||
|
}
|
||
|
else // Process arguments without the "/". Must be the drive letter.
|
||
|
{
|
||
|
DriveLetter = Argv[Index];
|
||
|
ValidArgs = ((DriveLetter.length() == 2) &&
|
||
|
(DriveLetter[1] == TEXT(':')));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!ValidArgs)
|
||
|
{
|
||
|
throw new ProgramUsage(Usage);
|
||
|
}
|
||
|
|
||
|
DriveLetter = TEXT("\\\\.\\") + DriveLetter;
|
||
|
}
|
||
|
|
||
|
friend std::ostream& operator<<(std::ostream &os, const ProgramArguments &Args)
|
||
|
{
|
||
|
os << TEXT("DriveLetter : ") << Args.DriveLetter << std::endl;
|
||
|
return os;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Verify that this partition is ready to be sys-ed.
|
||
|
//
|
||
|
VOID VerifyPartition(CDrive &Disk, ProgramArguments Args)
|
||
|
{
|
||
|
TCHAR szFileSystemNameBuffer[20] = TEXT("");
|
||
|
std::vector<LPTSTR> FileNames;
|
||
|
std::vector<LPTSTR>::iterator i;
|
||
|
|
||
|
|
||
|
if ( Args.bXPBootSector )
|
||
|
{
|
||
|
FileNames.push_back(TEXT("ntdetect.com"));
|
||
|
FileNames.push_back(TEXT("ntldr"));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FileNames.push_back(TEXT("io.sys"));
|
||
|
FileNames.push_back(TEXT("msdos.sys"));
|
||
|
FileNames.push_back(TEXT("command.com"));
|
||
|
}
|
||
|
|
||
|
// Make sure that io.sys and msdos.sys and command.com are there on the root.
|
||
|
//
|
||
|
std::wstring Temp;
|
||
|
|
||
|
for (i = FileNames.begin(); i < FileNames.end(); i++)
|
||
|
{
|
||
|
Temp = Args.DriveLetter + TEXT("\\");
|
||
|
Temp += *i;
|
||
|
|
||
|
if ( 0xFFFFFFFF == GetFileAttributes(Temp.c_str()) )
|
||
|
{
|
||
|
// Re-use the Temp string to put the error message in.
|
||
|
//
|
||
|
Temp = *i;
|
||
|
Temp += TEXT(" is not present on the root of the drive specified.");
|
||
|
throw new FileMissing(Temp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Verify that this partition is FAT32. Only handling FAT32 partitions at this point.
|
||
|
//
|
||
|
Temp = Args.DriveLetter + TEXT("\\");
|
||
|
|
||
|
// If the filesystem is not FAT32 then trow an exception.
|
||
|
//
|
||
|
if ( !(GetVolumeInformation(Temp.c_str(), NULL, 0, NULL, NULL, NULL, szFileSystemNameBuffer, sizeof (szFileSystemNameBuffer)/sizeof (szFileSystemNameBuffer[0])) &&
|
||
|
(CSTR_EQUAL == CompareString( LOCALE_INVARIANT,
|
||
|
NORM_IGNORECASE,
|
||
|
szFileSystemNameBuffer,
|
||
|
-1,
|
||
|
TEXT("FAT32"),
|
||
|
-1 ))) )
|
||
|
{
|
||
|
throw new FileSystem(TEXT("The target filesystem is not formatted FAT32."));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID Sys(CDrive &Disk, ProgramArguments &Args)
|
||
|
{
|
||
|
PBYTE pBuffer = NULL;
|
||
|
PBYTE pBootRecord = NULL; // Need a pointer to the boot record.
|
||
|
|
||
|
if ( Args.bXPBootSector )
|
||
|
{
|
||
|
pBootRecord = Fat32BootCode;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pBootRecord = Fat32BootCode9x;
|
||
|
}
|
||
|
|
||
|
// Read the 1st sector of the disk in order to get the BPB
|
||
|
//
|
||
|
Disk.ReadBootRecord(Args.DriveLetter.c_str(), 1, &pBuffer);
|
||
|
|
||
|
// Copy the old BPB to our boot record.
|
||
|
//
|
||
|
memcpy(&pBootRecord[11], &pBuffer[11], 79);
|
||
|
|
||
|
// Delete the buffer allocated by ReadBootRecord.
|
||
|
//
|
||
|
delete [] pBuffer;
|
||
|
|
||
|
// Write out the boot record.
|
||
|
//
|
||
|
if ( Args.bXPBootSector )
|
||
|
{
|
||
|
Disk.WriteBootRecordXP(Args.DriveLetter.c_str(), sizeof(Fat32BootCode9x) / SECTOR_SIZE, &pBootRecord);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Disk.WriteBootRecord(Args.DriveLetter.c_str(), sizeof(Fat32BootCode9x) / SECTOR_SIZE, &pBootRecord);
|
||
|
}
|
||
|
|
||
|
std::cout << TEXT("Done.") << std::endl;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// wmain() entry point
|
||
|
//
|
||
|
int
|
||
|
_cdecl
|
||
|
wmain(
|
||
|
int Argc,
|
||
|
wchar_t *Argv[]
|
||
|
)
|
||
|
{
|
||
|
INT Result = 0;
|
||
|
|
||
|
_set_new_handler( MyNewHandler ); // handles PREFIX issues
|
||
|
|
||
|
try
|
||
|
{
|
||
|
CDrive Disk;
|
||
|
ProgramArguments Args(Argc, Argv);
|
||
|
|
||
|
if ( S_OK != Disk.Initialize(Args.DriveLetter.c_str()))
|
||
|
{
|
||
|
throw new W32Error();
|
||
|
}
|
||
|
|
||
|
VerifyPartition(Disk, Args);
|
||
|
Sys(Disk, Args);
|
||
|
}
|
||
|
catch(W32Error *Error)
|
||
|
{
|
||
|
if (Error)
|
||
|
{
|
||
|
Result = (INT)(Error->ErrorCode);
|
||
|
Error->Dump(std::cout);
|
||
|
delete Error;
|
||
|
}
|
||
|
}
|
||
|
catch(ProgramException *Exp)
|
||
|
{
|
||
|
if (Exp)
|
||
|
{
|
||
|
Exp->Dump(std::cout);
|
||
|
delete Exp;
|
||
|
}
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
Result = 1;
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|