[pe] initial WinPE support (BartPE, XP install disc)

* also switched MBR to Win7 one
* also switched version to rufus-next
This commit is contained in:
Pete Batard 2012-03-16 18:30:44 +00:00
parent c07832b090
commit 4bd017ff07
8 changed files with 285 additions and 43 deletions

View file

@ -464,7 +464,7 @@ static BOOL WriteMBR(HANDLE hPhysicalDrive)
if ((dt == DT_ISO) && ((fs == FS_FAT16) || (fs == FS_FAT32))) {
r = write_syslinux_mbr(&fake_fd);
} else {
r = write_95b_mbr(&fake_fd);
r = write_win7_mbr(&fake_fd);
}
out:
@ -537,6 +537,229 @@ static BOOL WritePBR(HANDLE hLogicalVolume)
return FALSE;
}
/*
* Setup WinPE for bootable USB
*/
// TODO: set FormatError
static BOOL SetupWinPE(char drive_letter)
{
char src[64], dst[32];
const char* basedir[] = { "i386", "minint" };
const char* patch_str_org[] = { "\\minint\\txtsetup.sif", "\\minint\\system32\\" };
const char* patch_str_rep[] = { "\\$\\i386\\txtsetup.sif", "\\$\\i386\\system32\\" };
const char *win_nt_bt_org = "$win_nt$.~bt", *win_nt_bt_rep = "$\\i386";
const char* winnt_sif = "[Data]\n msdosinitiated = \"1\"\n";
const wchar_t* win_nt_ls = L"$win_nt$.~ls";
STARTUPINFOA si;
PROCESS_INFORMATION pi;
HANDLE handle = INVALID_HANDLE_VALUE;
DWORD i, j, size, rw_size, index = 0, exit_code;
BOOL minint = FALSE, r = FALSE;
char* buf = NULL;
index = ((iso_report.winpe&WINPE_I386) == WINPE_I386)?0:1;
// Parse TXTSETUP.SIF to see if /minint was provided for OsLoadOptions
safe_sprintf(src, sizeof(src), "%c:\\%s\\txtsetup.sif", drive_letter, basedir[index]);
buf = get_token_data(src, "OsLoadOptions");
if (buf != NULL) {
for (i=0; i<strlen(buf); i++)
buf[i] = tolower(buf[i]);
uprintf("OsLoadOptions = %s\n", buf);
minint = (strstr(buf, "/minint") != NULL);
}
safe_free(buf);
// TODO: detect if overwrite?
safe_sprintf(src, sizeof(src), "%c:\\%s\\ntdetect.com", drive_letter, basedir[index]);
safe_sprintf(dst, sizeof(dst), "%c:\\ntdetect.com", drive_letter);
CopyFileA(src, dst, TRUE);
safe_sprintf(src, sizeof(src), "%c:\\%s\\setupldr.bin", drive_letter, basedir[index]);
safe_sprintf(dst, sizeof(dst), "%c:\\BOOTMGR", drive_letter);
CopyFileA(src, dst, TRUE);
// \minint with /minint option doesn't require further processing => return true
// \minint and no \i386 without /minint is unclear => return error
if (iso_report.winpe&WINPE_MININT) {
if (minint) {
uprintf("Detected \\minint directory with /minint option: nothing to patch\n");
r = TRUE;
} else if (!(iso_report.winpe&WINPE_I386)) {
uprintf("Detected \\minint directory only but no /minint option: not sure what to do\n");
}
goto out;
}
// At this stage we only handle \i386
handle = CreateFileA(dst, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
uprintf("Could not open %s for patching: %s\n", dst, WindowsErrorString());
goto out;
}
size = GetFileSize(handle, NULL);
if (size == INVALID_FILE_SIZE) {
uprintf("Could not get size for file %s: %s\n", dst, WindowsErrorString());
goto out;
}
buf = (char*)malloc(size);
if (buf == NULL)
goto out;
if ((!ReadFile(handle, buf, size, &rw_size, NULL)) || (size != rw_size)) {
uprintf("Could not read file %s: %s\n", dst, WindowsErrorString());
goto out;
}
SetFilePointer(handle, 0, NULL, FILE_BEGIN);
/* Patch setupldr.bin so that [\$]\i386 can be used instead of \minint */
uprintf("Patching file %s\n", dst);
for (i=0; i<size-32; i++) {
for (j=0; j<ARRAYSIZE(patch_str_org); j++) {
if (safe_strnicmp(&buf[i], patch_str_org[j], strlen(patch_str_org[j])-1) == 0) {
uprintf(" 0x%08X: '%s' -> '%s'\n", i, &buf[i], &patch_str_rep[j][minint?2:0]);
strcpy(&buf[i], &patch_str_rep[j][minint?2:0]);
}
}
}
if (minint) {
if ((!WriteFile(handle, buf, size, &rw_size, NULL)) || (size != rw_size)) {
uprintf("Could not write patched file: %s\n", WindowsErrorString());
goto out;
}
}else {
// Finish patching \bootmgr
for (i=0; i<size-32; i++) {
if (safe_strnicmp(&buf[i], win_nt_bt_org, strlen(win_nt_bt_org)-1) == 0) {
uprintf(" 0x%08X: '%s' -> '%s%s'\n", i, &buf[i], win_nt_bt_rep, &buf[i+strlen(win_nt_bt_org)]);
strcpy(&buf[i], win_nt_bt_rep);
buf[i+strlen(win_nt_bt_rep)] = buf[i+strlen(win_nt_bt_org)];
buf[i+strlen(win_nt_bt_rep)+1] = 0;
}
}
if ((!WriteFile(handle, buf, size, &rw_size, NULL)) || (size != rw_size)) {
uprintf("Could not write patched file: %s\n", WindowsErrorString());
goto out;
}
safe_free(buf);
safe_closehandle(handle);
// Rename \i386 to \$\i386
safe_sprintf(src, sizeof(src), "%c:\\$", drive_letter);
if (!CreateDirectoryA(src, NULL)) {
uprintf("Could not create %s: %s\n", src, WindowsErrorString());
goto out;
}
safe_sprintf(src, sizeof(src), "%c:\\i386", drive_letter);
safe_sprintf(dst, sizeof(dst), "%c:\\$\\i386", drive_letter);
uprintf("Renaming '%s' to '%s'\n", src, dst);
if (!MoveFileA(src, dst)) {
uprintf(" failed: %s\n", WindowsErrorString());
goto out;
}
// Create a \$\i386\winnt.sif (avoids "Please insert" errors)
safe_sprintf(src, sizeof(src), "%c:\\$\\i386\\winnt.sif", drive_letter);
size = strlen(winnt_sif);
handle = CreateFileA(src, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
uprintf("Could not create %s: %s\n", src, WindowsErrorString());
goto out;
}
if ((!WriteFile(handle, winnt_sif, size, &rw_size, NULL)) || (size != rw_size)) {
uprintf("Could not write %s: %s\n", src, WindowsErrorString());
goto out;
}
safe_closehandle(handle);
// Uncompress $\\i386\\setupdd.sy_
// Don't bother calling Extract() from cabinet.dll - calling expand.exe is much simpler
// TODO: factorize CreateProcess()?
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
memset(&pi, 0, sizeof(pi));
uprintf("Decompressing %c:\\$\\i386\\setupdd.sy_\n", drive_letter);
safe_sprintf(src, sizeof(src), "expand %c:\\$\\i386\\setupdd.sy_ %c:\\$\\i386\\setupdd.sys", drive_letter, drive_letter);
if (!CreateProcessA(NULL, src, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
uprintf("Could not launch command '%s': %s", src, WindowsErrorString());
goto out;
}
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, &exit_code);
safe_closehandle(pi.hProcess);
safe_closehandle(pi.hThread);
if (exit_code != 0) {
uprintf("Command '%s' failed with exit code: %d\n", src, exit_code);
goto out;
}
// Patch the uncompressed $\\i386\\setupdd.sys
safe_sprintf(dst, sizeof(dst), "%c:\\$\\i386\\setupdd.sys", drive_letter);
handle = CreateFileA(dst, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
uprintf("Could not open %s for patching: %s\n", dst, WindowsErrorString());
goto out;
}
size = GetFileSize(handle, NULL);
if (size == INVALID_FILE_SIZE) {
uprintf("Could not get size for file %s: %s\n", dst, WindowsErrorString());
goto out;
}
buf = (char*)malloc(size);
if (buf == NULL)
goto out;
if ((!ReadFile(handle, buf, size, &rw_size, NULL)) || (size != rw_size)) {
uprintf("Could not read file %s: %s\n", dst, WindowsErrorString());
goto out;
}
SetFilePointer(handle, 0, NULL, FILE_BEGIN);
uprintf("Patching %s\n", dst);
for (i=0; i<size-32; i++) {
if (_wcsnicmp((wchar_t*)&buf[i], win_nt_ls, wcslen(win_nt_ls)-1) == 0) {
uprintf(" 0x%08X: '$win_nt$.~ls' -> '$'\n", i);
buf[i+2] = 0;
}
}
if ((!WriteFile(handle, buf, size, &rw_size, NULL)) || (size != rw_size)) {
uprintf("Could not write patched file: %s\n", WindowsErrorString());
goto out;
}
safe_closehandle(handle);
// Recompress to $\\i386\\setupdd.sy_
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
memset(&pi, 0, sizeof(pi));
uprintf("Compressing back %s\n", dst);
safe_sprintf(src, sizeof(src), "makecab %c:\\$\\i386\\setupdd.sys %c:\\$\\i386\\setupdd.sy_", drive_letter, drive_letter);
if (!CreateProcessA(NULL, src, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
uprintf("Could not launch command '%s': %s", src, WindowsErrorString());
goto out;
}
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, &exit_code);
safe_closehandle(pi.hProcess);
safe_closehandle(pi.hThread);
if (exit_code != 0) {
uprintf("Command '%s' failed with exit code: %d\n", src, exit_code);
goto out;
}
// Delete uncompressed file
_unlink(dst);
}
r = TRUE;
out:
safe_closehandle(handle);
safe_free(buf);
return r;
}
/*
* Issue a complete remount of the volume
*/
@ -753,6 +976,10 @@ DWORD WINAPI FormatThread(LPVOID param)
goto out;
}
}
if (IS_WINPE(iso_report.winpe)) {
// Apply WinPe fixup
SetupWinPE(drive_name[0]);
}
}
if (IsChecked(IDC_SET_ICON))
SetAutorun(drive_name);