2011-12-01 17:20:52 +00:00
|
|
|
/*
|
2011-12-05 11:36:02 +00:00
|
|
|
* Rufus: The Reliable USB Formatting Utility
|
2011-12-01 17:20:52 +00:00
|
|
|
* Formatting function calls
|
2012-01-02 23:55:47 +00:00
|
|
|
* Copyright (c) 2011-2012 Pete Batard <pete@akeo.ie>
|
2011-12-01 17:20:52 +00:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#ifdef _CRTDBG_MAP_ALLOC
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <crtdbg.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <windowsx.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <process.h>
|
2011-12-01 17:54:35 +00:00
|
|
|
#include <stddef.h>
|
2012-02-21 00:08:31 +00:00
|
|
|
#include <ctype.h>
|
2011-12-01 17:20:52 +00:00
|
|
|
|
|
|
|
#include "msapi_utf8.h"
|
|
|
|
#include "rufus.h"
|
|
|
|
#include "resource.h"
|
|
|
|
#include "br.h"
|
|
|
|
#include "fat16.h"
|
|
|
|
#include "fat32.h"
|
2012-02-03 18:19:50 +00:00
|
|
|
#include "ntfs.h"
|
2011-12-14 20:48:20 +00:00
|
|
|
#include "partition_info.h"
|
2011-12-01 17:20:52 +00:00
|
|
|
#include "file.h"
|
|
|
|
#include "format.h"
|
2011-12-06 02:23:28 +00:00
|
|
|
#include "badblocks.h"
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2011-12-01 17:54:35 +00:00
|
|
|
/*
|
|
|
|
* Globals
|
|
|
|
*/
|
|
|
|
DWORD FormatStatus;
|
2011-12-06 23:35:55 +00:00
|
|
|
badblocks_report report;
|
2011-12-09 01:39:13 +00:00
|
|
|
static float format_percent = 0.0f;
|
|
|
|
static int task_number = 0;
|
|
|
|
/* Number of steps for each FS for FCC_STRUCTURE_PROGRESS */
|
2011-12-09 12:57:32 +00:00
|
|
|
const int nb_steps[FS_MAX] = { 5, 5, 12, 10 };
|
|
|
|
static int fs_index = 0;
|
2011-12-01 17:54:35 +00:00
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
/*
|
|
|
|
* FormatEx callback. Return FALSE to halt operations
|
|
|
|
*/
|
|
|
|
static BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command, DWORD Action, PVOID pData)
|
|
|
|
{
|
|
|
|
DWORD* percent;
|
|
|
|
if (IS_ERROR(FormatStatus))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
switch(Command) {
|
|
|
|
case FCC_PROGRESS:
|
|
|
|
percent = (DWORD*)pData;
|
2012-02-03 18:19:50 +00:00
|
|
|
PrintStatus(0, FALSE, "Formatting: %d%% completed.", *percent);
|
2011-12-09 12:57:32 +00:00
|
|
|
UpdateProgress(OP_FORMAT, 1.0f * (*percent));
|
2011-12-01 17:20:52 +00:00
|
|
|
break;
|
|
|
|
case FCC_STRUCTURE_PROGRESS: // No progress on quick format
|
2012-02-03 18:19:50 +00:00
|
|
|
PrintStatus(0, TRUE, "Creating file system: Task %d/%d completed.", ++task_number, nb_steps[fs_index]);
|
2011-12-09 12:57:32 +00:00
|
|
|
format_percent += 100.0f / (1.0f * nb_steps[fs_index]);
|
|
|
|
UpdateProgress(OP_CREATE_FS, format_percent);
|
2011-12-01 17:20:52 +00:00
|
|
|
break;
|
|
|
|
case FCC_DONE:
|
2012-02-03 18:19:50 +00:00
|
|
|
PrintStatus(0, TRUE, "Creating file system: Task %d/%d completed.", nb_steps[fs_index], nb_steps[fs_index]);
|
2011-12-09 12:57:32 +00:00
|
|
|
UpdateProgress(OP_CREATE_FS, 100.0f);
|
2011-12-01 17:20:52 +00:00
|
|
|
if(*(BOOLEAN*)pData == FALSE) {
|
|
|
|
uprintf("Error while formatting.\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FCC_DONE_WITH_STRUCTURE: // We get this message when formatting Small FAT16
|
|
|
|
// pData Seems to be a struct with at least one (32 BIT!!!) string pointer to the size in MB
|
2011-12-13 02:10:27 +00:00
|
|
|
uprintf("Done with that sort of thing: Action=%d pData=%0p\n", Action, pData);
|
|
|
|
// /!\ THE FOLLOWING ONLY WORKS ON VISTA OR LATER - DO NOT ENABLE ON XP!
|
|
|
|
// DumpBufferHex(pData, 8);
|
|
|
|
// uprintf("Volume size: %s MB\n", (char*)(LONG_PTR)(*(ULONG32*)pData));
|
2011-12-01 17:20:52 +00:00
|
|
|
break;
|
|
|
|
case FCC_INCOMPATIBLE_FILE_SYSTEM:
|
|
|
|
uprintf("Incompatible File System\n");
|
2011-12-04 19:47:27 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INCOMPATIBLE_FS);
|
2011-12-01 17:20:52 +00:00
|
|
|
break;
|
|
|
|
case FCC_ACCESS_DENIED:
|
|
|
|
uprintf("Access denied\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
|
|
|
|
break;
|
|
|
|
case FCC_MEDIA_WRITE_PROTECTED:
|
|
|
|
uprintf("Media is write protected\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_PROTECT;
|
|
|
|
break;
|
|
|
|
case FCC_VOLUME_IN_USE:
|
|
|
|
uprintf("Volume is in use\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_DEVICE_IN_USE;
|
|
|
|
break;
|
|
|
|
case FCC_CANT_QUICK_FORMAT:
|
|
|
|
uprintf("Cannot quick format this volume\n");
|
2011-12-04 19:47:27 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_QUICK_FORMAT);
|
2011-12-01 17:20:52 +00:00
|
|
|
break;
|
|
|
|
case FCC_BAD_LABEL:
|
|
|
|
uprintf("Bad label\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_LABEL_TOO_LONG;
|
|
|
|
break;
|
|
|
|
case FCC_OUTPUT:
|
|
|
|
uprintf("%s\n", ((PTEXTOUTPUT)pData)->Output);
|
|
|
|
break;
|
|
|
|
case FCC_CLUSTER_SIZE_TOO_BIG:
|
|
|
|
case FCC_CLUSTER_SIZE_TOO_SMALL:
|
|
|
|
uprintf("Unsupported cluster size\n");
|
2011-12-04 19:47:27 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INVALID_CLUSTER_SIZE);
|
2011-12-01 17:20:52 +00:00
|
|
|
break;
|
|
|
|
case FCC_VOLUME_TOO_BIG:
|
|
|
|
case FCC_VOLUME_TOO_SMALL:
|
|
|
|
uprintf("Volume is too %s\n", FCC_VOLUME_TOO_BIG?"big":"small");
|
2011-12-04 19:47:27 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INVALID_VOLUME_SIZE);
|
2011-12-01 17:20:52 +00:00
|
|
|
case FCC_NO_MEDIA_IN_DRIVE:
|
|
|
|
uprintf("No media in drive\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_MEDIA_IN_DRIVE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
uprintf("FormatExCallback: received unhandled command %X\n", Command);
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_SUPPORTED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (!IS_ERROR(FormatStatus));
|
|
|
|
}
|
|
|
|
|
2012-03-09 01:38:52 +00:00
|
|
|
/*
|
|
|
|
* Chkdsk callback. Return FALSE to halt operations
|
|
|
|
*/
|
|
|
|
static BOOLEAN __stdcall ChkdskCallback(FILE_SYSTEM_CALLBACK_COMMAND Command, DWORD Action, PVOID pData)
|
|
|
|
{
|
|
|
|
DWORD* percent;
|
|
|
|
if (IS_ERROR(FormatStatus))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
switch(Command) {
|
|
|
|
case FCC_PROGRESS:
|
|
|
|
case FCC_CHECKDISK_PROGRESS:
|
|
|
|
percent = (DWORD*)pData;
|
|
|
|
PrintStatus(0, FALSE, "NTFS Fixup: %d%% completed.", *percent);
|
|
|
|
break;
|
|
|
|
case FCC_DONE:
|
|
|
|
if(*(BOOLEAN*)pData == FALSE) {
|
|
|
|
uprintf("Error while checking disk.\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FCC_UNKNOWN1A:
|
|
|
|
case FCC_DONE_WITH_STRUCTURE:
|
|
|
|
// Silence these specific calls
|
|
|
|
break;
|
|
|
|
case FCC_INCOMPATIBLE_FILE_SYSTEM:
|
|
|
|
uprintf("Incompatible File System\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INCOMPATIBLE_FS);
|
|
|
|
break;
|
|
|
|
case FCC_ACCESS_DENIED:
|
|
|
|
uprintf("Access denied\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
|
|
|
|
break;
|
|
|
|
case FCC_MEDIA_WRITE_PROTECTED:
|
|
|
|
uprintf("Media is write protected\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_PROTECT;
|
|
|
|
break;
|
|
|
|
case FCC_VOLUME_IN_USE:
|
|
|
|
uprintf("Volume is in use\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_DEVICE_IN_USE;
|
|
|
|
break;
|
|
|
|
case FCC_OUTPUT:
|
|
|
|
uprintf("%s\n", ((PTEXTOUTPUT)pData)->Output);
|
|
|
|
break;
|
|
|
|
case FCC_NO_MEDIA_IN_DRIVE:
|
|
|
|
uprintf("No media in drive\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_MEDIA_IN_DRIVE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
uprintf("ChkdskExCallback: received unhandled command %X\n", Command);
|
|
|
|
// Assume the command isn't an error
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (!IS_ERROR(FormatStatus));
|
|
|
|
}
|
|
|
|
|
2012-02-15 21:55:41 +00:00
|
|
|
/*
|
|
|
|
* Converts an UTF-16 label to a valid FAT/NTFS one
|
|
|
|
*/
|
|
|
|
static void ToValidLabel(WCHAR* name, BOOL bFAT)
|
|
|
|
{
|
|
|
|
size_t i, j, k;
|
|
|
|
BOOL found;
|
|
|
|
WCHAR unauthorized[] = L"*?.,;:/\\|+=<>[]";
|
|
|
|
WCHAR to_underscore[] = L"\t";
|
|
|
|
|
|
|
|
if (name == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i=0, k=0; i<wcslen(name); i++) {
|
|
|
|
if (bFAT) { // NTFS does allows all the FAT unauthorized above
|
|
|
|
found = FALSE;
|
|
|
|
for (j=0; j<wcslen(unauthorized); j++) {
|
|
|
|
if (name[i] == unauthorized[j]) {
|
|
|
|
found = TRUE; break;
|
|
|
|
}
|
|
|
|
}
|
2012-02-21 19:46:28 +00:00
|
|
|
// A FAT label that contains extended chars will be rejected
|
|
|
|
if (name[i] >= 0x80) {
|
|
|
|
name[k++] = '_';
|
|
|
|
found = TRUE;
|
|
|
|
}
|
2012-02-15 21:55:41 +00:00
|
|
|
if (found) continue;
|
|
|
|
}
|
|
|
|
found = FALSE;
|
|
|
|
for (j=0; j<wcslen(to_underscore); j++) {
|
|
|
|
if (name[i] == to_underscore[j]) {
|
|
|
|
name[k++] = '_';
|
|
|
|
found = TRUE; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found) continue;
|
2012-02-21 00:08:31 +00:00
|
|
|
name[k++] = bFAT?toupper(name[i]):name[i];
|
2012-02-15 21:55:41 +00:00
|
|
|
}
|
|
|
|
name[k] = 0;
|
|
|
|
if (bFAT) {
|
|
|
|
name[11] = 0;
|
2012-02-21 19:46:28 +00:00
|
|
|
for (i=0, j=0; name[i]!=0; i++)
|
|
|
|
if (name[i] == '_') j++;
|
|
|
|
if (i<2*j) {
|
|
|
|
// If the final label is mostly underscore, use the proposed label
|
|
|
|
uprintf("FAT label is mostly undercores. Using '%s' label instead.\n", SelectedDrive.proposed_label);
|
|
|
|
for(i=0; SelectedDrive.proposed_label[i]!=0; i++)
|
|
|
|
name[i] = SelectedDrive.proposed_label[i];
|
|
|
|
name[i] = 0;
|
|
|
|
}
|
2012-02-15 21:55:41 +00:00
|
|
|
} else {
|
|
|
|
name[32] = 0;
|
|
|
|
}
|
2012-02-21 19:46:28 +00:00
|
|
|
|
|
|
|
// Needed for disk by label isolinux.cfg workaround
|
2012-02-21 00:08:31 +00:00
|
|
|
wchar_to_utf8_no_alloc(name, iso_report.usb_label, sizeof(iso_report.usb_label));
|
2012-02-15 21:55:41 +00:00
|
|
|
}
|
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
/*
|
|
|
|
* Call on fmifs.dll's FormatEx() to format the drive
|
|
|
|
*/
|
|
|
|
static BOOL FormatDrive(char DriveLetter)
|
|
|
|
{
|
|
|
|
BOOL r = FALSE;
|
|
|
|
PF_DECL(FormatEx);
|
|
|
|
WCHAR wDriveRoot[] = L"?:\\";
|
|
|
|
WCHAR wFSType[32];
|
2012-02-15 21:55:41 +00:00
|
|
|
WCHAR wLabel[64];
|
2011-12-01 17:20:52 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
wDriveRoot[0] = (WCHAR)DriveLetter;
|
2012-02-03 18:19:50 +00:00
|
|
|
PrintStatus(0, TRUE, "Formatting...");
|
2011-12-01 17:20:52 +00:00
|
|
|
PF_INIT_OR_OUT(FormatEx, fmifs);
|
|
|
|
|
|
|
|
GetWindowTextW(hFileSystem, wFSType, ARRAYSIZE(wFSType));
|
|
|
|
// We may have a " (Default)" trail
|
|
|
|
for (i=0; i<wcslen(wFSType); i++) {
|
|
|
|
if (wFSType[i] == ' ') {
|
|
|
|
wFSType[i] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel));
|
2012-02-15 21:55:41 +00:00
|
|
|
// Make sure the label is valid
|
|
|
|
ToValidLabel(wLabel, (wFSType[0] == 'F') && (wFSType[1] == 'A') && (wFSType[2] == 'T'));
|
2011-12-01 17:20:52 +00:00
|
|
|
uprintf("Using cluster size: %d bytes\n", ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize)));
|
2011-12-09 01:39:13 +00:00
|
|
|
format_percent = 0.0f;
|
|
|
|
task_number = 0;
|
2011-12-11 02:19:38 +00:00
|
|
|
fs_index = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
|
2011-12-04 20:13:51 +00:00
|
|
|
pfFormatEx(wDriveRoot, SelectedDrive.Geometry.MediaType, wFSType, wLabel,
|
2011-12-01 17:20:52 +00:00
|
|
|
IsChecked(IDC_QUICKFORMAT), (ULONG)ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize)),
|
|
|
|
FormatExCallback);
|
|
|
|
if (!IS_ERROR(FormatStatus)) {
|
|
|
|
uprintf("Format completed.\n");
|
|
|
|
r = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2012-03-09 01:38:52 +00:00
|
|
|
/*
|
|
|
|
* Call on fmifs.dll's Chkdsk() to fixup the filesystem
|
|
|
|
*/
|
|
|
|
static BOOL CheckDisk(char DriveLetter)
|
|
|
|
{
|
|
|
|
BOOL r = FALSE;
|
|
|
|
PF_DECL(Chkdsk);
|
|
|
|
WCHAR wDriveRoot[] = L"?:\\";
|
|
|
|
WCHAR wFSType[32];
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
wDriveRoot[0] = (WCHAR)DriveLetter;
|
|
|
|
PrintStatus(0, TRUE, "NTFS Fixup (Checkdisk)...");
|
|
|
|
|
|
|
|
PF_INIT_OR_OUT(Chkdsk, fmifs);
|
|
|
|
|
|
|
|
GetWindowTextW(hFileSystem, wFSType, ARRAYSIZE(wFSType));
|
|
|
|
// We may have a " (Default)" trail
|
|
|
|
for (i=0; i<wcslen(wFSType); i++) {
|
|
|
|
if (wFSType[i] == ' ') {
|
|
|
|
wFSType[i] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pfChkdsk(wDriveRoot, wFSType, FALSE, FALSE, FALSE, FALSE, NULL, NULL, ChkdskCallback);
|
|
|
|
if (!IS_ERROR(FormatStatus)) {
|
|
|
|
uprintf("NTFS Fixup completed.\n");
|
|
|
|
r = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
static BOOL AnalyzeMBR(HANDLE hPhysicalDrive)
|
|
|
|
{
|
2011-12-13 23:29:09 +00:00
|
|
|
FILE fake_fd = { 0 };
|
2011-12-01 17:20:52 +00:00
|
|
|
|
|
|
|
fake_fd._ptr = (char*)hPhysicalDrive;
|
|
|
|
fake_fd._bufsiz = SelectedDrive.Geometry.BytesPerSector;
|
|
|
|
|
2011-12-13 23:29:09 +00:00
|
|
|
if (!is_br(&fake_fd)) {
|
|
|
|
uprintf("Drive does not have an x86 master boot record\n");
|
2011-12-01 17:20:52 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2011-12-13 23:29:09 +00:00
|
|
|
if (is_dos_mbr(&fake_fd)) {
|
|
|
|
uprintf("Drive has a Microsoft DOS/NT/95A master boot record\n");
|
2011-12-01 17:20:52 +00:00
|
|
|
} else if (is_dos_f2_mbr(&fake_fd)) {
|
2011-12-13 23:29:09 +00:00
|
|
|
uprintf("Drive has a Microsoft DOS/NT/95A master boot record "
|
|
|
|
"with the undocumented F2 instruction\n");
|
2011-12-01 17:20:52 +00:00
|
|
|
} else if (is_95b_mbr(&fake_fd)) {
|
2011-12-13 23:29:09 +00:00
|
|
|
uprintf("Drive has a Microsoft 95B/98/98SE/ME master boot record\n");
|
2011-12-01 17:20:52 +00:00
|
|
|
} else if (is_2000_mbr(&fake_fd)) {
|
2011-12-13 23:29:09 +00:00
|
|
|
uprintf("Drive has a Microsoft 2000/XP/2003 master boot record\n");
|
2011-12-01 17:20:52 +00:00
|
|
|
} else if (is_vista_mbr(&fake_fd)) {
|
2011-12-13 23:29:09 +00:00
|
|
|
uprintf("Drive has a Microsoft Vista master boot record\n");
|
2011-12-01 17:20:52 +00:00
|
|
|
} else if (is_win7_mbr(&fake_fd)) {
|
2011-12-13 23:29:09 +00:00
|
|
|
uprintf("Drive has a Microsoft 7 master boot record\n");
|
2011-12-01 17:20:52 +00:00
|
|
|
} else if (is_zero_mbr(&fake_fd)) {
|
2011-12-13 23:29:09 +00:00
|
|
|
uprintf("Drive has a zeroed non-bootable master boot record\n");
|
2011-12-01 17:20:52 +00:00
|
|
|
} else {
|
|
|
|
uprintf("Unknown boot record\n");
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-12-13 23:29:09 +00:00
|
|
|
static BOOL AnalyzePBR(HANDLE hLogicalVolume)
|
|
|
|
{
|
|
|
|
FILE fake_fd = { 0 };
|
|
|
|
|
|
|
|
fake_fd._ptr = (char*)hLogicalVolume;
|
|
|
|
fake_fd._bufsiz = SelectedDrive.Geometry.BytesPerSector;
|
|
|
|
|
|
|
|
// TODO: Add/Eliminate FAT12?
|
|
|
|
if (!is_br(&fake_fd)) {
|
|
|
|
uprintf("Volume does not have an x86 partition boot record\n");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (is_fat_16_br(&fake_fd) || is_fat_32_br(&fake_fd)) {
|
|
|
|
if (entire_fat_16_br_matches(&fake_fd)) {
|
|
|
|
uprintf("Drive has a FAT16 DOS partition boot record\n");
|
|
|
|
} else if (entire_fat_16_fd_br_matches(&fake_fd)) {
|
|
|
|
uprintf("Drive has a FAT16 FreeDOS partition boot record\n");
|
|
|
|
} else if (entire_fat_32_br_matches(&fake_fd)) {
|
|
|
|
uprintf("Drive has a FAT32 DOS partition boot record\n");
|
|
|
|
} else if (entire_fat_32_nt_br_matches(&fake_fd)) {
|
|
|
|
uprintf("Drive has a FAT32 NT partition boot record\n");
|
|
|
|
} else if (entire_fat_32_fd_br_matches(&fake_fd)) {
|
|
|
|
uprintf("Drive has a FAT32 FreeDOS partition boot record\n");
|
|
|
|
} else {
|
|
|
|
uprintf("Drive has a unknown FAT16 or FAT32 partition boot record\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
2011-12-06 18:11:38 +00:00
|
|
|
|
|
|
|
static BOOL ClearMBR(HANDLE hPhysicalDrive)
|
|
|
|
{
|
2011-12-13 23:29:09 +00:00
|
|
|
FILE fake_fd = { 0 };
|
2011-12-06 18:11:38 +00:00
|
|
|
|
|
|
|
fake_fd._ptr = (char*)hPhysicalDrive;
|
|
|
|
fake_fd._bufsiz = SelectedDrive.Geometry.BytesPerSector;
|
|
|
|
return clear_mbr(&fake_fd);
|
|
|
|
}
|
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
/*
|
2011-12-02 00:11:53 +00:00
|
|
|
* Process the Master Boot Record
|
2011-12-01 17:20:52 +00:00
|
|
|
*/
|
2011-12-02 00:11:53 +00:00
|
|
|
static BOOL WriteMBR(HANDLE hPhysicalDrive)
|
2011-12-01 17:20:52 +00:00
|
|
|
{
|
|
|
|
BOOL r = FALSE;
|
2012-03-03 23:12:48 +00:00
|
|
|
int dt, fs;
|
2011-12-01 17:20:52 +00:00
|
|
|
unsigned char* buf = NULL;
|
|
|
|
size_t SecSize = SelectedDrive.Geometry.BytesPerSector;
|
|
|
|
size_t nSecs = (0x200 + SecSize -1) / SecSize;
|
2011-12-13 23:29:09 +00:00
|
|
|
FILE fake_fd = { 0 };
|
2011-12-01 17:20:52 +00:00
|
|
|
|
|
|
|
if (!AnalyzeMBR(hPhysicalDrive)) return FALSE;
|
|
|
|
|
|
|
|
// FormatEx rewrites the MBR and removes the LBA attribute of FAT16
|
|
|
|
// and FAT32 partitions - we need to correct this in the MBR
|
|
|
|
// TODO: something else for bootable GPT
|
|
|
|
buf = (unsigned char*)malloc(SecSize * nSecs);
|
|
|
|
if (buf == NULL) {
|
|
|
|
uprintf("Could not allocate memory for MBR");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2011-12-06 02:23:28 +00:00
|
|
|
if (!read_sectors(hPhysicalDrive, SelectedDrive.Geometry.BytesPerSector, 0, nSecs, buf)) {
|
2011-12-01 17:20:52 +00:00
|
|
|
uprintf("Could not read MBR\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_READ_FAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2011-12-02 00:11:53 +00:00
|
|
|
|
|
|
|
switch (ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))) {
|
2011-12-01 17:20:52 +00:00
|
|
|
case FS_FAT16:
|
2011-12-02 00:11:53 +00:00
|
|
|
if (buf[0x1c2] == 0x0e) {
|
|
|
|
uprintf("Partition is already FAT16 LBA...\n");
|
|
|
|
} else if ((buf[0x1c2] != 0x04) && (buf[0x1c2] != 0x06)) {
|
|
|
|
uprintf("Warning: converting a non FAT16 partition to FAT16 LBA: FS type=0x%02x\n", buf[0x1c2]);
|
|
|
|
}
|
2011-12-01 17:20:52 +00:00
|
|
|
buf[0x1c2] = 0x0e;
|
|
|
|
break;
|
|
|
|
case FS_FAT32:
|
2011-12-02 00:11:53 +00:00
|
|
|
if (buf[0x1c2] == 0x0c) {
|
|
|
|
uprintf("Partition is already FAT32 LBA...\n");
|
|
|
|
} else if (buf[0x1c2] != 0x0b) {
|
|
|
|
uprintf("Warning: converting a non FAT32 partition to FAT32 LBA: FS type=0x%02x\n", buf[0x1c2]);
|
|
|
|
}
|
2011-12-01 17:20:52 +00:00
|
|
|
buf[0x1c2] = 0x0c;
|
|
|
|
break;
|
|
|
|
}
|
2011-12-02 00:11:53 +00:00
|
|
|
if (IsChecked(IDC_DOS)) {
|
2011-12-01 17:20:52 +00:00
|
|
|
buf[0x1be] = 0x80; // Set first partition bootable
|
|
|
|
}
|
|
|
|
|
2011-12-06 02:23:28 +00:00
|
|
|
if (!write_sectors(hPhysicalDrive, SecSize, 0, nSecs, buf)) {
|
2011-12-01 17:20:52 +00:00
|
|
|
uprintf("Could not write MBR\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
fake_fd._ptr = (char*)hPhysicalDrive;
|
|
|
|
fake_fd._bufsiz = SelectedDrive.Geometry.BytesPerSector;
|
2012-03-03 23:12:48 +00:00
|
|
|
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
|
|
|
|
dt = (int)ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType));
|
|
|
|
if ((dt == DT_ISO) && ((fs == FS_FAT16) || (fs == FS_FAT32))) {
|
2012-01-12 02:52:40 +00:00
|
|
|
r = write_syslinux_mbr(&fake_fd);
|
|
|
|
} else {
|
2012-03-16 18:30:44 +00:00
|
|
|
r = write_win7_mbr(&fake_fd);
|
2012-01-12 02:52:40 +00:00
|
|
|
}
|
2011-12-01 17:20:52 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
safe_free(buf);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-12-02 00:11:53 +00:00
|
|
|
/*
|
|
|
|
* Process the Partition Boot Record
|
|
|
|
*/
|
2012-02-14 01:23:42 +00:00
|
|
|
static BOOL WritePBR(HANDLE hLogicalVolume)
|
2011-12-01 17:20:52 +00:00
|
|
|
{
|
2011-12-13 23:29:09 +00:00
|
|
|
int i;
|
|
|
|
FILE fake_fd = { 0 };
|
2012-02-14 01:23:42 +00:00
|
|
|
BOOL bFreeDOS = (ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType)) == DT_FREEDOS);
|
2011-12-01 17:20:52 +00:00
|
|
|
|
|
|
|
fake_fd._ptr = (char*)hLogicalVolume;
|
|
|
|
fake_fd._bufsiz = SelectedDrive.Geometry.BytesPerSector;
|
|
|
|
|
2011-12-14 20:48:20 +00:00
|
|
|
// TODO: call write_partition_number_of_heads() and write_partition_start_sector_number()?
|
2011-12-02 00:11:53 +00:00
|
|
|
switch (ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))) {
|
|
|
|
case FS_FAT16:
|
2011-12-13 23:29:09 +00:00
|
|
|
if (!is_fat_16_fs(&fake_fd)) {
|
|
|
|
uprintf("New volume does not have a FAT16 boot sector\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
uprintf("Confirmed new volume has a FAT16 boot sector\n");
|
2011-12-15 00:46:47 +00:00
|
|
|
if (bFreeDOS) {
|
|
|
|
if (!write_fat_16_fd_br(&fake_fd, 0)) break;
|
2012-02-03 18:19:50 +00:00
|
|
|
} else {
|
|
|
|
if (!write_fat_16_br(&fake_fd, 0)) break;
|
|
|
|
}
|
2011-12-15 00:46:47 +00:00
|
|
|
// Disk Drive ID needs to be corrected on XP
|
|
|
|
if (!write_partition_physical_disk_drive_id_fat16(&fake_fd))
|
2011-12-13 23:29:09 +00:00
|
|
|
break;
|
|
|
|
return TRUE;
|
2011-12-02 00:11:53 +00:00
|
|
|
case FS_FAT32:
|
2011-12-13 23:29:09 +00:00
|
|
|
for (i=0; i<2; i++) {
|
|
|
|
if (!is_fat_32_fs(&fake_fd)) {
|
|
|
|
uprintf("New volume does not have a %s FAT32 boot sector\n", i?"secondary":"primary");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
uprintf("Confirmed new volume has a %s FAT32 boot sector\n", i?"secondary":"primary");
|
|
|
|
uprintf("Setting %s FAT32 boot sector for DOS boot...\n", i?"secondary":"primary");
|
2011-12-15 00:46:47 +00:00
|
|
|
if (bFreeDOS) {
|
|
|
|
if (!write_fat_32_fd_br(&fake_fd, 0)) break;
|
|
|
|
} else if (!write_fat_32_br(&fake_fd, 0)) break;
|
|
|
|
// Disk Drive ID needs to be corrected on XP
|
|
|
|
if (!write_partition_physical_disk_drive_id_fat32(&fake_fd))
|
2011-12-13 23:29:09 +00:00
|
|
|
break;
|
|
|
|
fake_fd._cnt += 6 * (int)SelectedDrive.Geometry.BytesPerSector;
|
|
|
|
}
|
|
|
|
return TRUE;
|
2012-02-03 18:19:50 +00:00
|
|
|
case FS_NTFS:
|
|
|
|
if (!is_ntfs_fs(&fake_fd)) {
|
|
|
|
uprintf("New volume does not have an NTFS boot sector\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
uprintf("Confirmed new volume has an NTFS boot sector\n");
|
|
|
|
if (!write_ntfs_br(&fake_fd)) break;
|
|
|
|
// Note: NTFS requires a full remount after writing the PBR. We dismount when we lock
|
2012-02-07 02:05:58 +00:00
|
|
|
// and also go through a forced remount, so that shouldn't be an issue.
|
|
|
|
// But with NTFS, if you don't remount, you don't boot!
|
2012-02-03 18:19:50 +00:00
|
|
|
return TRUE;
|
2011-12-02 00:11:53 +00:00
|
|
|
default:
|
|
|
|
uprintf("unsupported FS for FS BR processing\n");
|
|
|
|
break;
|
2011-12-01 17:20:52 +00:00
|
|
|
}
|
2011-12-02 00:11:53 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
|
|
|
return FALSE;
|
2011-12-01 17:20:52 +00:00
|
|
|
}
|
|
|
|
|
2012-03-16 18:30:44 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2012-02-21 00:08:31 +00:00
|
|
|
/*
|
|
|
|
* Issue a complete remount of the volume
|
|
|
|
*/
|
|
|
|
static BOOL RemountVolume(char drive_letter)
|
|
|
|
{
|
|
|
|
char drive_guid[50];
|
|
|
|
char drive_name[] = "?:\\";
|
|
|
|
|
|
|
|
drive_name[0] = drive_letter;
|
|
|
|
if (GetVolumeNameForVolumeMountPointA(drive_name, drive_guid, sizeof(drive_guid))) {
|
|
|
|
if (DeleteVolumeMountPointA(drive_name)) {
|
|
|
|
Sleep(200);
|
|
|
|
if (SetVolumeMountPointA(drive_name, drive_guid)) {
|
|
|
|
uprintf("Successfully remounted %s on %s\n", drive_guid, drive_name);
|
|
|
|
} else {
|
|
|
|
uprintf("Failed to remount %s on %s\n", drive_guid, drive_name);
|
|
|
|
// This will leave the drive unaccessible and must be flagged as an error
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_REMOUNT_VOLUME);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
uprintf("Could not remount %s %s\n", drive_name, WindowsErrorString());
|
|
|
|
// Try to continue regardless
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
/*
|
|
|
|
* Standalone thread for the formatting operation
|
|
|
|
*/
|
2012-02-07 02:05:58 +00:00
|
|
|
DWORD WINAPI FormatThread(LPVOID param)
|
2011-12-01 17:20:52 +00:00
|
|
|
{
|
|
|
|
DWORD num = (DWORD)(uintptr_t)param;
|
|
|
|
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
|
|
|
|
HANDLE hLogicalVolume = INVALID_HANDLE_VALUE;
|
2011-12-30 21:23:13 +00:00
|
|
|
SYSTEMTIME lt;
|
2012-02-05 19:54:48 +00:00
|
|
|
char drive_name[] = "?:\\";
|
2011-12-30 21:23:13 +00:00
|
|
|
char bb_msg[512];
|
|
|
|
char logfile[MAX_PATH], *userdir;
|
|
|
|
FILE* log_fd;
|
2012-03-03 23:12:48 +00:00
|
|
|
int r, fs, dt;
|
2011-12-01 17:20:52 +00:00
|
|
|
|
|
|
|
hPhysicalDrive = GetDriveHandle(num, NULL, TRUE, TRUE);
|
|
|
|
if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
2011-12-06 02:23:28 +00:00
|
|
|
// At this stage with have both a handle and a lock to the physical drive...
|
|
|
|
|
2011-12-11 02:19:38 +00:00
|
|
|
// ... but we can't write sectors that are part of a volume, even if we have
|
|
|
|
// access to physical, unless we have a lock (which doesn't have to be write)
|
|
|
|
// Also, having a volume handle allows us to unmount the volume
|
|
|
|
hLogicalVolume = GetDriveHandle(num, drive_name, FALSE, TRUE);
|
|
|
|
if (hLogicalVolume == INVALID_HANDLE_VALUE) {
|
|
|
|
uprintf("Could not lock volume\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
UnmountDrive(hLogicalVolume);
|
|
|
|
|
2011-12-13 23:29:09 +00:00
|
|
|
AnalyzeMBR(hPhysicalDrive);
|
|
|
|
AnalyzePBR(hLogicalVolume);
|
|
|
|
|
2011-12-06 02:23:28 +00:00
|
|
|
if (IsChecked(IDC_BADBLOCKS)) {
|
2011-12-11 02:19:38 +00:00
|
|
|
do {
|
2011-12-30 21:23:13 +00:00
|
|
|
// create a log file for bad blocks report. Since %USERPROFILE% may
|
|
|
|
// have localised characters, we use the UTF-8 API.
|
|
|
|
userdir = getenvU("USERPROFILE");
|
|
|
|
safe_strcpy(logfile, MAX_PATH, userdir);
|
|
|
|
safe_free(userdir);
|
|
|
|
GetLocalTime(<);
|
|
|
|
safe_sprintf(&logfile[strlen(logfile)], sizeof(logfile)-strlen(logfile)-1,
|
|
|
|
"\\rufus_%04d%02d%02d_%02d%02d%02d.log",
|
|
|
|
lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond);
|
|
|
|
log_fd = fopenU(logfile, "w+");
|
|
|
|
if (log_fd == NULL) {
|
|
|
|
uprintf("Could not create log file for bad blocks check\n");
|
|
|
|
} else {
|
|
|
|
fprintf(log_fd, "Rufus bad blocks check started on: %04d.%02d.%02d %02d:%02d:%02d\n",
|
|
|
|
lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond);
|
|
|
|
fflush(log_fd);
|
|
|
|
}
|
|
|
|
|
2011-12-11 02:19:38 +00:00
|
|
|
if (!BadBlocks(hPhysicalDrive, SelectedDrive.DiskSize,
|
2012-01-08 23:41:20 +00:00
|
|
|
SelectedDrive.Geometry.BytesPerSector, ComboBox_GetCurSel(hNBPasses)+1, &report, log_fd)) {
|
2012-03-03 22:59:58 +00:00
|
|
|
uprintf("Bad blocks: Check failed.\n");
|
2011-12-11 02:19:38 +00:00
|
|
|
if (!FormatStatus)
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|
|
|
|
|
APPERR(ERROR_BADBLOCKS_FAILURE);
|
2011-12-13 23:29:09 +00:00
|
|
|
ClearMBR(hPhysicalDrive);
|
2012-03-03 22:59:58 +00:00
|
|
|
fclose(log_fd);
|
|
|
|
_unlink(logfile);
|
2011-12-09 01:39:13 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2012-03-03 22:59:58 +00:00
|
|
|
uprintf("Bad Blocks: Check completed, %u bad block%s found. (%d/%d/%d errors)\n",
|
2011-12-11 02:19:38 +00:00
|
|
|
report.bb_count, (report.bb_count==1)?"":"s",
|
|
|
|
report.num_read_errors, report.num_write_errors, report.num_corruption_errors);
|
|
|
|
r = IDOK;
|
|
|
|
if (report.bb_count) {
|
2011-12-30 21:23:13 +00:00
|
|
|
safe_sprintf(bb_msg, sizeof(bb_msg), "Check completed: %u bad block%s found.\n"
|
|
|
|
" %d read errors\n %d write errors\n %d corruption errors\n",
|
2011-12-11 02:19:38 +00:00
|
|
|
report.bb_count, (report.bb_count==1)?"":"s",
|
|
|
|
report.num_read_errors, report.num_write_errors,
|
|
|
|
report.num_corruption_errors);
|
2011-12-30 21:23:13 +00:00
|
|
|
fprintf(log_fd, "%s", bb_msg);
|
2012-03-03 22:59:58 +00:00
|
|
|
GetLocalTime(<);
|
|
|
|
fprintf(log_fd, "Rufus bad blocks check ended on: %04d.%02d.%02d %02d:%02d:%02d\n",
|
|
|
|
lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond);
|
2011-12-30 21:23:13 +00:00
|
|
|
fclose(log_fd);
|
|
|
|
safe_sprintf(&bb_msg[strlen(bb_msg)], sizeof(bb_msg)-strlen(bb_msg)-1,
|
|
|
|
"\nA more detailed report can be found in:\n%s\n", logfile);
|
|
|
|
r = MessageBoxU(hMainDialog, bb_msg, "Bad blocks found", MB_ABORTRETRYIGNORE|MB_ICONWARNING);
|
|
|
|
} else {
|
|
|
|
// We didn't get any errors => delete the log file
|
|
|
|
fclose(log_fd);
|
|
|
|
_unlink(logfile);
|
2011-12-11 02:19:38 +00:00
|
|
|
}
|
|
|
|
} while (r == IDRETRY);
|
|
|
|
if (r == IDABORT) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
|
|
|
|
goto out;
|
2011-12-08 00:22:13 +00:00
|
|
|
}
|
2011-12-06 02:23:28 +00:00
|
|
|
}
|
2011-12-11 02:19:38 +00:00
|
|
|
// Close the (unmounted) volume before formatting, but keep the lock
|
|
|
|
safe_closehandle(hLogicalVolume);
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2011-12-06 18:11:38 +00:00
|
|
|
// Especially after destructive badblocks test, you must zero the MBR completely
|
|
|
|
// before repartitioning. Else, all kind of bad things happen
|
|
|
|
if (!ClearMBR(hPhysicalDrive)) {
|
|
|
|
uprintf("unable to zero MBR\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2011-12-09 01:39:13 +00:00
|
|
|
UpdateProgress(OP_ZERO_MBR, -1.0f);
|
2011-12-06 18:11:38 +00:00
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
if (!CreatePartition(hPhysicalDrive)) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
|
|
|
|
goto out;
|
|
|
|
}
|
2011-12-09 01:39:13 +00:00
|
|
|
UpdateProgress(OP_PARTITION, -1.0f);
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2011-12-11 02:19:38 +00:00
|
|
|
// Add a small delay after partitioning to be safe
|
2012-02-05 19:54:48 +00:00
|
|
|
Sleep(200);
|
2011-12-01 17:20:52 +00:00
|
|
|
|
|
|
|
if (!FormatDrive(drive_name[0])) {
|
|
|
|
// Error will be set by FormatDrive() in FormatStatus
|
2011-12-06 23:35:55 +00:00
|
|
|
uprintf("Format error: %s\n", StrError(FormatStatus));
|
2011-12-01 17:20:52 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-02-03 18:19:50 +00:00
|
|
|
PrintStatus(0, TRUE, "Writing master boot record...");
|
2011-12-02 00:11:53 +00:00
|
|
|
if (!WriteMBR(hPhysicalDrive)) {
|
2011-12-01 17:20:52 +00:00
|
|
|
// Errorcode has already been set
|
|
|
|
goto out;
|
|
|
|
}
|
2011-12-09 01:39:13 +00:00
|
|
|
UpdateProgress(OP_FIX_MBR, -1.0f);
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2012-03-03 23:12:48 +00:00
|
|
|
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
|
|
|
|
dt = (int)ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType));
|
2011-12-02 00:11:53 +00:00
|
|
|
if (IsChecked(IDC_DOS)) {
|
2012-03-03 23:12:48 +00:00
|
|
|
if ((dt == DT_WINME) || (dt == DT_FREEDOS) || ((dt == DT_ISO) && (fs == FS_NTFS))) {
|
2012-01-12 02:52:40 +00:00
|
|
|
// We still have a lock, which we need to modify the volume boot record
|
|
|
|
// => no need to reacquire the lock...
|
|
|
|
hLogicalVolume = GetDriveHandle(num, drive_name, TRUE, FALSE);
|
|
|
|
if (hLogicalVolume == INVALID_HANDLE_VALUE) {
|
|
|
|
uprintf("Could not re-mount volume for partition boot record access\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
2012-02-24 18:51:33 +00:00
|
|
|
// NB: if you unmount the logical volume here, XP will report error:
|
|
|
|
// [0x00000456] The media in the drive may have changed
|
2012-02-03 18:19:50 +00:00
|
|
|
PrintStatus(0, TRUE, "Writing partition boot record...");
|
2012-02-14 01:23:42 +00:00
|
|
|
if (!WritePBR(hLogicalVolume)) {
|
|
|
|
if (!FormatStatus)
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
2012-01-12 02:52:40 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2012-02-15 00:52:40 +00:00
|
|
|
// We must close and unlock the volume to write files to it
|
|
|
|
safe_unlockclose(hLogicalVolume);
|
2012-03-03 23:12:48 +00:00
|
|
|
} else if ((dt == DT_ISO) && ((fs == FS_FAT16) || (fs == FS_FAT32))) {
|
2012-02-14 01:23:42 +00:00
|
|
|
PrintStatus(0, TRUE, "Installing Syslinux...");
|
2012-01-12 11:04:03 +00:00
|
|
|
if (!InstallSyslinux(num, drive_name)) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE;
|
2012-01-12 02:52:40 +00:00
|
|
|
}
|
2011-12-01 17:20:52 +00:00
|
|
|
}
|
2012-02-21 19:46:28 +00:00
|
|
|
} else {
|
|
|
|
if (IsChecked(IDC_SET_ICON))
|
|
|
|
SetAutorun(drive_name);
|
2011-12-01 17:20:52 +00:00
|
|
|
}
|
|
|
|
|
2012-02-14 01:23:42 +00:00
|
|
|
// We issue a complete remount of the filesystem at on account of:
|
2012-02-05 19:54:48 +00:00
|
|
|
// - Ensuring the file explorer properly detects that the volume was updated
|
|
|
|
// - Ensuring that an NTFS system will be reparsed so that it becomes bootable
|
2012-02-21 00:08:31 +00:00
|
|
|
if (!RemountVolume(drive_name[0]))
|
|
|
|
goto out;
|
2012-02-14 01:23:42 +00:00
|
|
|
|
|
|
|
if (IsChecked(IDC_DOS)) {
|
|
|
|
UpdateProgress(OP_DOS, -1.0f);
|
2012-03-03 23:12:48 +00:00
|
|
|
if ((dt == DT_WINME) || (dt == DT_FREEDOS)) {
|
2012-02-14 01:23:42 +00:00
|
|
|
PrintStatus(0, TRUE, "Copying DOS files...");
|
|
|
|
if (!ExtractDOS(drive_name)) {
|
|
|
|
if (!FormatStatus)
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY;
|
|
|
|
goto out;
|
|
|
|
}
|
2012-03-03 23:12:48 +00:00
|
|
|
} else if (dt == DT_ISO) {
|
2012-02-14 01:23:42 +00:00
|
|
|
if (iso_path != NULL) {
|
|
|
|
PrintStatus(0, TRUE, "Copying ISO files...");
|
|
|
|
drive_name[2] = 0;
|
2012-03-01 19:19:12 +00:00
|
|
|
if (!ExtractISO(iso_path, drive_name, FALSE)) {
|
|
|
|
if (!FormatStatus)
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY;
|
2012-02-14 01:23:42 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2012-03-16 18:30:44 +00:00
|
|
|
if (IS_WINPE(iso_report.winpe)) {
|
|
|
|
// Apply WinPe fixup
|
|
|
|
SetupWinPE(drive_name[0]);
|
|
|
|
}
|
2012-02-05 19:54:48 +00:00
|
|
|
}
|
2012-02-21 19:46:28 +00:00
|
|
|
if (IsChecked(IDC_SET_ICON))
|
|
|
|
SetAutorun(drive_name);
|
2012-02-24 18:51:33 +00:00
|
|
|
UpdateProgress(OP_DOS, -1.0f);
|
2012-02-21 00:08:31 +00:00
|
|
|
// Issue another complete remount before we exit, to ensure we're clean
|
|
|
|
RemountVolume(drive_name[0]);
|
2012-03-09 01:38:52 +00:00
|
|
|
// NTFS fixup (WinPE/AIK images don't seem to boot without an extra checkdisk)
|
2012-03-11 01:55:25 +00:00
|
|
|
if ((dt == DT_ISO) && (fs == FS_NTFS))
|
2012-03-09 01:38:52 +00:00
|
|
|
CheckDisk(drive_name[0]);
|
2012-02-05 19:54:48 +00:00
|
|
|
}
|
2012-02-03 18:19:50 +00:00
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
out:
|
2012-03-11 01:55:25 +00:00
|
|
|
SendMessage(hISOProgressDlg, UM_ISO_EXIT, 0, 0);
|
2011-12-01 17:20:52 +00:00
|
|
|
safe_unlockclose(hLogicalVolume);
|
|
|
|
safe_unlockclose(hPhysicalDrive);
|
|
|
|
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
|
2012-02-07 02:05:58 +00:00
|
|
|
ExitThread(0);
|
2011-12-01 17:20:52 +00:00
|
|
|
}
|