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
|
2013-02-01 22:59:46 +00:00
|
|
|
* Copyright © 2007-2009 Tom Thornhill/Ridgecrop
|
[net] add Windows retail ISO downloads
* This is accomplished through Fido (https://github.com/pbatard/Fido), a *SIGNED*
PowerShell script, that is downloaded from GitHub and that resides in memory for
the duration of a session.
* The reason we use a downloaded PS script, rather than an embedded on, is because:
- Microsoft have regularly been changing the deal with regards to how retail ISOs
can be downloaded, and not for the better, so we can't simply embed a static
means of downloading ISOs and expect that to work forever.
- By using an external script, we can immediately respond to whatever new means of
*ANNOYING* their legitimate users Microsoft will come up with next, as well as
make sure that, the minute a new retail version of Windows becomes available, it
also becomes available for download in Rufus.
* Note that if you are concerned about downloading a remote PS script that is being
run at the same level as an elevated application, you should understand that:
- Only scripts downloaded from GitHub, from an account that is protected with 2FA,
are allowed to run (i.e. someone would first have to steal a *physical* 2FA key
to be in a position to upload a malicious script).
- On top of this, only scripts that are signed with a separate private key (RSA +
AES-256), that is itself also protected with a strong unique password which only
a single person knows (and must manually enter each time they want to make a new
version of the script available for download), are allowed to run.
The above means that there's about as much chance for someone to manage to upload
a malicious script on the GitHub servers, that Rufus would allow to run, as there
is for someone to upload a malicious version of Rufus itself.
Still, if you are paranoid and have concerns that, even as you can validate from
its source that Rufus does not attempt to execute any remote script unless a user
actively selected and clicked the DOWNLOAD button, you can also completely disable
the remote script download feature, if you just set the update check to disabled
(which, by the way, Rufus *EXPLICITLY* asks you to choose whether you want to
enable or not, the very first time you run the application).
* Also remove _unlinkU() which duplicates what DeleteFileU() already does.
2019-03-02 23:28:56 +00:00
|
|
|
* Copyright © 2011-2019 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>
|
2012-05-16 11:18:48 +00:00
|
|
|
#include <locale.h>
|
2018-06-30 21:45:15 +00:00
|
|
|
#include <assert.h>
|
2011-12-01 17:20:52 +00:00
|
|
|
|
|
|
|
#include "rufus.h"
|
2016-02-20 22:52:32 +00:00
|
|
|
#include "missing.h"
|
2011-12-01 17:20:52 +00:00
|
|
|
#include "resource.h"
|
2016-02-20 22:52:32 +00:00
|
|
|
#include "msapi_utf8.h"
|
|
|
|
#include "localization.h"
|
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
#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"
|
2014-01-05 01:39:41 +00:00
|
|
|
#include "drive.h"
|
2011-12-01 17:20:52 +00:00
|
|
|
#include "format.h"
|
2011-12-06 02:23:28 +00:00
|
|
|
#include "badblocks.h"
|
2014-12-29 20:34:41 +00:00
|
|
|
#include "bled/bled.h"
|
2015-02-16 22:29:23 +00:00
|
|
|
#include "../res/grub/grub_version.h"
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2011-12-01 17:54:35 +00:00
|
|
|
/*
|
|
|
|
* Globals
|
|
|
|
*/
|
2018-09-13 10:49:51 +00:00
|
|
|
DWORD FormatStatus = 0;
|
|
|
|
badblocks_report report = { 0 };
|
|
|
|
static uint64_t LastRefresh = 0;
|
2011-12-09 01:39:13 +00:00
|
|
|
static float format_percent = 0.0f;
|
|
|
|
static int task_number = 0;
|
2013-07-08 23:14:29 +00:00
|
|
|
extern const int nb_steps[FS_MAX];
|
2013-10-31 22:59:53 +00:00
|
|
|
extern uint32_t dur_mins, dur_secs;
|
2019-01-08 18:30:07 +00:00
|
|
|
static int fs_index = 0, wintogo_index = -1, wininst_index = 0;
|
2018-07-06 11:35:22 +00:00
|
|
|
extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing, write_as_image;
|
2014-12-30 19:46:13 +00:00
|
|
|
uint8_t *grub2_buf = NULL;
|
|
|
|
long grub2_len;
|
2013-09-22 02:28:56 +00:00
|
|
|
static BOOL WritePBR(HANDLE hLogicalDrive);
|
2011-12-01 17:54:35 +00:00
|
|
|
|
2015-10-18 20:31:47 +00:00
|
|
|
/*
|
2013-12-20 02:59:44 +00:00
|
|
|
* Convert the fmifs outputs messages (that use an OEM code page) to UTF-8
|
|
|
|
*/
|
|
|
|
static void OutputUTF8Message(const char* src)
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
wchar_t* wdst = NULL;
|
|
|
|
|
|
|
|
if (src == NULL)
|
|
|
|
goto out;
|
|
|
|
len = (int)safe_strlen(src);
|
|
|
|
while ((len > 0) && ((src[len-1] == 0x0A) || (src[len-1] == 0x0D) || (src[len-1] == ' ')))
|
|
|
|
len--;
|
|
|
|
if (len == 0)
|
|
|
|
goto out;
|
|
|
|
|
2014-01-21 10:45:49 +00:00
|
|
|
len = MultiByteToWideChar(CP_OEMCP, 0, src, len, NULL, 0);
|
|
|
|
if (len == 0)
|
|
|
|
goto out;
|
|
|
|
wdst = (wchar_t*)calloc(len+1, sizeof(wchar_t));
|
|
|
|
if ((wdst == NULL) || (MultiByteToWideChar(CP_OEMCP, 0, src, len, wdst, len+1) == 0))
|
|
|
|
goto out;
|
2019-01-03 12:29:28 +00:00
|
|
|
uprintf("%S", wdst);
|
2013-12-20 02:59:44 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
safe_free(wdst);
|
|
|
|
}
|
|
|
|
|
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;
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfo(0, MSG_217, 1.0f * (*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
|
2014-10-31 19:03:51 +00:00
|
|
|
if (task_number < nb_steps[fs_index] - 1) {
|
2015-03-23 22:18:29 +00:00
|
|
|
if (task_number == 0)
|
|
|
|
uprintf("Creating file system...");
|
|
|
|
PrintInfo(0, MSG_218, ++task_number, nb_steps[fs_index]);
|
2014-10-31 19:03:51 +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:
|
2015-03-23 22:18:29 +00:00
|
|
|
PrintInfo(0, MSG_218, 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) {
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("Error while formatting");
|
2011-12-01 17:20:52 +00:00
|
|
|
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
|
2012-05-30 23:49:28 +00:00
|
|
|
// uprintf("Done with that sort of thing: Action=%d pData=%0p\n", Action, pData);
|
2011-12-13 02:10:27 +00:00
|
|
|
// /!\ 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:
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("Incompatible File System");
|
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:
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("Access denied");
|
2011-12-01 17:20:52 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
|
|
|
|
break;
|
|
|
|
case FCC_MEDIA_WRITE_PROTECTED:
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("Media is write protected");
|
2011-12-01 17:20:52 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_PROTECT;
|
|
|
|
break;
|
|
|
|
case FCC_VOLUME_IN_USE:
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("Volume is in use");
|
2011-12-01 17:20:52 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_DEVICE_IN_USE;
|
|
|
|
break;
|
2014-03-29 00:17:41 +00:00
|
|
|
case FCC_DEVICE_NOT_READY:
|
|
|
|
uprintf("The device is not ready");
|
2014-05-19 22:25:00 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_READY;
|
2014-04-02 21:47:35 +00:00
|
|
|
break;
|
2011-12-01 17:20:52 +00:00
|
|
|
case FCC_CANT_QUICK_FORMAT:
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("Cannot quick format this volume");
|
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:
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("Bad label");
|
2011-12-01 17:20:52 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_LABEL_TOO_LONG;
|
|
|
|
break;
|
|
|
|
case FCC_OUTPUT:
|
2013-12-20 02:59:44 +00:00
|
|
|
OutputUTF8Message(((PTEXTOUTPUT)pData)->Output);
|
2011-12-01 17:20:52 +00:00
|
|
|
break;
|
|
|
|
case FCC_CLUSTER_SIZE_TOO_BIG:
|
|
|
|
case FCC_CLUSTER_SIZE_TOO_SMALL:
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("Unsupported cluster size");
|
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:
|
2014-04-02 21:47:35 +00:00
|
|
|
uprintf("Volume is too %s", (Command == 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);
|
2014-04-02 21:47:35 +00:00
|
|
|
break;
|
2011-12-01 17:20:52 +00:00
|
|
|
case FCC_NO_MEDIA_IN_DRIVE:
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("No media in drive");
|
2011-12-01 17:20:52 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_MEDIA_IN_DRIVE;
|
|
|
|
break;
|
|
|
|
default:
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("FormatExCallback: Received unhandled command 0x02%X - aborting", Command);
|
2011-12-01 17:20:52 +00:00
|
|
|
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;
|
|
|
|
|
2017-05-01 15:40:14 +00:00
|
|
|
switch (Command) {
|
2012-03-09 01:38:52 +00:00
|
|
|
case FCC_PROGRESS:
|
|
|
|
case FCC_CHECKDISK_PROGRESS:
|
|
|
|
percent = (DWORD*)pData;
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfo(0, MSG_219, *percent);
|
2012-03-09 01:38:52 +00:00
|
|
|
break;
|
|
|
|
case FCC_DONE:
|
2017-05-01 15:40:14 +00:00
|
|
|
if (*(BOOLEAN*)pData == FALSE) {
|
|
|
|
uprintf("Error while checking disk");
|
|
|
|
return FALSE;
|
2012-03-09 01:38:52 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case FCC_UNKNOWN1A:
|
|
|
|
case FCC_DONE_WITH_STRUCTURE:
|
|
|
|
// Silence these specific calls
|
|
|
|
break;
|
|
|
|
case FCC_INCOMPATIBLE_FILE_SYSTEM:
|
2017-05-01 15:40:14 +00:00
|
|
|
uprintf("Incompatible File System");
|
|
|
|
return FALSE;
|
2012-03-09 01:38:52 +00:00
|
|
|
case FCC_ACCESS_DENIED:
|
2017-05-01 15:40:14 +00:00
|
|
|
uprintf("Access denied");
|
|
|
|
return FALSE;
|
2012-03-09 01:38:52 +00:00
|
|
|
case FCC_MEDIA_WRITE_PROTECTED:
|
2017-05-01 15:40:14 +00:00
|
|
|
uprintf("Media is write protected");
|
|
|
|
return FALSE;
|
2012-03-09 01:38:52 +00:00
|
|
|
case FCC_VOLUME_IN_USE:
|
2017-05-01 15:40:14 +00:00
|
|
|
uprintf("Volume is in use");
|
|
|
|
return FALSE;
|
2012-03-09 01:38:52 +00:00
|
|
|
case FCC_OUTPUT:
|
2013-12-20 02:59:44 +00:00
|
|
|
OutputUTF8Message(((PTEXTOUTPUT)pData)->Output);
|
2012-03-09 01:38:52 +00:00
|
|
|
break;
|
|
|
|
case FCC_NO_MEDIA_IN_DRIVE:
|
2017-05-01 15:40:14 +00:00
|
|
|
uprintf("No media in drive");
|
|
|
|
return FALSE;
|
2012-12-13 23:50:23 +00:00
|
|
|
case FCC_READ_ONLY_MODE:
|
2017-05-01 15:40:14 +00:00
|
|
|
uprintf("Media has been switched to read-only - Leaving checkdisk");
|
2012-12-13 23:50:23 +00:00
|
|
|
break;
|
2012-03-09 01:38:52 +00:00
|
|
|
default:
|
2017-05-01 15:40:14 +00:00
|
|
|
uprintf("ChkdskExCallback: received unhandled command %X", Command);
|
2012-03-09 01:38:52 +00:00
|
|
|
// Assume the command isn't an error
|
|
|
|
break;
|
|
|
|
}
|
2017-05-01 15:40:14 +00:00
|
|
|
return TRUE;
|
2012-03-09 01:38:52 +00:00
|
|
|
}
|
|
|
|
|
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;
|
2013-10-26 23:05:54 +00:00
|
|
|
WCHAR unauthorized[] = L"*?,;:/\\|+=<>[]\"";
|
2013-09-22 02:54:50 +00:00
|
|
|
WCHAR to_underscore[] = L"\t.";
|
2012-02-15 21:55:41 +00:00
|
|
|
|
|
|
|
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
|
2013-06-20 14:41:22 +00:00
|
|
|
uprintf("FAT label is mostly underscores. Using '%s' label instead.\n", SelectedDrive.proposed_label);
|
2012-02-21 19:46:28 +00:00
|
|
|
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
|
2015-09-02 22:20:00 +00:00
|
|
|
wchar_to_utf8_no_alloc(name, img_report.usb_label, sizeof(img_report.usb_label));
|
2012-02-15 21:55:41 +00:00
|
|
|
}
|
|
|
|
|
2012-11-03 17:40:33 +00:00
|
|
|
/*
|
|
|
|
* 28.2 CALCULATING THE VOLUME SERIAL NUMBER
|
|
|
|
*
|
|
|
|
* For example, say a disk was formatted on 26 Dec 95 at 9:55 PM and 41.94
|
|
|
|
* seconds. DOS takes the date and time just before it writes it to the
|
|
|
|
* disk.
|
2015-10-18 20:31:47 +00:00
|
|
|
*
|
2012-11-03 17:40:33 +00:00
|
|
|
* Low order word is calculated: Volume Serial Number is:
|
|
|
|
* Month & Day 12/26 0c1ah
|
2013-06-20 14:41:22 +00:00
|
|
|
* Sec & Hundredths 41:94 295eh 3578:1d02
|
2012-11-03 17:40:33 +00:00
|
|
|
* -----
|
|
|
|
* 3578h
|
2015-10-18 20:31:47 +00:00
|
|
|
*
|
2012-11-03 17:40:33 +00:00
|
|
|
* High order word is calculated:
|
|
|
|
* Hours & Minutes 21:55 1537h
|
|
|
|
* Year 1995 07cbh
|
|
|
|
* -----
|
|
|
|
* 1d02h
|
|
|
|
*/
|
|
|
|
static DWORD GetVolumeID(void)
|
|
|
|
{
|
|
|
|
SYSTEMTIME s;
|
|
|
|
DWORD d;
|
|
|
|
WORD lo,hi,tmp;
|
|
|
|
|
|
|
|
GetLocalTime(&s);
|
|
|
|
|
|
|
|
lo = s.wDay + (s.wMonth << 8);
|
|
|
|
tmp = (s.wMilliseconds/10) + (s.wSecond << 8);
|
|
|
|
lo += tmp;
|
|
|
|
|
|
|
|
hi = s.wMinute + (s.wHour << 8);
|
|
|
|
hi += s.wYear;
|
|
|
|
|
|
|
|
d = lo + (hi << 16);
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-02-26 13:26:34 +00:00
|
|
|
* Proper computation of FAT size
|
|
|
|
* See: http://www.syslinux.org/archives/2016-February/024850.html
|
|
|
|
* and subsequent replies.
|
2012-11-03 17:40:33 +00:00
|
|
|
*/
|
|
|
|
static DWORD GetFATSizeSectors(DWORD DskSize, DWORD ReservedSecCnt, DWORD SecPerClus, DWORD NumFATs, DWORD BytesPerSect)
|
|
|
|
{
|
|
|
|
ULONGLONG Numerator, Denominator;
|
|
|
|
ULONGLONG FatElementSize = 4;
|
2016-02-26 13:26:34 +00:00
|
|
|
ULONGLONG ReservedClusCnt = 2;
|
2012-11-03 17:40:33 +00:00
|
|
|
ULONGLONG FatSz;
|
|
|
|
|
2016-02-26 13:26:34 +00:00
|
|
|
Numerator = DskSize - ReservedSecCnt + ReservedClusCnt * SecPerClus;
|
|
|
|
Denominator = SecPerClus * BytesPerSect / FatElementSize + NumFATs;
|
|
|
|
FatSz = Numerator / Denominator + 1; // +1 to ensure we are rounded up
|
2012-11-03 17:40:33 +00:00
|
|
|
|
|
|
|
return (DWORD)FatSz;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Large FAT32 volume formatting from fat32format by Tom Thornhill
|
|
|
|
* http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm
|
|
|
|
*/
|
|
|
|
static BOOL FormatFAT32(DWORD DriveIndex)
|
|
|
|
{
|
|
|
|
BOOL r = FALSE;
|
2014-12-29 20:34:41 +00:00
|
|
|
DWORD i;
|
2012-11-03 17:40:33 +00:00
|
|
|
HANDLE hLogicalVolume;
|
|
|
|
DWORD cbRet;
|
|
|
|
DISK_GEOMETRY dgDrive;
|
2014-03-29 00:17:41 +00:00
|
|
|
BYTE geometry_ex[256]; // DISK_GEOMETRY_EX is variable size
|
|
|
|
PDISK_GEOMETRY_EX xdgDrive = (PDISK_GEOMETRY_EX)(void*)geometry_ex;
|
2012-11-03 17:40:33 +00:00
|
|
|
PARTITION_INFORMATION piDrive;
|
2013-11-23 22:39:54 +00:00
|
|
|
PARTITION_INFORMATION_EX xpiDrive;
|
2012-11-03 17:40:33 +00:00
|
|
|
// Recommended values
|
|
|
|
DWORD ReservedSectCount = 32;
|
|
|
|
DWORD NumFATs = 2;
|
|
|
|
DWORD BackupBootSect = 6;
|
|
|
|
DWORD VolumeId = 0; // calculated before format
|
2013-04-07 23:10:58 +00:00
|
|
|
char* VolumeName = NULL;
|
|
|
|
WCHAR wLabel[64], *wVolumeName = NULL;
|
2012-11-03 17:40:33 +00:00
|
|
|
DWORD BurstSize = 128; // Zero in blocks of 64K typically
|
|
|
|
|
|
|
|
// Calculated later
|
2015-10-18 20:31:47 +00:00
|
|
|
DWORD FatSize = 0;
|
2012-11-03 17:40:33 +00:00
|
|
|
DWORD BytesPerSect = 0;
|
|
|
|
DWORD ClusterSize = 0;
|
|
|
|
DWORD SectorsPerCluster = 0;
|
|
|
|
DWORD TotalSectors = 0;
|
|
|
|
DWORD SystemAreaSize = 0;
|
|
|
|
DWORD UserAreaSize = 0;
|
|
|
|
ULONGLONG qTotalSectors = 0;
|
|
|
|
|
|
|
|
// Structures to be written to the disk
|
|
|
|
FAT_BOOTSECTOR32 *pFAT32BootSect = NULL;
|
|
|
|
FAT_FSINFO *pFAT32FsInfo = NULL;
|
|
|
|
DWORD *pFirstSectOfFat = NULL;
|
|
|
|
BYTE* pZeroSect = NULL;
|
|
|
|
char VolId[12] = "NO NAME ";
|
|
|
|
|
|
|
|
// Debug temp vars
|
|
|
|
ULONGLONG FatNeeded, ClusterCount;
|
|
|
|
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_222, "Large FAT32");
|
2014-12-29 20:34:41 +00:00
|
|
|
LastRefresh = 0;
|
2012-11-03 17:40:33 +00:00
|
|
|
VolumeId = GetVolumeID();
|
|
|
|
|
2013-06-25 17:39:07 +00:00
|
|
|
// Open the drive and lock it
|
2017-02-16 14:13:30 +00:00
|
|
|
hLogicalVolume = GetLogicalHandle(DriveIndex, TRUE, TRUE, FALSE);
|
2012-11-03 17:40:33 +00:00
|
|
|
if (IS_ERROR(FormatStatus)) goto out;
|
2013-06-25 01:55:25 +00:00
|
|
|
if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL))
|
|
|
|
die("Invalid logical volume handle\n", ERROR_INVALID_HANDLE);
|
2012-11-03 17:40:33 +00:00
|
|
|
|
2013-06-25 17:39:07 +00:00
|
|
|
// Try to disappear the volume while we're formatting it
|
|
|
|
UnmountVolume(hLogicalVolume);
|
2012-11-03 17:40:33 +00:00
|
|
|
|
|
|
|
// Work out drive params
|
|
|
|
if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dgDrive,
|
|
|
|
sizeof(dgDrive), &cbRet, NULL)) {
|
2014-03-29 00:17:41 +00:00
|
|
|
if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, xdgDrive,
|
|
|
|
sizeof(geometry_ex), &cbRet, NULL)) {
|
|
|
|
uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY error: %s\n", WindowsErrorString());
|
|
|
|
die("Failed to get device geometry (both regular and _ex)\n", ERROR_NOT_SUPPORTED);
|
|
|
|
}
|
|
|
|
memcpy(&dgDrive, &xdgDrive->Geometry, sizeof(dgDrive));
|
2012-11-03 17:40:33 +00:00
|
|
|
}
|
2014-08-03 18:34:01 +00:00
|
|
|
if (dgDrive.BytesPerSector < 512)
|
|
|
|
dgDrive.BytesPerSector = 512;
|
2012-11-03 17:40:33 +00:00
|
|
|
if (IS_ERROR(FormatStatus)) goto out;
|
|
|
|
if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &piDrive,
|
|
|
|
sizeof(piDrive), &cbRet, NULL)) {
|
2013-11-23 22:39:54 +00:00
|
|
|
if (!DeviceIoControl (hLogicalVolume, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &xpiDrive,
|
|
|
|
sizeof(xpiDrive), &cbRet, NULL)) {
|
2014-03-29 00:17:41 +00:00
|
|
|
uprintf("IOCTL_DISK_GET_PARTITION_INFO error: %s\n", WindowsErrorString());
|
|
|
|
die("Failed to get partition info (both regular and _ex)\n", ERROR_NOT_SUPPORTED);
|
2013-11-23 22:39:54 +00:00
|
|
|
}
|
|
|
|
|
2014-03-29 00:17:41 +00:00
|
|
|
memset(&piDrive, 0, sizeof(piDrive));
|
2013-11-23 22:39:54 +00:00
|
|
|
piDrive.StartingOffset.QuadPart = xpiDrive.StartingOffset.QuadPart;
|
|
|
|
piDrive.PartitionLength.QuadPart = xpiDrive.PartitionLength.QuadPart;
|
|
|
|
piDrive.HiddenSectors = (DWORD) (xpiDrive.StartingOffset.QuadPart / dgDrive.BytesPerSector);
|
2012-11-03 17:40:33 +00:00
|
|
|
}
|
2014-03-29 00:17:41 +00:00
|
|
|
if (IS_ERROR(FormatStatus)) goto out;
|
2012-11-03 17:40:33 +00:00
|
|
|
|
|
|
|
BytesPerSect = dgDrive.BytesPerSector;
|
|
|
|
|
|
|
|
// Checks on Disk Size
|
|
|
|
qTotalSectors = piDrive.PartitionLength.QuadPart/dgDrive.BytesPerSector;
|
|
|
|
// Low end limit - 65536 sectors
|
|
|
|
if (qTotalSectors < 65536) {
|
|
|
|
// Most FAT32 implementations would probably mount this volume just fine,
|
|
|
|
// but the spec says that we shouldn't do this, so we won't
|
|
|
|
die("This drive is too small for FAT32 - there must be at least 64K clusters\n", APPERR(ERROR_INVALID_CLUSTER_SIZE));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (qTotalSectors >= 0xffffffff) {
|
|
|
|
// This is a more fundamental limitation on FAT32 - the total sector count in the root dir
|
2014-05-09 21:05:25 +00:00
|
|
|
// is 32bit. With a bit of creativity, FAT32 could be extended to handle at least 2^28 clusters
|
2012-11-03 17:40:33 +00:00
|
|
|
// There would need to be an extra field in the FSInfo sector, and the old sector count could
|
|
|
|
// be set to 0xffffffff. This is non standard though, the Windows FAT driver FASTFAT.SYS won't
|
|
|
|
// understand this. Perhaps a future version of FAT32 and FASTFAT will handle this.
|
2014-03-29 00:17:41 +00:00
|
|
|
die("This drive is too big for FAT32 - max 2TB supported\n", APPERR(ERROR_INVALID_VOLUME_SIZE));
|
2012-11-03 17:40:33 +00:00
|
|
|
}
|
|
|
|
|
2014-05-09 21:05:25 +00:00
|
|
|
// coverity[tainted_data]
|
2012-11-03 17:40:33 +00:00
|
|
|
pFAT32BootSect = (FAT_BOOTSECTOR32*) calloc(BytesPerSect, 1);
|
|
|
|
pFAT32FsInfo = (FAT_FSINFO*) calloc(BytesPerSect, 1);
|
|
|
|
pFirstSectOfFat = (DWORD*) calloc(BytesPerSect, 1);
|
|
|
|
if (!pFAT32BootSect || !pFAT32FsInfo || !pFirstSectOfFat) {
|
|
|
|
die("Failed to allocate memory\n", ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
// fill out the boot sector and fs info
|
|
|
|
pFAT32BootSect->sJmpBoot[0]=0xEB;
|
2013-11-23 22:39:54 +00:00
|
|
|
pFAT32BootSect->sJmpBoot[1]=0x58; // jmp.s $+0x5a is 0xeb 0x58, not 0xeb 0x5a. Thanks Marco!
|
2012-11-03 17:40:33 +00:00
|
|
|
pFAT32BootSect->sJmpBoot[2]=0x90;
|
2018-09-03 12:41:29 +00:00
|
|
|
memcpy(pFAT32BootSect->sOEMName, "MSWIN4.1", 8);
|
2012-11-03 17:40:33 +00:00
|
|
|
pFAT32BootSect->wBytsPerSec = (WORD) BytesPerSect;
|
|
|
|
|
2012-11-04 00:29:24 +00:00
|
|
|
ClusterSize = (DWORD)ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize));
|
2012-11-03 17:40:33 +00:00
|
|
|
SectorsPerCluster = ClusterSize / BytesPerSect;
|
|
|
|
|
|
|
|
pFAT32BootSect->bSecPerClus = (BYTE) SectorsPerCluster ;
|
|
|
|
pFAT32BootSect->wRsvdSecCnt = (WORD) ReservedSectCount;
|
|
|
|
pFAT32BootSect->bNumFATs = (BYTE) NumFATs;
|
|
|
|
pFAT32BootSect->wRootEntCnt = 0;
|
|
|
|
pFAT32BootSect->wTotSec16 = 0;
|
|
|
|
pFAT32BootSect->bMedia = 0xF8;
|
|
|
|
pFAT32BootSect->wFATSz16 = 0;
|
|
|
|
pFAT32BootSect->wSecPerTrk = (WORD) dgDrive.SectorsPerTrack;
|
|
|
|
pFAT32BootSect->wNumHeads = (WORD) dgDrive.TracksPerCylinder;
|
|
|
|
pFAT32BootSect->dHiddSec = (DWORD) piDrive.HiddenSectors;
|
|
|
|
TotalSectors = (DWORD) (piDrive.PartitionLength.QuadPart/dgDrive.BytesPerSector);
|
|
|
|
pFAT32BootSect->dTotSec32 = TotalSectors;
|
|
|
|
|
2015-10-18 20:31:47 +00:00
|
|
|
FatSize = GetFATSizeSectors(pFAT32BootSect->dTotSec32, pFAT32BootSect->wRsvdSecCnt,
|
2012-11-03 17:40:33 +00:00
|
|
|
pFAT32BootSect->bSecPerClus, pFAT32BootSect->bNumFATs, BytesPerSect);
|
|
|
|
|
|
|
|
pFAT32BootSect->dFATSz32 = FatSize;
|
|
|
|
pFAT32BootSect->wExtFlags = 0;
|
|
|
|
pFAT32BootSect->wFSVer = 0;
|
|
|
|
pFAT32BootSect->dRootClus = 2;
|
|
|
|
pFAT32BootSect->wFSInfo = 1;
|
|
|
|
pFAT32BootSect->wBkBootSec = (WORD) BackupBootSect;
|
|
|
|
pFAT32BootSect->bDrvNum = 0x80;
|
|
|
|
pFAT32BootSect->Reserved1 = 0;
|
|
|
|
pFAT32BootSect->bBootSig = 0x29;
|
|
|
|
|
|
|
|
pFAT32BootSect->dBS_VolID = VolumeId;
|
|
|
|
memcpy(pFAT32BootSect->sVolLab, VolId, 11);
|
|
|
|
memcpy(pFAT32BootSect->sBS_FilSysType, "FAT32 ", 8);
|
|
|
|
((BYTE*)pFAT32BootSect)[510] = 0x55;
|
|
|
|
((BYTE*)pFAT32BootSect)[511] = 0xaa;
|
|
|
|
|
2015-10-18 20:31:47 +00:00
|
|
|
// FATGEN103.DOC says "NOTE: Many FAT documents mistakenly say that this 0xAA55 signature occupies the "last 2 bytes of
|
|
|
|
// the boot sector". This statement is correct if - and only if - BPB_BytsPerSec is 512. If BPB_BytsPerSec is greater than
|
|
|
|
// 512, the offsets of these signature bytes do not change (although it is perfectly OK for the last two bytes at the end
|
|
|
|
// of the boot sector to also contain this signature)."
|
|
|
|
//
|
2012-11-03 17:40:33 +00:00
|
|
|
// Windows seems to only check the bytes at offsets 510 and 511. Other OSs might check the ones at the end of the sector,
|
|
|
|
// so we'll put them there too.
|
|
|
|
if (BytesPerSect != 512) {
|
|
|
|
((BYTE*)pFAT32BootSect)[BytesPerSect-2] = 0x55;
|
|
|
|
((BYTE*)pFAT32BootSect)[BytesPerSect-1] = 0xaa;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FSInfo sect
|
|
|
|
pFAT32FsInfo->dLeadSig = 0x41615252;
|
|
|
|
pFAT32FsInfo->dStrucSig = 0x61417272;
|
|
|
|
pFAT32FsInfo->dFree_Count = (DWORD) -1;
|
|
|
|
pFAT32FsInfo->dNxt_Free = (DWORD) -1;
|
|
|
|
pFAT32FsInfo->dTrailSig = 0xaa550000;
|
|
|
|
|
|
|
|
// First FAT Sector
|
|
|
|
pFirstSectOfFat[0] = 0x0ffffff8; // Reserved cluster 1 media id in low byte
|
|
|
|
pFirstSectOfFat[1] = 0x0fffffff; // Reserved cluster 2 EOC
|
|
|
|
pFirstSectOfFat[2] = 0x0fffffff; // end of cluster chain for root dir
|
|
|
|
|
|
|
|
// Write boot sector, fats
|
|
|
|
// Sector 0 Boot Sector
|
2015-10-18 20:31:47 +00:00
|
|
|
// Sector 1 FSInfo
|
2012-11-03 17:40:33 +00:00
|
|
|
// Sector 2 More boot code - we write zeros here
|
|
|
|
// Sector 3 unused
|
|
|
|
// Sector 4 unused
|
|
|
|
// Sector 5 unused
|
|
|
|
// Sector 6 Backup boot sector
|
|
|
|
// Sector 7 Backup FSInfo sector
|
|
|
|
// Sector 8 Backup 'more boot code'
|
2013-06-20 14:41:22 +00:00
|
|
|
// zeroed sectors upto ReservedSectCount
|
2012-11-03 17:40:33 +00:00
|
|
|
// FAT1 ReservedSectCount to ReservedSectCount + FatSize
|
|
|
|
// ...
|
|
|
|
// FATn ReservedSectCount to ReservedSectCount + FatSize
|
|
|
|
// RootDir - allocated to cluster2
|
|
|
|
|
|
|
|
UserAreaSize = TotalSectors - ReservedSectCount - (NumFATs*FatSize);
|
|
|
|
ClusterCount = UserAreaSize / SectorsPerCluster;
|
|
|
|
|
2015-10-18 20:31:47 +00:00
|
|
|
// Sanity check for a cluster count of >2^28, since the upper 4 bits of the cluster values in
|
2012-11-03 17:40:33 +00:00
|
|
|
// the FAT are reserved.
|
|
|
|
if (ClusterCount > 0x0FFFFFFF) {
|
|
|
|
die("This drive has more than 2^28 clusters, try to specify a larger cluster size or use the default\n",
|
|
|
|
ERROR_INVALID_CLUSTER_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sanity check - < 64K clusters means that the volume will be misdetected as FAT16
|
|
|
|
if (ClusterCount < 65536) {
|
|
|
|
die("FAT32 must have at least 65536 clusters, try to specify a smaller cluster size or use the default\n",
|
|
|
|
ERROR_INVALID_CLUSTER_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sanity check, make sure the fat is big enough
|
2015-10-18 20:31:47 +00:00
|
|
|
// Convert the cluster count into a Fat sector count, and check the fat size value we calculated
|
2012-11-03 17:40:33 +00:00
|
|
|
// earlier is OK.
|
|
|
|
FatNeeded = ClusterCount * 4;
|
|
|
|
FatNeeded += (BytesPerSect-1);
|
|
|
|
FatNeeded /= BytesPerSect;
|
|
|
|
if (FatNeeded > FatSize) {
|
|
|
|
die("This drive is too big for large FAT32 format\n", APPERR(ERROR_INVALID_VOLUME_SIZE));
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:41:22 +00:00
|
|
|
// Now we're committed - print some info first
|
2014-03-01 00:09:40 +00:00
|
|
|
uprintf("Size : %s %u sectors\n", SizeToHumanReadable(piDrive.PartitionLength.QuadPart, TRUE, FALSE), TotalSectors);
|
2012-11-03 17:40:33 +00:00
|
|
|
uprintf("Cluster size %d bytes, %d Bytes Per Sector\n", SectorsPerCluster*BytesPerSect, BytesPerSect);
|
|
|
|
uprintf("Volume ID is %x:%x\n", VolumeId>>16, VolumeId&0xffff);
|
|
|
|
uprintf("%d Reserved Sectors, %d Sectors per FAT, %d FATs\n", ReservedSectCount, FatSize, NumFATs);
|
|
|
|
uprintf("%d Total clusters\n", ClusterCount);
|
|
|
|
|
|
|
|
// Fix up the FSInfo sector
|
|
|
|
pFAT32FsInfo->dFree_Count = (UserAreaSize/SectorsPerCluster) - 1;
|
2013-06-20 14:41:22 +00:00
|
|
|
pFAT32FsInfo->dNxt_Free = 3; // clusters 0-1 reserved, we used cluster 2 for the root dir
|
2012-11-03 17:40:33 +00:00
|
|
|
|
|
|
|
uprintf("%d Free Clusters\n", pFAT32FsInfo->dFree_Count);
|
|
|
|
// Work out the Cluster count
|
|
|
|
|
|
|
|
// First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster
|
|
|
|
SystemAreaSize = ReservedSectCount + (NumFATs*FatSize) + SectorsPerCluster;
|
|
|
|
uprintf("Clearing out %d sectors for reserved sectors, FATs and root cluster...\n", SystemAreaSize);
|
|
|
|
|
|
|
|
// Not the most effective, but easy on RAM
|
|
|
|
pZeroSect = (BYTE*)calloc(BytesPerSect, BurstSize);
|
|
|
|
if (!pZeroSect) {
|
|
|
|
die("Failed to allocate memory\n", ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
format_percent = 0.0f;
|
|
|
|
for (i=0; i<(SystemAreaSize+BurstSize-1); i+=BurstSize) {
|
2017-11-13 14:29:48 +00:00
|
|
|
if (GetTickCount64() > LastRefresh + MAX_REFRESH) {
|
|
|
|
LastRefresh = GetTickCount64();
|
2013-09-22 02:54:50 +00:00
|
|
|
format_percent = (100.0f*i)/(1.0f*(SystemAreaSize+BurstSize));
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfo(0, MSG_217, format_percent);
|
2013-09-22 02:54:50 +00:00
|
|
|
UpdateProgress(OP_FORMAT, format_percent);
|
|
|
|
}
|
2012-11-03 17:40:33 +00:00
|
|
|
if (IS_ERROR(FormatStatus)) goto out; // For cancellation
|
|
|
|
if (write_sectors(hLogicalVolume, BytesPerSect, i, BurstSize, pZeroSect) != (BytesPerSect*BurstSize)) {
|
|
|
|
die("Error clearing reserved sectors\n", ERROR_WRITE_FAULT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-20 14:41:22 +00:00
|
|
|
uprintf ("Initializing reserved sectors and FATs...\n");
|
2012-11-03 17:40:33 +00:00
|
|
|
// Now we should write the boot sector and fsinfo twice, once at 0 and once at the backup boot sect position
|
|
|
|
for (i=0; i<2; i++) {
|
|
|
|
int SectorStart = (i==0) ? 0 : BackupBootSect;
|
|
|
|
write_sectors(hLogicalVolume, BytesPerSect, SectorStart, 1, pFAT32BootSect);
|
|
|
|
write_sectors(hLogicalVolume, BytesPerSect, SectorStart+1, 1, pFAT32FsInfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the first fat sector in the right places
|
|
|
|
for ( i=0; i<NumFATs; i++ ) {
|
|
|
|
int SectorStart = ReservedSectCount + (i * FatSize );
|
|
|
|
uprintf("FAT #%d sector at address: %d\n", i, SectorStart);
|
|
|
|
write_sectors(hLogicalVolume, BytesPerSect, SectorStart, 1, pFirstSectOfFat);
|
|
|
|
}
|
|
|
|
|
2013-09-22 02:28:56 +00:00
|
|
|
// Must do it here, as have issues when trying to write the PBR after a remount
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_229);
|
2013-09-22 02:28:56 +00:00
|
|
|
if (!WritePBR(hLogicalVolume)) {
|
|
|
|
// Non fatal error, but the drive probably won't boot
|
|
|
|
uprintf("Could not write partition boot record - drive may not boot...\n");
|
|
|
|
}
|
|
|
|
|
2012-11-03 17:40:33 +00:00
|
|
|
// Set the FAT32 volume label
|
|
|
|
GetWindowTextW(hLabel, wLabel, ARRAYSIZE(wLabel));
|
|
|
|
ToValidLabel(wLabel, TRUE);
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_221);
|
2012-11-03 17:40:33 +00:00
|
|
|
// Handle must be closed for SetVolumeLabel to work
|
|
|
|
safe_closehandle(hLogicalVolume);
|
2013-06-25 17:39:07 +00:00
|
|
|
VolumeName = GetLogicalName(DriveIndex, TRUE, TRUE);
|
2013-04-07 23:10:58 +00:00
|
|
|
wVolumeName = utf8_to_wchar(VolumeName);
|
|
|
|
if ((wVolumeName == NULL) || (!SetVolumeLabelW(wVolumeName, wLabel))) {
|
2012-11-03 17:40:33 +00:00
|
|
|
uprintf("Could not set label: %s\n", WindowsErrorString());
|
2013-04-07 23:10:58 +00:00
|
|
|
// Non fatal error
|
2012-11-03 17:40:33 +00:00
|
|
|
}
|
2013-04-07 23:10:58 +00:00
|
|
|
|
2012-11-03 17:40:33 +00:00
|
|
|
uprintf("Format completed.\n");
|
|
|
|
r = TRUE;
|
|
|
|
|
|
|
|
out:
|
2013-04-07 23:10:58 +00:00
|
|
|
safe_free(VolumeName);
|
|
|
|
safe_free(wVolumeName);
|
2012-11-03 17:40:33 +00:00
|
|
|
safe_closehandle(hLogicalVolume);
|
|
|
|
safe_free(pFAT32BootSect);
|
|
|
|
safe_free(pFAT32FsInfo);
|
|
|
|
safe_free(pFirstSectOfFat);
|
|
|
|
safe_free(pZeroSect);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
/*
|
|
|
|
* Call on fmifs.dll's FormatEx() to format the drive
|
|
|
|
*/
|
2013-04-07 23:10:58 +00:00
|
|
|
static BOOL FormatDrive(DWORD DriveIndex)
|
2011-12-01 17:20:52 +00:00
|
|
|
{
|
|
|
|
BOOL r = FALSE;
|
|
|
|
PF_DECL(FormatEx);
|
2014-01-31 02:51:28 +00:00
|
|
|
PF_DECL(EnableVolumeCompression);
|
2018-05-29 11:54:45 +00:00
|
|
|
char FSType[64], path[MAX_PATH];
|
2013-07-08 23:14:29 +00:00
|
|
|
char *locale, *VolumeName = NULL;
|
|
|
|
WCHAR* wVolumeName = NULL;
|
2013-10-15 21:58:27 +00:00
|
|
|
WCHAR wFSType[64];
|
2012-02-15 21:55:41 +00:00
|
|
|
WCHAR wLabel[64];
|
2013-07-08 23:14:29 +00:00
|
|
|
ULONG ulClusterSize;
|
2018-05-29 11:54:45 +00:00
|
|
|
size_t i, index;
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2013-10-15 21:58:27 +00:00
|
|
|
GetWindowTextU(hFileSystem, FSType, ARRAYSIZE(FSType));
|
2018-05-29 11:54:45 +00:00
|
|
|
// Skip the RIGHT_TO_LEFT_EMBEDDING mark from LTR languages
|
|
|
|
index = (strncmp(FSType, RIGHT_TO_LEFT_EMBEDDING, sizeof(RIGHT_TO_LEFT_EMBEDDING) - 1) == 0) ? (sizeof(RIGHT_TO_LEFT_EMBEDDING) - 1) : 0;
|
2014-03-01 00:09:40 +00:00
|
|
|
// Might have a (Default) suffix => remove it
|
|
|
|
for (i=strlen(FSType); i>2; i--) {
|
|
|
|
if (FSType[i] == '(') {
|
|
|
|
FSType[i-1] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-10-31 22:59:53 +00:00
|
|
|
if ((fs == FS_UDF) && !((dur_mins == 0) && (dur_secs == 0))) {
|
2018-05-29 11:54:45 +00:00
|
|
|
PrintInfoDebug(0, MSG_220, &FSType[index], dur_mins, dur_secs);
|
2013-10-31 22:59:53 +00:00
|
|
|
} else {
|
2018-05-29 11:54:45 +00:00
|
|
|
PrintInfoDebug(0, MSG_222, &FSType[index]);
|
2013-10-31 22:59:53 +00:00
|
|
|
}
|
2014-01-31 02:51:28 +00:00
|
|
|
VolumeName = GetLogicalName(DriveIndex, TRUE, TRUE);
|
2013-04-07 23:10:58 +00:00
|
|
|
wVolumeName = utf8_to_wchar(VolumeName);
|
|
|
|
if (wVolumeName == NULL) {
|
|
|
|
uprintf("Could not read volume name\n");
|
2014-04-02 21:47:35 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE;
|
2013-04-07 23:10:58 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2014-01-31 02:51:28 +00:00
|
|
|
// Hey, nice consistency here, Microsoft! - FormatEx() fails if wVolumeName has
|
|
|
|
// a trailing backslash, but EnableCompression() fails without...
|
|
|
|
wVolumeName[wcslen(wVolumeName)-1] = 0; // Remove trailing backslash
|
2013-04-07 23:10:58 +00:00
|
|
|
|
2017-04-11 21:15:05 +00:00
|
|
|
// Check if Windows picked the UEFI:NTFS partition
|
|
|
|
// NB: No need to do this for Large FAT32, as this only applies to NTFS
|
2017-08-10 18:43:04 +00:00
|
|
|
static_strcpy(path, VolumeName);
|
|
|
|
static_strcat(path, "EFI\\Rufus\\ntfs_x64.efi");
|
2017-04-11 21:15:05 +00:00
|
|
|
if (PathFileExistsA(path)) {
|
|
|
|
uprintf("Windows selected the UEFI:NTFS partition for formatting - Retry needed", VolumeName);
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_RETRY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2012-05-16 11:18:48 +00:00
|
|
|
// LoadLibrary("fmifs.dll") appears to changes the locale, which can lead to
|
|
|
|
// problems with tolower(). Make sure we restore the locale. For more details,
|
|
|
|
// see http://comments.gmane.org/gmane.comp.gnu.mingw.user/39300
|
|
|
|
locale = setlocale(LC_ALL, NULL);
|
2019-03-19 12:04:29 +00:00
|
|
|
PF_INIT_OR_OUT(FormatEx, fmifs);
|
|
|
|
PF_INIT(EnableVolumeCompression, fmifs);
|
2012-05-16 11:18:48 +00:00
|
|
|
setlocale(LC_ALL, locale);
|
2011-12-01 17:20:52 +00:00
|
|
|
|
|
|
|
GetWindowTextW(hFileSystem, wFSType, ARRAYSIZE(wFSType));
|
2018-05-29 11:54:45 +00:00
|
|
|
// Again, skip the RIGHT_TO_LEFT_EMBEDDING mark if present
|
|
|
|
index = (wFSType[0] == 0x202b) ? 1 : 0;
|
2011-12-01 17:20:52 +00:00
|
|
|
// 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
|
2016-08-31 12:01:39 +00:00
|
|
|
ToValidLabel(wLabel, (fs == FS_FAT16) || (fs == FS_FAT32) || (fs == FS_EXFAT));
|
2013-07-08 23:14:29 +00:00
|
|
|
ulClusterSize = (ULONG)ComboBox_GetItemData(hClusterSize, ComboBox_GetCurSel(hClusterSize));
|
|
|
|
if (ulClusterSize < 0x200) {
|
|
|
|
// 0 is FormatEx's value for default, which we need to use for UDF
|
|
|
|
ulClusterSize = 0;
|
|
|
|
uprintf("Using default cluster size\n");
|
|
|
|
} else {
|
|
|
|
uprintf("Using cluster size: %d bytes\n", ulClusterSize);
|
|
|
|
}
|
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));
|
2014-01-31 02:51:28 +00:00
|
|
|
|
2018-03-22 23:14:20 +00:00
|
|
|
uprintf("%s format was selected\n", IsChecked(IDC_QUICK_FORMAT)?"Quick":"Slow");
|
2018-05-29 11:54:45 +00:00
|
|
|
pfFormatEx(wVolumeName, SelectedDrive.MediaType, &wFSType[index], wLabel,
|
2018-03-22 23:14:20 +00:00
|
|
|
IsChecked(IDC_QUICK_FORMAT), ulClusterSize, FormatExCallback);
|
2014-01-31 02:51:28 +00:00
|
|
|
|
|
|
|
if ((fs == FS_NTFS) && (enable_ntfs_compression) && (pfEnableVolumeCompression != NULL)) {
|
|
|
|
wVolumeName[wcslen(wVolumeName)] = '\\'; // Add trailing backslash back again
|
|
|
|
if (pfEnableVolumeCompression(wVolumeName, FPF_COMPRESSED)) {
|
|
|
|
uprintf("Enabled NTFS compression\n");
|
|
|
|
} else {
|
|
|
|
uprintf("Could not enable NTFS compression: %s\n", WindowsErrorString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
if (!IS_ERROR(FormatStatus)) {
|
|
|
|
uprintf("Format completed.\n");
|
|
|
|
r = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2019-03-19 12:04:29 +00:00
|
|
|
if (!r && !IS_ERROR(FormatStatus))
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|SCODE_CODE(GetLastError());
|
2013-04-07 23:10:58 +00:00
|
|
|
safe_free(VolumeName);
|
|
|
|
safe_free(wVolumeName);
|
2011-12-01 17:20:52 +00:00
|
|
|
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;
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_223);
|
2012-03-09 01:38:52 +00:00
|
|
|
|
2014-05-12 21:44:10 +00:00
|
|
|
PF_INIT_OR_OUT(Chkdsk, Fmifs);
|
2012-03-09 01:38:52 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-12-05 18:56:05 +00:00
|
|
|
static BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSize, BOOL add1MB)
|
2011-12-06 18:11:38 +00:00
|
|
|
{
|
2012-11-03 17:40:33 +00:00
|
|
|
BOOL r = FALSE;
|
2018-06-13 18:23:24 +00:00
|
|
|
uint64_t i, j, last_sector = DiskSize/SectorSize, num_sectors_to_clear;
|
2012-11-03 17:40:33 +00:00
|
|
|
unsigned char* pBuf = (unsigned char*) calloc(SectorSize, 1);
|
2011-12-06 18:11:38 +00:00
|
|
|
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_224);
|
2012-11-03 17:40:33 +00:00
|
|
|
if (pBuf == NULL) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-01-18 01:39:24 +00:00
|
|
|
// http://en.wikipedia.org/wiki/GUID_Partition_Table tells us we should clear 34 sectors at the
|
|
|
|
// beginning and 33 at the end. We bump these values to MAX_SECTORS_TO_CLEAR each end to help
|
|
|
|
// with reluctant access to large drive.
|
2013-09-22 02:28:56 +00:00
|
|
|
|
2016-07-07 17:13:01 +00:00
|
|
|
// We try to clear at least 1MB + the PBR when Large FAT32 is selected (add1MB), but
|
|
|
|
// don't do it otherwise, as it seems unnecessary and may take time for slow drives.
|
|
|
|
// Also, for various reasons (one of which being that Windows seems to have issues
|
|
|
|
// with GPT drives that contain a lot of small partitions) we try not not to clear
|
|
|
|
// sectors further than the lowest partition already residing on the disk.
|
2016-07-09 15:20:58 +00:00
|
|
|
num_sectors_to_clear = min(SelectedDrive.FirstDataSector, (DWORD)((add1MB ? 2048 : 0) + MAX_SECTORS_TO_CLEAR));
|
2016-08-21 12:06:15 +00:00
|
|
|
// Special case for big floppy disks (FirstDataSector = 0)
|
|
|
|
if (num_sectors_to_clear < 4)
|
|
|
|
num_sectors_to_clear = (DWORD)((add1MB ? 2048 : 0) + MAX_SECTORS_TO_CLEAR);
|
|
|
|
|
2016-07-07 17:13:01 +00:00
|
|
|
uprintf("Erasing %d sectors", num_sectors_to_clear);
|
|
|
|
for (i=0; i<num_sectors_to_clear; i++) {
|
2018-06-13 18:23:24 +00:00
|
|
|
for (j = 1; j <= WRITE_RETRIES; j++) {
|
|
|
|
if (IS_ERROR(FormatStatus))
|
|
|
|
goto out;
|
|
|
|
if (write_sectors(hPhysicalDrive, SectorSize, i, 1, pBuf) != SectorSize) {
|
|
|
|
if (j < WRITE_RETRIES) {
|
|
|
|
uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000);
|
|
|
|
Sleep(WRITE_TIMEOUT);
|
|
|
|
} else
|
|
|
|
goto out;
|
|
|
|
}
|
2013-01-18 01:39:24 +00:00
|
|
|
}
|
|
|
|
}
|
2018-06-13 18:23:24 +00:00
|
|
|
for (i = last_sector - MAX_SECTORS_TO_CLEAR; i < last_sector; i++) {
|
|
|
|
for (j = 1; j <= WRITE_RETRIES; j++) {
|
|
|
|
if (IS_ERROR(FormatStatus))
|
|
|
|
goto out;
|
|
|
|
if (write_sectors(hPhysicalDrive, SectorSize, i, 1, pBuf) != SectorSize) {
|
|
|
|
if (j < WRITE_RETRIES) {
|
|
|
|
uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000);
|
|
|
|
Sleep(WRITE_TIMEOUT);
|
2018-09-17 11:08:07 +00:00
|
|
|
} else {
|
|
|
|
// Windows seems to be an ass about keeping a lock on a backup GPT,
|
2018-09-24 22:42:04 +00:00
|
|
|
// so we try to be lenient about not being able to clear it.
|
2018-09-17 11:08:07 +00:00
|
|
|
uprintf("Warning: Failed to clear backup GPT...");
|
|
|
|
r = TRUE;
|
2018-06-13 18:23:24 +00:00
|
|
|
goto out;
|
2018-09-17 11:08:07 +00:00
|
|
|
}
|
2018-06-13 18:23:24 +00:00
|
|
|
}
|
2013-01-18 01:39:24 +00:00
|
|
|
}
|
2012-11-03 17:40:33 +00:00
|
|
|
}
|
|
|
|
r = TRUE;
|
|
|
|
|
|
|
|
out:
|
|
|
|
safe_free(pBuf);
|
|
|
|
return r;
|
2011-12-06 18:11:38 +00:00
|
|
|
}
|
|
|
|
|
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;
|
2013-06-25 17:39:07 +00:00
|
|
|
DWORD size;
|
2016-06-10 11:42:43 +00:00
|
|
|
unsigned char* buffer = NULL;
|
2015-08-10 22:19:57 +00:00
|
|
|
FAKE_FD fake_fd = { 0 };
|
|
|
|
FILE* fp = (FILE*)&fake_fd;
|
2014-01-05 01:39:41 +00:00
|
|
|
const char* using_msg = "Using %s MBR\n";
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2018-10-03 17:14:40 +00:00
|
|
|
AnalyzeMBR(hPhysicalDrive, "Drive", FALSE);
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2017-03-10 18:07:48 +00:00
|
|
|
if (SelectedDrive.SectorSize < 512)
|
|
|
|
goto out;
|
|
|
|
|
2019-03-16 13:01:55 +00:00
|
|
|
if (pt == PARTITION_STYLE_GPT) {
|
|
|
|
// Add a notice in the protective MBR
|
|
|
|
fake_fd._handle = (char*)hPhysicalDrive;
|
|
|
|
set_bytes_per_sector(SelectedDrive.SectorSize);
|
|
|
|
uprintf(using_msg, "Rufus protective");
|
|
|
|
r = write_rufus_gpt_mbr(fp);
|
|
|
|
goto notify;
|
|
|
|
}
|
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
// FormatEx rewrites the MBR and removes the LBA attribute of FAT16
|
|
|
|
// and FAT32 partitions - we need to correct this in the MBR
|
2016-06-10 11:42:43 +00:00
|
|
|
buffer = (unsigned char*)_mm_malloc(SelectedDrive.SectorSize, 16);
|
|
|
|
if (buffer == NULL) {
|
2011-12-01 17:20:52 +00:00
|
|
|
uprintf("Could not allocate memory for MBR");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-06-10 11:42:43 +00:00
|
|
|
if (!read_sectors(hPhysicalDrive, SelectedDrive.SectorSize, 0, 1, buffer)) {
|
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:
|
2016-06-10 11:42:43 +00:00
|
|
|
if (buffer[0x1c2] == 0x0e) {
|
2011-12-02 00:11:53 +00:00
|
|
|
uprintf("Partition is already FAT16 LBA...\n");
|
2016-06-10 11:42:43 +00:00
|
|
|
} else if ((buffer[0x1c2] != 0x04) && (buffer[0x1c2] != 0x06)) {
|
|
|
|
uprintf("Warning: converting a non FAT16 partition to FAT16 LBA: FS type=0x%02x\n", buffer[0x1c2]);
|
2011-12-02 00:11:53 +00:00
|
|
|
}
|
2016-06-10 11:42:43 +00:00
|
|
|
buffer[0x1c2] = 0x0e;
|
2011-12-01 17:20:52 +00:00
|
|
|
break;
|
|
|
|
case FS_FAT32:
|
2016-06-10 11:42:43 +00:00
|
|
|
if (buffer[0x1c2] == 0x0c) {
|
2011-12-02 00:11:53 +00:00
|
|
|
uprintf("Partition is already FAT32 LBA...\n");
|
2016-06-10 11:42:43 +00:00
|
|
|
} else if (buffer[0x1c2] != 0x0b) {
|
|
|
|
uprintf("Warning: converting a non FAT32 partition to FAT32 LBA: FS type=0x%02x\n", buffer[0x1c2]);
|
2011-12-02 00:11:53 +00:00
|
|
|
}
|
2016-06-10 11:42:43 +00:00
|
|
|
buffer[0x1c2] = 0x0c;
|
2011-12-01 17:20:52 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-03-22 23:14:20 +00:00
|
|
|
if ((bt != BT_NON_BOOTABLE) && (tt == TT_BIOS)) {
|
2012-05-16 22:38:39 +00:00
|
|
|
// Set first partition bootable - masquerade as per the DiskID selected
|
2016-06-10 11:42:43 +00:00
|
|
|
buffer[0x1be] = IsChecked(IDC_RUFUS_MBR) ?
|
2014-11-18 23:49:29 +00:00
|
|
|
(BYTE)ComboBox_GetItemData(hDiskID, ComboBox_GetCurSel(hDiskID)):0x80;
|
2016-06-10 11:42:43 +00:00
|
|
|
uprintf("Set bootable USB partition as 0x%02X\n", buffer[0x1be]);
|
2011-12-01 17:20:52 +00:00
|
|
|
}
|
|
|
|
|
2016-06-10 11:42:43 +00:00
|
|
|
if (!write_sectors(hPhysicalDrive, SelectedDrive.SectorSize, 0, 1, buffer)) {
|
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;
|
|
|
|
}
|
|
|
|
|
2015-08-10 22:19:57 +00:00
|
|
|
fake_fd._handle = (char*)hPhysicalDrive;
|
2016-05-23 11:19:11 +00:00
|
|
|
set_bytes_per_sector(SelectedDrive.SectorSize);
|
2015-02-25 01:45:47 +00:00
|
|
|
|
|
|
|
// What follows is really a case statement with complex conditions listed
|
|
|
|
// by order of preference
|
2016-12-14 23:27:04 +00:00
|
|
|
if (HAS_WINDOWS(img_report) && (allow_dual_uefi_bios) && (tt == TT_BIOS))
|
2015-02-25 01:45:47 +00:00
|
|
|
goto windows_mbr;
|
|
|
|
|
|
|
|
// Forced UEFI (by zeroing the MBR)
|
2015-07-01 20:26:15 +00:00
|
|
|
if (tt == TT_UEFI) {
|
2014-01-11 00:19:03 +00:00
|
|
|
uprintf(using_msg, "zeroed");
|
2015-08-10 22:19:57 +00:00
|
|
|
r = write_zero_mbr(fp);
|
2015-02-25 01:45:47 +00:00
|
|
|
goto notify;
|
|
|
|
}
|
2015-10-18 20:31:47 +00:00
|
|
|
|
2015-02-25 01:45:47 +00:00
|
|
|
// Syslinux
|
2015-07-01 20:26:15 +00:00
|
|
|
if ( (bt == BT_SYSLINUX_V4) || (bt == BT_SYSLINUX_V6) ||
|
2018-03-22 23:14:20 +00:00
|
|
|
((bt == BT_IMAGE) && HAS_SYSLINUX(img_report)) ) {
|
2015-02-25 01:45:47 +00:00
|
|
|
uprintf(using_msg, "Syslinux");
|
2015-08-10 22:19:57 +00:00
|
|
|
r = write_syslinux_mbr(fp);
|
2015-02-25 01:45:47 +00:00
|
|
|
goto notify;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grub 2.0
|
2018-03-22 23:14:20 +00:00
|
|
|
if ( ((bt == BT_IMAGE) && (img_report.has_grub2)) || (bt == BT_GRUB2) ) {
|
2014-11-14 23:40:00 +00:00
|
|
|
uprintf(using_msg, "Grub 2.0");
|
2015-08-10 22:19:57 +00:00
|
|
|
r = write_grub2_mbr(fp);
|
2015-02-25 01:45:47 +00:00
|
|
|
goto notify;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grub4DOS
|
2018-03-22 23:14:20 +00:00
|
|
|
if ( ((bt == BT_IMAGE) && (img_report.has_grub4dos)) || (bt == BT_GRUB4DOS) ) {
|
2015-02-25 01:45:47 +00:00
|
|
|
uprintf(using_msg, "Grub4DOS");
|
2016-01-07 15:49:58 +00:00
|
|
|
r = write_grub4dos_mbr(fp);
|
2015-02-25 01:45:47 +00:00
|
|
|
goto notify;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReactOS
|
2015-07-01 20:26:15 +00:00
|
|
|
if (bt == BT_REACTOS) {
|
2014-01-05 01:39:41 +00:00
|
|
|
uprintf(using_msg, "ReactOS");
|
2015-08-10 22:19:57 +00:00
|
|
|
r = write_reactos_mbr(fp);
|
2015-02-25 01:45:47 +00:00
|
|
|
goto notify;
|
2015-10-18 20:31:47 +00:00
|
|
|
}
|
2015-02-25 01:45:47 +00:00
|
|
|
|
|
|
|
// KolibriOS
|
2018-03-22 23:14:20 +00:00
|
|
|
if ( (bt == BT_IMAGE) && HAS_KOLIBRIOS(img_report) && (IS_FAT(fs))) {
|
2015-02-25 01:45:47 +00:00
|
|
|
uprintf(using_msg, "KolibriOS");
|
2016-01-07 15:49:58 +00:00
|
|
|
r = write_kolibrios_mbr(fp);
|
2015-02-25 01:45:47 +00:00
|
|
|
goto notify;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If everything else failed, fall back to a conventional Windows/Rufus MBR
|
|
|
|
windows_mbr:
|
2016-12-14 23:27:04 +00:00
|
|
|
if ((HAS_WINPE(img_report) && !img_report.uses_minint) || (IsChecked(IDC_RUFUS_MBR))) {
|
2015-02-25 01:45:47 +00:00
|
|
|
uprintf(using_msg, APPLICATION_NAME);
|
2015-08-10 22:19:57 +00:00
|
|
|
r = write_rufus_mbr(fp);
|
2012-01-12 02:52:40 +00:00
|
|
|
} else {
|
2015-02-25 01:45:47 +00:00
|
|
|
uprintf(using_msg, "Windows 7");
|
2015-08-10 22:19:57 +00:00
|
|
|
r = write_win7_mbr(fp);
|
2012-01-12 02:52:40 +00:00
|
|
|
}
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2015-02-25 01:45:47 +00:00
|
|
|
notify:
|
2013-06-25 17:39:07 +00:00
|
|
|
// Tell the system we've updated the disk properties
|
2014-05-09 21:05:25 +00:00
|
|
|
if (!DeviceIoControl(hPhysicalDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &size, NULL))
|
|
|
|
uprintf("Failed to notify system about disk properties update: %s\n", WindowsErrorString());
|
2013-06-25 17:39:07 +00:00
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
out:
|
2016-06-10 11:42:43 +00:00
|
|
|
safe_mm_free(buffer);
|
2011-12-01 17:20:52 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2014-11-17 23:41:46 +00:00
|
|
|
/*
|
|
|
|
* Write Secondary Boot Record (usually right after the MBR)
|
|
|
|
*/
|
|
|
|
static BOOL WriteSBR(HANDLE hPhysicalDrive)
|
|
|
|
{
|
2014-11-18 23:49:29 +00:00
|
|
|
// TODO: Do we need anything special for 4K sectors?
|
|
|
|
DWORD size, max_size, mbr_size = 0x200;
|
2018-06-04 11:10:23 +00:00
|
|
|
int r, sub_type = bt;
|
2014-11-17 23:41:46 +00:00
|
|
|
unsigned char* buf = NULL;
|
2015-08-10 22:19:57 +00:00
|
|
|
FAKE_FD fake_fd = { 0 };
|
|
|
|
FILE* fp = (FILE*)&fake_fd;
|
2014-11-17 23:41:46 +00:00
|
|
|
|
2019-03-16 13:01:55 +00:00
|
|
|
if (pt == PARTITION_STYLE_GPT)
|
|
|
|
return TRUE;
|
|
|
|
|
2015-08-10 22:19:57 +00:00
|
|
|
fake_fd._handle = (char*)hPhysicalDrive;
|
2016-05-23 11:19:11 +00:00
|
|
|
set_bytes_per_sector(SelectedDrive.SectorSize);
|
2014-11-18 23:49:29 +00:00
|
|
|
// Ensure that we have sufficient space for the SBR
|
2018-03-22 23:14:20 +00:00
|
|
|
max_size = IsChecked(IDC_OLD_BIOS_FIXES) ?
|
2016-05-23 11:19:11 +00:00
|
|
|
(DWORD)(SelectedDrive.SectorsPerTrack * SelectedDrive.SectorSize) : 1*MB;
|
2014-11-18 23:49:29 +00:00
|
|
|
max_size -= mbr_size;
|
2015-02-25 01:45:47 +00:00
|
|
|
// Syslinux has precedence over Grub
|
2018-03-22 23:14:20 +00:00
|
|
|
if ((bt == BT_IMAGE) && (!HAS_SYSLINUX(img_report))) {
|
2015-09-02 22:20:00 +00:00
|
|
|
if (img_report.has_grub4dos)
|
2018-06-04 11:10:23 +00:00
|
|
|
sub_type = BT_GRUB4DOS;
|
2015-09-02 22:20:00 +00:00
|
|
|
if (img_report.has_grub2)
|
2018-06-04 11:10:23 +00:00
|
|
|
sub_type = BT_GRUB2;
|
2015-02-25 01:45:47 +00:00
|
|
|
}
|
2014-11-18 23:49:29 +00:00
|
|
|
|
2018-06-04 11:10:23 +00:00
|
|
|
switch (sub_type) {
|
2015-07-01 20:26:15 +00:00
|
|
|
case BT_GRUB4DOS:
|
2016-05-25 11:20:20 +00:00
|
|
|
uprintf("Writing Grub4Dos SBR");
|
2014-11-17 23:41:46 +00:00
|
|
|
buf = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_GR_GRUB_GRLDR_MBR), _RT_RCDATA, "grldr.mbr", &size, FALSE);
|
2014-11-18 23:49:29 +00:00
|
|
|
if ((buf == NULL) || (size <= mbr_size)) {
|
|
|
|
uprintf("grldr.mbr is either not present or too small");
|
|
|
|
return FALSE;
|
2014-11-17 23:41:46 +00:00
|
|
|
}
|
2014-11-18 23:49:29 +00:00
|
|
|
buf = &buf[mbr_size];
|
|
|
|
size -= mbr_size;
|
|
|
|
break;
|
2015-07-01 20:26:15 +00:00
|
|
|
case BT_GRUB2:
|
2014-12-30 19:46:13 +00:00
|
|
|
if (grub2_buf != NULL) {
|
2016-05-25 11:20:20 +00:00
|
|
|
uprintf("Writing Grub 2.0 SBR (from download) %s",
|
|
|
|
IsBufferInDB(grub2_buf, grub2_len)?"✓":"✗");
|
2014-12-30 19:46:13 +00:00
|
|
|
buf = grub2_buf;
|
|
|
|
size = (DWORD)grub2_len;
|
|
|
|
} else {
|
2016-05-25 11:20:20 +00:00
|
|
|
uprintf("Writing Grub 2.0 SBR (from embedded)");
|
2014-12-30 19:46:13 +00:00
|
|
|
buf = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_GR_GRUB2_CORE_IMG), _RT_RCDATA, "core.img", &size, FALSE);
|
|
|
|
if (buf == NULL) {
|
|
|
|
uprintf("Could not access core.img");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2014-11-17 23:41:46 +00:00
|
|
|
}
|
2014-11-18 23:49:29 +00:00
|
|
|
break;
|
|
|
|
default:
|
2014-11-17 23:41:46 +00:00
|
|
|
// No need to write secondary block
|
2014-11-18 23:49:29 +00:00
|
|
|
return TRUE;
|
2014-11-17 23:41:46 +00:00
|
|
|
}
|
2014-11-18 23:49:29 +00:00
|
|
|
|
|
|
|
if (size > max_size) {
|
|
|
|
uprintf(" SBR size is too large - You may need to uncheck 'Add fixes for old BIOSes'.");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-08-10 22:19:57 +00:00
|
|
|
r = write_data(fp, mbr_size, buf, (uint64_t)size);
|
2014-12-30 19:46:13 +00:00
|
|
|
safe_free(grub2_buf);
|
|
|
|
return (r != 0);
|
2014-11-17 23:41:46 +00:00
|
|
|
}
|
|
|
|
|
2011-12-02 00:11:53 +00:00
|
|
|
/*
|
|
|
|
* Process the Partition Boot Record
|
|
|
|
*/
|
2018-03-22 23:14:20 +00:00
|
|
|
static __inline const char* bt_to_name(void) {
|
2015-07-01 20:26:15 +00:00
|
|
|
switch (bt) {
|
|
|
|
case BT_FREEDOS: return "FreeDOS";
|
|
|
|
case BT_REACTOS: return "ReactOS";
|
2014-11-18 23:49:29 +00:00
|
|
|
default:
|
2018-03-22 23:14:20 +00:00
|
|
|
return ((bt==BT_IMAGE) && HAS_KOLIBRIOS(img_report)) ? "KolibriOS" : "Standard";
|
2014-01-05 01:39:41 +00:00
|
|
|
}
|
|
|
|
}
|
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;
|
2015-08-10 22:19:57 +00:00
|
|
|
FAKE_FD fake_fd = { 0 };
|
|
|
|
FILE* fp = (FILE*)&fake_fd;
|
2014-01-05 01:39:41 +00:00
|
|
|
const char* using_msg = "Using %s %s partition boot record\n";
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2015-08-10 22:19:57 +00:00
|
|
|
fake_fd._handle = (char*)hLogicalVolume;
|
2016-05-23 11:19:11 +00:00
|
|
|
set_bytes_per_sector(SelectedDrive.SectorSize);
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2011-12-02 00:11:53 +00:00
|
|
|
switch (ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))) {
|
|
|
|
case FS_FAT16:
|
2018-03-22 23:14:20 +00:00
|
|
|
uprintf(using_msg, bt_to_name(), "FAT16");
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!is_fat_16_fs(fp)) {
|
2014-01-05 01:39:41 +00:00
|
|
|
uprintf("New volume does not have a FAT16 boot sector - aborting\n");
|
2011-12-13 23:29:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
uprintf("Confirmed new volume has a FAT16 boot sector\n");
|
2015-07-01 20:26:15 +00:00
|
|
|
if (bt == BT_FREEDOS) {
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!write_fat_16_fd_br(fp, 0)) break;
|
2015-07-01 20:26:15 +00:00
|
|
|
} else if (bt == BT_REACTOS) {
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!write_fat_16_ros_br(fp, 0)) break;
|
2018-03-22 23:14:20 +00:00
|
|
|
} else if ((bt == BT_IMAGE) && HAS_KOLIBRIOS(img_report)) {
|
2014-05-15 20:17:12 +00:00
|
|
|
uprintf("FAT16 is not supported for KolibriOS\n"); break;
|
2012-02-03 18:19:50 +00:00
|
|
|
} else {
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!write_fat_16_br(fp, 0)) break;
|
2012-02-03 18:19:50 +00:00
|
|
|
}
|
2011-12-15 00:46:47 +00:00
|
|
|
// Disk Drive ID needs to be corrected on XP
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!write_partition_physical_disk_drive_id_fat16(fp))
|
2011-12-13 23:29:09 +00:00
|
|
|
break;
|
|
|
|
return TRUE;
|
2011-12-02 00:11:53 +00:00
|
|
|
case FS_FAT32:
|
2018-03-22 23:14:20 +00:00
|
|
|
uprintf(using_msg, bt_to_name(), "FAT32");
|
2011-12-13 23:29:09 +00:00
|
|
|
for (i=0; i<2; i++) {
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!is_fat_32_fs(fp)) {
|
2014-01-05 01:39:41 +00:00
|
|
|
uprintf("New volume does not have a %s FAT32 boot sector - aborting\n", i?"secondary":"primary");
|
2011-12-13 23:29:09 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
uprintf("Confirmed new volume has a %s FAT32 boot sector\n", i?"secondary":"primary");
|
2014-01-05 01:39:41 +00:00
|
|
|
uprintf("Setting %s FAT32 boot sector for boot...\n", i?"secondary":"primary");
|
2015-07-01 20:26:15 +00:00
|
|
|
if (bt == BT_FREEDOS) {
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!write_fat_32_fd_br(fp, 0)) break;
|
2015-07-01 20:26:15 +00:00
|
|
|
} else if (bt == BT_REACTOS) {
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!write_fat_32_ros_br(fp, 0)) break;
|
2018-03-22 23:14:20 +00:00
|
|
|
} else if ((bt == BT_IMAGE) && HAS_KOLIBRIOS(img_report)) {
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!write_fat_32_kos_br(fp, 0)) break;
|
2018-03-22 23:14:20 +00:00
|
|
|
} else if ((bt == BT_IMAGE) && HAS_BOOTMGR(img_report)) {
|
2017-01-03 16:56:30 +00:00
|
|
|
if (!write_fat_32_pe_br(fp, 0)) break;
|
2018-03-22 23:14:20 +00:00
|
|
|
} else if ((bt == BT_IMAGE) && HAS_WINPE(img_report)) {
|
2017-01-03 16:56:30 +00:00
|
|
|
if (!write_fat_32_nt_br(fp, 0)) break;
|
2014-01-05 01:39:41 +00:00
|
|
|
} else {
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!write_fat_32_br(fp, 0)) break;
|
2014-01-05 01:39:41 +00:00
|
|
|
}
|
2011-12-15 00:46:47 +00:00
|
|
|
// Disk Drive ID needs to be corrected on XP
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!write_partition_physical_disk_drive_id_fat32(fp))
|
2011-12-13 23:29:09 +00:00
|
|
|
break;
|
2016-05-23 11:19:11 +00:00
|
|
|
fake_fd._offset += 6 * SelectedDrive.SectorSize;
|
2011-12-13 23:29:09 +00:00
|
|
|
}
|
|
|
|
return TRUE;
|
2012-02-03 18:19:50 +00:00
|
|
|
case FS_NTFS:
|
2018-03-22 23:14:20 +00:00
|
|
|
uprintf(using_msg, bt_to_name(), "NTFS");
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!is_ntfs_fs(fp)) {
|
2014-01-05 01:39:41 +00:00
|
|
|
uprintf("New volume does not have an NTFS boot sector - aborting\n");
|
2012-02-03 18:19:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
uprintf("Confirmed new volume has an NTFS boot sector\n");
|
2015-08-10 22:19:57 +00:00
|
|
|
if (!write_ntfs_br(fp)) break;
|
2012-02-03 18:19:50 +00:00
|
|
|
// 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:
|
2014-01-05 01:39:41 +00:00
|
|
|
uprintf("Unsupported FS for FS BR processing - aborting\n");
|
2011-12-02 00:11:53 +00:00
|
|
|
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
|
|
|
|
*/
|
|
|
|
static BOOL SetupWinPE(char drive_letter)
|
|
|
|
{
|
|
|
|
char src[64], dst[32];
|
2018-06-22 19:59:03 +00:00
|
|
|
const char* basedir[3] = { "i386", "amd64", "minint" };
|
|
|
|
const char* patch_str_org[2] = { "\\minint\\txtsetup.sif", "\\minint\\system32\\" };
|
|
|
|
const char* patch_str_rep[2][2] = { { "\\i386\\txtsetup.sif", "\\i386\\system32\\" } ,
|
|
|
|
{ "\\amd64\\txtsetup.sif", "\\amd64\\system32\\" } };
|
|
|
|
const char *win_nt_bt_org = "$win_nt$.~bt";
|
2012-03-25 21:09:24 +00:00
|
|
|
const char *rdisk_zero = "rdisk(0)";
|
2016-06-06 18:39:53 +00:00
|
|
|
const LARGE_INTEGER liZero = { {0, 0} };
|
2012-05-16 22:38:39 +00:00
|
|
|
char setupsrcdev[64];
|
2012-03-16 18:30:44 +00:00
|
|
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
2012-03-27 19:31:15 +00:00
|
|
|
DWORD i, j, size, rw_size, index = 0;
|
|
|
|
BOOL r = FALSE;
|
2016-06-10 11:42:43 +00:00
|
|
|
char* buffer = NULL;
|
2012-03-16 18:30:44 +00:00
|
|
|
|
2018-06-22 19:59:03 +00:00
|
|
|
if ((img_report.winpe & WINPE_AMD64) == WINPE_AMD64)
|
|
|
|
index = 1;
|
|
|
|
else if ((img_report.winpe & WINPE_MININT) == WINPE_MININT)
|
|
|
|
index = 2;
|
2012-05-16 22:38:39 +00:00
|
|
|
// Allow other values than harddisk 1, as per user choice for disk ID
|
2017-08-10 18:43:04 +00:00
|
|
|
static_sprintf(setupsrcdev, "SetupSourceDevice = \"\\device\\harddisk%d\\partition1\"",
|
|
|
|
ComboBox_GetCurSel(hDiskID));
|
2012-04-06 15:22:25 +00:00
|
|
|
// Copy of ntdetect.com in root
|
2018-06-22 19:59:03 +00:00
|
|
|
static_sprintf(src, "%c:\\%s\\ntdetect.com", drive_letter, basedir[2*(index/2)]);
|
2017-08-10 18:43:04 +00:00
|
|
|
static_sprintf(dst, "%c:\\ntdetect.com", drive_letter);
|
2012-04-06 15:22:25 +00:00
|
|
|
CopyFileA(src, dst, TRUE);
|
2015-09-02 22:20:00 +00:00
|
|
|
if (!img_report.uses_minint) {
|
2018-06-22 19:59:03 +00:00
|
|
|
// Create a copy of txtsetup.sif, as we want to keep the i386/amd64 files unmodified
|
2017-08-10 18:43:04 +00:00
|
|
|
static_sprintf(src, "%c:\\%s\\txtsetup.sif", drive_letter, basedir[index]);
|
|
|
|
static_sprintf(dst, "%c:\\txtsetup.sif", drive_letter);
|
2012-05-29 16:47:24 +00:00
|
|
|
if (!CopyFileA(src, dst, TRUE)) {
|
|
|
|
uprintf("Did not copy %s as %s: %s\n", src, dst, WindowsErrorString());
|
|
|
|
}
|
2012-03-27 19:31:15 +00:00
|
|
|
if (insert_section_data(dst, "[SetupData]", setupsrcdev, FALSE) == NULL) {
|
|
|
|
uprintf("Failed to add SetupSourceDevice in %s\n", dst);
|
|
|
|
goto out;
|
|
|
|
}
|
2013-06-20 14:41:22 +00:00
|
|
|
uprintf("Successfully added '%s' to %s\n", setupsrcdev, dst);
|
2012-03-16 18:30:44 +00:00
|
|
|
}
|
|
|
|
|
2018-06-22 19:59:03 +00:00
|
|
|
static_sprintf(src, "%c:\\%s\\setupldr.bin", drive_letter, basedir[2*(index/2)]);
|
2017-08-10 18:43:04 +00:00
|
|
|
static_sprintf(dst, "%c:\\BOOTMGR", drive_letter);
|
2012-05-29 16:47:24 +00:00
|
|
|
if (!CopyFileA(src, dst, TRUE)) {
|
|
|
|
uprintf("Did not copy %s as %s: %s\n", src, dst, WindowsErrorString());
|
|
|
|
}
|
2012-03-16 18:30:44 +00:00
|
|
|
|
|
|
|
// \minint with /minint option doesn't require further processing => return true
|
|
|
|
// \minint and no \i386 without /minint is unclear => return error
|
2015-09-02 22:20:00 +00:00
|
|
|
if (img_report.winpe&WINPE_MININT) {
|
|
|
|
if (img_report.uses_minint) {
|
2012-03-16 18:30:44 +00:00
|
|
|
uprintf("Detected \\minint directory with /minint option: nothing to patch\n");
|
|
|
|
r = TRUE;
|
2018-06-22 19:59:03 +00:00
|
|
|
} else if (!(img_report.winpe&(WINPE_I386|WINPE_AMD64))) {
|
2012-03-16 18:30:44 +00:00
|
|
|
uprintf("Detected \\minint directory only but no /minint option: not sure what to do\n");
|
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// At this stage we only handle \i386
|
2017-02-16 14:13:30 +00:00
|
|
|
handle = CreateFileA(dst, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ,
|
2014-11-11 19:17:39 +00:00
|
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
2012-03-16 18:30:44 +00:00
|
|
|
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;
|
|
|
|
}
|
2016-06-10 11:42:43 +00:00
|
|
|
buffer = (char*)malloc(size);
|
|
|
|
if (buffer == NULL)
|
2012-03-16 18:30:44 +00:00
|
|
|
goto out;
|
2016-06-10 11:42:43 +00:00
|
|
|
if ((!ReadFile(handle, buffer, size, &rw_size, NULL)) || (size != rw_size)) {
|
2012-03-16 18:30:44 +00:00
|
|
|
uprintf("Could not read file %s: %s\n", dst, WindowsErrorString());
|
|
|
|
goto out;
|
|
|
|
}
|
2017-01-04 17:23:53 +00:00
|
|
|
if (!SetFilePointerEx(handle, liZero, NULL, FILE_BEGIN)) {
|
|
|
|
uprintf("Could not rewind file %s: %s\n", dst, WindowsErrorString());
|
|
|
|
goto out;
|
|
|
|
}
|
2012-03-16 18:30:44 +00:00
|
|
|
|
2012-03-27 19:31:15 +00:00
|
|
|
// Patch setupldr.bin
|
2012-03-16 18:30:44 +00:00
|
|
|
uprintf("Patching file %s\n", dst);
|
2012-03-27 19:31:15 +00:00
|
|
|
// Remove CRC check for 32 bit part of setupldr.bin from Win2k3
|
2016-06-10 11:42:43 +00:00
|
|
|
if ((size > 0x2061) && (buffer[0x2060] == 0x74) && (buffer[0x2061] == 0x03)) {
|
|
|
|
buffer[0x2060] = 0xeb;
|
|
|
|
buffer[0x2061] = 0x1a;
|
2012-03-27 19:31:15 +00:00
|
|
|
uprintf(" 0x00002060: 0x74 0x03 -> 0xEB 0x1A (disable Win2k3 CRC check)\n");
|
|
|
|
}
|
|
|
|
for (i=1; i<size-32; i++) {
|
2012-03-16 18:30:44 +00:00
|
|
|
for (j=0; j<ARRAYSIZE(patch_str_org); j++) {
|
2016-06-10 11:42:43 +00:00
|
|
|
if (safe_strnicmp(&buffer[i], patch_str_org[j], strlen(patch_str_org[j])-1) == 0) {
|
2018-06-22 19:59:03 +00:00
|
|
|
uprintf(" 0x%08X: '%s' -> '%s'\n", i, &buffer[i], patch_str_rep[index][j]);
|
|
|
|
strcpy(&buffer[i], patch_str_rep[index][j]);
|
|
|
|
i += (DWORD)max(strlen(patch_str_org[j]), strlen(patch_str_rep[index][j])); // in case org is a substring of rep
|
2012-03-16 18:30:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-02 22:20:00 +00:00
|
|
|
if (!img_report.uses_minint) {
|
2012-03-27 19:31:15 +00:00
|
|
|
// Additional setupldr.bin/bootmgr patching
|
2012-03-16 18:30:44 +00:00
|
|
|
for (i=0; i<size-32; i++) {
|
2012-05-16 22:38:39 +00:00
|
|
|
// rdisk(0) -> rdisk(#) disk masquerading
|
2012-05-29 16:47:24 +00:00
|
|
|
// NB: only the first one seems to be needed
|
2016-06-10 11:42:43 +00:00
|
|
|
if (safe_strnicmp(&buffer[i], rdisk_zero, strlen(rdisk_zero)-1) == 0) {
|
|
|
|
buffer[i+6] = 0x30 + ComboBox_GetCurSel(hDiskID);
|
|
|
|
uprintf(" 0x%08X: '%s' -> 'rdisk(%c)'\n", i, rdisk_zero, buffer[i+6]);
|
2012-03-25 21:09:24 +00:00
|
|
|
}
|
2018-06-22 19:59:03 +00:00
|
|
|
// $WIN_NT$_~BT -> i386/amd64
|
2016-06-10 11:42:43 +00:00
|
|
|
if (safe_strnicmp(&buffer[i], win_nt_bt_org, strlen(win_nt_bt_org)-1) == 0) {
|
2018-06-22 19:59:03 +00:00
|
|
|
uprintf(" 0x%08X: '%s' -> '%s%s'\n", i, &buffer[i], basedir[index], &buffer[i+strlen(win_nt_bt_org)]);
|
|
|
|
strcpy(&buffer[i], basedir[index]);
|
2012-03-27 19:31:15 +00:00
|
|
|
// This ensures that we keep the terminator backslash
|
2018-06-22 19:59:03 +00:00
|
|
|
buffer[i+strlen(basedir[index])] = buffer[i+strlen(win_nt_bt_org)];
|
|
|
|
buffer[i+strlen(basedir[index])+1] = 0;
|
2012-03-16 18:30:44 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-27 19:31:15 +00:00
|
|
|
}
|
2012-03-16 18:30:44 +00:00
|
|
|
|
2016-06-10 11:42:43 +00:00
|
|
|
if (!WriteFileWithRetry(handle, buffer, size, &rw_size, WRITE_RETRIES)) {
|
2012-03-27 19:31:15 +00:00
|
|
|
uprintf("Could not write patched file: %s\n", WindowsErrorString());
|
|
|
|
goto out;
|
2012-03-16 18:30:44 +00:00
|
|
|
}
|
|
|
|
r = TRUE;
|
|
|
|
|
|
|
|
out:
|
|
|
|
safe_closehandle(handle);
|
2016-06-10 11:42:43 +00:00
|
|
|
safe_free(buffer);
|
2012-03-16 18:30:44 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-01-08 18:30:07 +00:00
|
|
|
// Checks which versions of Windows are available in an install image
|
2016-12-15 12:04:19 +00:00
|
|
|
// to set our extraction index. Asks the user to select one if needed.
|
2017-05-01 23:21:14 +00:00
|
|
|
// Returns -2 on user cancel, -1 on other error, >=0 on success.
|
|
|
|
int SetWinToGoIndex(void)
|
2016-12-15 12:04:19 +00:00
|
|
|
{
|
2017-04-19 10:30:24 +00:00
|
|
|
char *mounted_iso, *build, image[128];
|
2016-12-15 12:04:19 +00:00
|
|
|
char tmp_path[MAX_PATH] = "", xml_file[MAX_PATH] = "";
|
2019-01-08 18:30:07 +00:00
|
|
|
char *install_names[MAX_WININST];
|
2016-12-15 12:04:19 +00:00
|
|
|
StrArray version_name, version_index;
|
2017-04-19 10:30:24 +00:00
|
|
|
int i, build_nr = 0;
|
2017-08-02 17:58:27 +00:00
|
|
|
BOOL bNonStandard = FALSE;
|
2016-12-15 12:04:19 +00:00
|
|
|
|
|
|
|
// Sanity checks
|
2017-04-19 10:30:24 +00:00
|
|
|
wintogo_index = -1;
|
2019-01-08 18:30:07 +00:00
|
|
|
wininst_index = 0;
|
2016-12-15 12:04:19 +00:00
|
|
|
if ((nWindowsVersion < WINDOWS_8) || ((WimExtractCheck() & 4) == 0) ||
|
|
|
|
(ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)) != FS_NTFS)) {
|
2019-01-08 18:30:07 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have multiple windows install images, ask the user the one to use
|
|
|
|
if (img_report.wininst_index > 1) {
|
|
|
|
for (i = 0; i < img_report.wininst_index; i++)
|
|
|
|
install_names[i] = &img_report.wininst_path[i][2];
|
|
|
|
wininst_index = SelectionDialog(lmprintf(MSG_130), lmprintf(MSG_131), install_names, img_report.wininst_index);
|
|
|
|
if (wininst_index < 0)
|
|
|
|
return -2;
|
|
|
|
wininst_index--;
|
|
|
|
if ((wininst_index < 0) || (wininst_index >= MAX_WININST))
|
|
|
|
wininst_index = 0;
|
2016-12-15 12:04:19 +00:00
|
|
|
}
|
2019-01-08 18:30:07 +00:00
|
|
|
|
2016-12-15 12:04:19 +00:00
|
|
|
// Mount the install.wim image, that resides on the ISO
|
|
|
|
mounted_iso = MountISO(image_path);
|
|
|
|
if (mounted_iso == NULL) {
|
|
|
|
uprintf("Could not mount ISO for Windows To Go selection");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2019-01-08 18:30:07 +00:00
|
|
|
static_sprintf(image, "%s%s", mounted_iso, &img_report.wininst_path[wininst_index][2]);
|
2016-12-15 12:04:19 +00:00
|
|
|
|
|
|
|
// Now take a look at the XML file in install.wim to list our versions
|
|
|
|
if ((GetTempPathU(sizeof(tmp_path), tmp_path) == 0)
|
|
|
|
|| (GetTempFileNameU(tmp_path, APPLICATION_NAME, 0, xml_file) == 0)
|
|
|
|
|| (xml_file[0] == 0)) {
|
2017-08-02 17:58:27 +00:00
|
|
|
// Last ditch effort to get a tmp file - just extract it to the current directory
|
2017-08-10 18:43:04 +00:00
|
|
|
static_strcpy(xml_file, ".\\RufVXml.tmp");
|
2016-12-15 12:04:19 +00:00
|
|
|
}
|
|
|
|
// GetTempFileName() may leave a file behind
|
|
|
|
DeleteFileU(xml_file);
|
|
|
|
|
|
|
|
// Must use the Windows WIM API as 7z messes up the XML
|
|
|
|
if (!WimExtractFile_API(image, 0, "[1].xml", xml_file)) {
|
2019-01-08 18:30:07 +00:00
|
|
|
uprintf("Could not acquire WIM index");
|
2017-04-19 10:30:24 +00:00
|
|
|
goto out;
|
2016-12-15 12:04:19 +00:00
|
|
|
}
|
2017-04-19 10:30:24 +00:00
|
|
|
|
2016-12-15 12:04:19 +00:00
|
|
|
StrArrayCreate(&version_name, 16);
|
|
|
|
StrArrayCreate(&version_index, 16);
|
2017-08-02 17:58:27 +00:00
|
|
|
for (i = 0; StrArrayAdd(&version_index, get_token_data_file_indexed("IMAGE INDEX", xml_file, i + 1), FALSE) >= 0; i++) {
|
|
|
|
// Some people are apparently creating *unofficial* Windows ISOs that don't have DISPLAYNAME elements.
|
|
|
|
// If we are parsing such an ISO, try to fall back to using DESCRIPTION. Of course, since we don't use
|
|
|
|
// a formal XML parser, if an ISO mixes entries with both DISPLAYNAME and DESCRIPTION and others with
|
|
|
|
// only DESCRIPTION, the version names we report will be wrong.
|
|
|
|
// But hey, there's only so far I'm willing to go to help people who, not content to have demonstrated
|
|
|
|
// their utter ignorance on development matters, are also trying to lecture experienced developers
|
|
|
|
// about specific "noob mistakes"... that don't exist in the code they are trying to criticize.
|
|
|
|
if (StrArrayAdd(&version_name, get_token_data_file_indexed("DISPLAYNAME", xml_file, i + 1), FALSE) < 0) {
|
|
|
|
bNonStandard = TRUE;
|
|
|
|
if (StrArrayAdd(&version_name, get_token_data_file_indexed("DESCRIPTION", xml_file, i + 1), FALSE) < 0) {
|
|
|
|
uprintf("Warning: Could not find a description for image index %d", i + 1);
|
|
|
|
StrArrayAdd(&version_name, "Unknown Windows Version", TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bNonStandard)
|
|
|
|
uprintf("Warning: Nonstandard Windows image (missing <DISPLAYNAME> entries)");
|
2015-06-24 19:00:20 +00:00
|
|
|
|
2016-12-15 12:04:19 +00:00
|
|
|
if (i > 1)
|
2017-07-11 16:43:51 +00:00
|
|
|
i = SelectionDialog(lmprintf(MSG_291), lmprintf(MSG_292), version_name.String, i);
|
2016-12-15 12:04:19 +00:00
|
|
|
if (i < 0) {
|
2017-06-20 13:10:22 +00:00
|
|
|
wintogo_index = -2; // Cancelled by the user
|
2016-12-15 12:04:19 +00:00
|
|
|
} else if (i == 0) {
|
|
|
|
wintogo_index = 1;
|
|
|
|
} else {
|
|
|
|
wintogo_index = atoi(version_index.String[i - 1]);
|
|
|
|
}
|
2017-08-02 17:58:27 +00:00
|
|
|
if (i > 0) {
|
2017-04-19 10:30:24 +00:00
|
|
|
// Get the build version
|
|
|
|
build = get_token_data_file_indexed("BUILD", xml_file, i);
|
|
|
|
if (build != NULL)
|
|
|
|
build_nr = atoi(build);
|
|
|
|
free(build);
|
|
|
|
uprintf("Will use '%s' (Build: %d, Index %s) for Windows To Go",
|
|
|
|
version_name.String[i - 1], build_nr, version_index.String[i - 1]);
|
|
|
|
// Need Windows 10 Creator Update or later for boot on REMOVABLE to work
|
|
|
|
if ((build_nr < 15000) && (SelectedDrive.MediaType != FixedMedia)) {
|
|
|
|
if (MessageBoxExU(hMainDialog, lmprintf(MSG_098), lmprintf(MSG_190),
|
|
|
|
MB_YESNO | MB_ICONWARNING | MB_IS_RTL, selected_langid) != IDYES)
|
2017-05-01 23:21:14 +00:00
|
|
|
wintogo_index = -2;
|
2017-04-19 10:30:24 +00:00
|
|
|
}
|
2019-01-30 17:15:25 +00:00
|
|
|
// Display a notice about WppRecorder.sys for 1809 ISOs
|
|
|
|
if (build_nr == 17763) {
|
|
|
|
notification_info more_info;
|
|
|
|
more_info.id = MORE_INFO_URL;
|
|
|
|
more_info.url = WPPRECORDER_MORE_INFO_URL;
|
|
|
|
Notification(MSG_INFO, NULL, &more_info, lmprintf(MSG_128, "Windows To Go"), lmprintf(MSG_133));
|
|
|
|
}
|
2017-04-19 10:30:24 +00:00
|
|
|
}
|
2016-12-15 12:04:19 +00:00
|
|
|
StrArrayDestroy(&version_name);
|
|
|
|
StrArrayDestroy(&version_index);
|
2017-04-19 10:30:24 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
DeleteFileU(xml_file);
|
|
|
|
UnMountISO();
|
2017-05-01 23:21:14 +00:00
|
|
|
return wintogo_index;
|
2016-12-15 12:04:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// http://technet.microsoft.com/en-ie/library/jj721578.aspx
|
2015-06-24 19:00:20 +00:00
|
|
|
// As opposed to the technet guide above, we no longer set internal drives offline,
|
|
|
|
// due to people wondering why they can't see them by default, and also due to dism
|
|
|
|
// incompatibilities from one version of Windows to the next.
|
|
|
|
// Maybe when we use wimlib we'll review this, but for now just turn it off.
|
|
|
|
//#define SET_INTERNAL_DRIVES_OFFLINE
|
2016-03-04 16:34:50 +00:00
|
|
|
static BOOL SetupWinToGo(const char* drive_name, BOOL use_ms_efi)
|
2015-01-16 01:51:24 +00:00
|
|
|
{
|
2015-06-24 19:00:20 +00:00
|
|
|
#ifdef SET_INTERNAL_DRIVES_OFFLINE
|
|
|
|
static char san_policy_path[] = "?:\\san_policy.xml";
|
|
|
|
#endif
|
|
|
|
static char unattend_path[] = "?:\\Windows\\System32\\sysprep\\unattend.xml";
|
2015-06-27 21:12:30 +00:00
|
|
|
char *mounted_iso, *ms_efi = NULL, image[128], cmd[MAX_PATH];
|
2015-01-16 01:51:24 +00:00
|
|
|
unsigned char *buffer;
|
2015-06-24 19:00:20 +00:00
|
|
|
wchar_t wVolumeName[] = L"?:";
|
2015-01-16 01:51:24 +00:00
|
|
|
DWORD bufsize;
|
2015-01-20 21:50:24 +00:00
|
|
|
ULONG cluster_size;
|
2015-01-16 01:51:24 +00:00
|
|
|
FILE* fd;
|
2015-01-20 02:56:17 +00:00
|
|
|
PF_DECL(FormatEx);
|
|
|
|
PF_INIT(FormatEx, Fmifs);
|
2015-01-16 01:51:24 +00:00
|
|
|
|
|
|
|
uprintf("Windows To Go mode selected");
|
2015-01-20 21:50:24 +00:00
|
|
|
// Additional sanity checks
|
2017-04-19 10:30:24 +00:00
|
|
|
if ( (use_ms_efi) && (SelectedDrive.MediaType != FixedMedia) && (nWindowsBuildNumber < 15000)) {
|
2015-01-20 02:56:17 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_SUPPORTED;
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-01-16 01:51:24 +00:00
|
|
|
|
|
|
|
// First, we need to access the install.wim image, that resides on the ISO
|
|
|
|
mounted_iso = MountISO(image_path);
|
|
|
|
if (mounted_iso == NULL) {
|
|
|
|
uprintf("Could not mount ISO for Windows To Go installation");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2019-01-08 18:30:07 +00:00
|
|
|
static_sprintf(image, "%s%s", mounted_iso, &img_report.wininst_path[wininst_index][2]);
|
2015-01-16 01:51:24 +00:00
|
|
|
uprintf("Mounted ISO as '%s'", mounted_iso);
|
|
|
|
|
|
|
|
// Now we use the WIM API to apply that image
|
2016-12-15 12:04:19 +00:00
|
|
|
if (!WimApplyImage(image, wintogo_index, drive_name)) {
|
2015-01-16 01:51:24 +00:00
|
|
|
uprintf("Failed to apply Windows To Go image");
|
|
|
|
if (!IS_ERROR(FormatStatus))
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
|
|
|
|
UnMountISO();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
UnMountISO();
|
|
|
|
|
2015-01-20 02:56:17 +00:00
|
|
|
if (use_ms_efi) {
|
|
|
|
uprintf("Setting up MS EFI system partition");
|
|
|
|
if (pfFormatEx == NULL)
|
|
|
|
return FALSE;
|
|
|
|
ms_efi = AltMountVolume(drive_name, 3); // MSR, main, EFI
|
|
|
|
if (ms_efi == NULL) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-01-20 21:50:24 +00:00
|
|
|
uprintf("Formatting EFI system partition %s", ms_efi);
|
|
|
|
// According to Ubuntu (https://bugs.launchpad.net/ubuntu/+source/partman-efi/+bug/811485) you want to use FAT32.
|
|
|
|
// However, you have to be careful that the cluster size needs to be greater or equal to the sector size, which
|
|
|
|
// in turn has an impact on the minimum EFI partition size we can create (see ms_efi_size_MB in drive.c)
|
2016-05-23 11:19:11 +00:00
|
|
|
if (SelectedDrive.SectorSize <= 1024)
|
2015-01-20 21:50:24 +00:00
|
|
|
cluster_size = 1024;
|
2016-05-23 11:19:11 +00:00
|
|
|
else if (SelectedDrive.SectorSize <= 4096)
|
2015-01-20 21:50:24 +00:00
|
|
|
cluster_size = 4096;
|
|
|
|
else // Go for broke
|
2016-05-23 11:19:11 +00:00
|
|
|
cluster_size = (ULONG)SelectedDrive.SectorSize;
|
2015-01-20 21:50:24 +00:00
|
|
|
fs_index = 1; // FAT32
|
2015-01-20 02:56:17 +00:00
|
|
|
task_number = 0;
|
|
|
|
wVolumeName[0] = ms_efi[0];
|
2015-01-20 21:50:24 +00:00
|
|
|
|
|
|
|
// Boy do you *NOT* want to specify a label here, and spend HOURS figuring out why your EFI partition cannot boot...
|
2016-05-23 11:19:11 +00:00
|
|
|
pfFormatEx(wVolumeName, SelectedDrive.MediaType, L"FAT32", L"", TRUE, cluster_size, FormatExCallback);
|
2015-01-20 02:56:17 +00:00
|
|
|
if (IS_ERROR(FormatStatus)) {
|
|
|
|
uprintf("Failed to format EFI partition");
|
|
|
|
AltUnmountVolume(ms_efi);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-08-22 22:23:08 +00:00
|
|
|
Sleep(200);
|
2015-01-20 02:56:17 +00:00
|
|
|
}
|
|
|
|
|
2015-08-22 22:23:08 +00:00
|
|
|
// We invoke the 'bcdboot' command from the host, as the one from the drive produces problems (#558)
|
|
|
|
// Also, since Rufus should (usually) be running as a 32 bit app, on 64 bit systems, we need to use
|
|
|
|
// 'C:\Windows\Sysnative' and not 'C:\Windows\System32' to invoke bcdboot, as 'C:\Windows\System32'
|
2018-09-11 15:05:30 +00:00
|
|
|
// will get converted to 'C:\Windows\SysWOW64' behind the scenes, and there is no bcdboot.exe there.
|
2018-09-14 13:10:40 +00:00
|
|
|
static_sprintf(cmd, "%s\\bcdboot.exe %s\\Windows /v /f %s /s %s", sysnative_dir, drive_name,
|
|
|
|
HAS_BOOTMGR_BIOS(img_report) ? (HAS_BOOTMGR_EFI(img_report) ? "ALL" : "BIOS") : "UEFI",
|
|
|
|
(use_ms_efi)?ms_efi:drive_name);
|
2017-06-20 13:10:22 +00:00
|
|
|
uprintf("Enabling boot using command '%s'", cmd);
|
2017-04-11 21:15:05 +00:00
|
|
|
if (RunCommand(cmd, sysnative_dir, usb_debug) != 0) {
|
2015-08-22 22:23:08 +00:00
|
|
|
// Try to continue... but report a failure
|
2017-06-20 13:10:22 +00:00
|
|
|
uprintf("Failed to enable boot");
|
2015-08-22 22:23:08 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_ISO_EXTRACT);
|
2015-01-16 01:51:24 +00:00
|
|
|
}
|
2015-01-20 02:56:17 +00:00
|
|
|
|
|
|
|
if (use_ms_efi) {
|
|
|
|
Sleep(200);
|
|
|
|
AltUnmountVolume(ms_efi);
|
|
|
|
}
|
2015-01-22 22:31:34 +00:00
|
|
|
PrintInfo(0, MSG_267, 99.9f);
|
|
|
|
UpdateProgress(OP_DOS, 99.9f);
|
2015-01-16 01:51:24 +00:00
|
|
|
|
|
|
|
// The following are non fatal if they fail
|
2015-06-24 19:00:20 +00:00
|
|
|
|
|
|
|
#ifdef SET_INTERNAL_DRIVES_OFFLINE
|
|
|
|
uprintf("Applying 'san_policy.xml', to set the target's internal drives offline...");
|
2015-01-16 01:51:24 +00:00
|
|
|
buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_TOGO_SAN_POLICY_XML),
|
|
|
|
_RT_RCDATA, "san_policy.xml", &bufsize, FALSE);
|
|
|
|
san_policy_path[0] = drive_name[0];
|
|
|
|
fd = fopenU(san_policy_path, "wb");
|
|
|
|
if ((fd == NULL) || (fwrite(buffer, 1, bufsize, fd) != bufsize)) {
|
|
|
|
uprintf("Could not write '%s'\n", san_policy_path);
|
|
|
|
if (fd)
|
|
|
|
fclose(fd);
|
|
|
|
} else {
|
|
|
|
fclose(fd);
|
2015-01-26 23:20:39 +00:00
|
|
|
// Can't use the one from the USB (at least for Windows 10 preview), as you'll get
|
|
|
|
// "Error: 0x800401f0 An error occurred while initializing COM security".
|
|
|
|
// On the other hand, using Windows 8.1 dism against Windows 10 doesn't work either
|
|
|
|
// (you get a message about needing to upgrade to latest AIK)...
|
2015-01-20 02:56:17 +00:00
|
|
|
static_sprintf(cmd, "dism /Image:%s\\ /Apply-Unattend:%s", drive_name, san_policy_path);
|
2015-01-16 01:51:24 +00:00
|
|
|
if (RunCommand(cmd, NULL, TRUE) != 0)
|
2015-01-26 23:20:39 +00:00
|
|
|
uprintf("Command '%s' failed to run", cmd);
|
2015-01-16 01:51:24 +00:00
|
|
|
}
|
2015-06-24 19:00:20 +00:00
|
|
|
#endif
|
2015-01-16 01:51:24 +00:00
|
|
|
|
2015-06-24 19:00:20 +00:00
|
|
|
uprintf("Copying 'unattend.xml', to disable the use of the Windows Recovery Environment...");
|
2015-01-16 01:51:24 +00:00
|
|
|
buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_TOGO_UNATTEND_XML),
|
|
|
|
_RT_RCDATA, "unattend.xml", &bufsize, FALSE);
|
|
|
|
unattend_path[0] = drive_name[0];
|
|
|
|
fd = fopenU(unattend_path, "wb");
|
|
|
|
if ((fd == NULL) || (fwrite(buffer, 1, bufsize, fd) != bufsize)) {
|
|
|
|
uprintf("Could not write '%s'\n", unattend_path);
|
|
|
|
}
|
|
|
|
fclose(fd);
|
2015-01-22 22:31:34 +00:00
|
|
|
PrintInfo(0, MSG_267, 100.0f);
|
2015-01-16 01:51:24 +00:00
|
|
|
UpdateProgress(OP_DOS, 100.0f);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-03-04 16:34:50 +00:00
|
|
|
static void update_progress(const uint64_t processed_bytes)
|
2014-12-29 20:34:41 +00:00
|
|
|
{
|
2017-11-13 14:29:48 +00:00
|
|
|
if (GetTickCount64() > LastRefresh + MAX_REFRESH) {
|
|
|
|
LastRefresh = GetTickCount64();
|
2017-05-01 15:22:34 +00:00
|
|
|
format_percent = (100.0f*processed_bytes)/(1.0f*img_report.image_size);
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfo(0, MSG_261, format_percent);
|
2014-12-29 20:34:41 +00:00
|
|
|
UpdateProgress(OP_FORMAT, format_percent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-04 16:34:50 +00:00
|
|
|
/* Write an image file or zero a drive */
|
|
|
|
static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage)
|
|
|
|
{
|
|
|
|
BOOL s, ret = FALSE;
|
|
|
|
LARGE_INTEGER li;
|
2018-07-06 11:35:22 +00:00
|
|
|
DWORD rSize, wSize, xSize, BufSize;
|
2017-05-01 15:22:34 +00:00
|
|
|
uint64_t wb, target_size = hSourceImage?img_report.image_size:SelectedDrive.DiskSize;
|
2017-10-12 15:40:54 +00:00
|
|
|
int64_t bled_ret;
|
2016-06-10 11:42:43 +00:00
|
|
|
uint8_t *buffer = NULL;
|
2018-07-06 11:35:22 +00:00
|
|
|
uint8_t *cmp_buffer = NULL;
|
2018-07-15 11:27:21 +00:00
|
|
|
int i, *ptr, zero_data, throttle_fast_zeroing = 0;
|
2016-03-04 16:34:50 +00:00
|
|
|
|
|
|
|
// We poked the MBR and other stuff, so we need to rewind
|
|
|
|
li.QuadPart = 0;
|
|
|
|
if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN))
|
|
|
|
uprintf("Warning: Unable to rewind image position - wrong data might be copied!");
|
|
|
|
LastRefresh = 0;
|
|
|
|
|
|
|
|
if (img_report.compression_type != BLED_COMPRESSION_NONE) {
|
2017-10-12 15:40:54 +00:00
|
|
|
uprintf("Writing compressed image...");
|
2016-03-04 16:34:50 +00:00
|
|
|
bled_init(_uprintf, update_progress, &FormatStatus);
|
2017-10-12 15:40:54 +00:00
|
|
|
bled_ret = bled_uncompress_with_handles(hSourceImage, hPhysicalDrive, img_report.compression_type);
|
2016-03-04 16:34:50 +00:00
|
|
|
bled_exit();
|
2017-10-12 15:40:54 +00:00
|
|
|
if ((bled_ret < 0) && (SCODE_CODE(FormatStatus) != ERROR_CANCELLED)) {
|
|
|
|
// Unfortunately, different compression backends return different negative error codes
|
|
|
|
uprintf("Could not write compressed image: %" PRIi64, bled_ret);
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_WRITE_FAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2016-03-04 16:34:50 +00:00
|
|
|
} else {
|
2018-07-06 11:35:22 +00:00
|
|
|
uprintf(hSourceImage?"Writing Image...":fast_zeroing?"Fast-zeroing drive...":"Zeroing drive...");
|
2016-06-10 11:42:43 +00:00
|
|
|
// Our buffer size must be a multiple of the sector size and *ALIGNED* to the sector size
|
2016-05-23 11:19:11 +00:00
|
|
|
BufSize = ((DD_BUFFER_SIZE + SelectedDrive.SectorSize - 1) / SelectedDrive.SectorSize) * SelectedDrive.SectorSize;
|
2016-06-10 11:42:43 +00:00
|
|
|
buffer = (uint8_t*)_mm_malloc(BufSize, SelectedDrive.SectorSize);
|
2016-03-04 16:34:50 +00:00
|
|
|
if (buffer == NULL) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NOT_ENOUGH_MEMORY;
|
2016-06-10 11:42:43 +00:00
|
|
|
uprintf("Could not allocate disk write buffer");
|
|
|
|
goto out;
|
|
|
|
}
|
2018-07-06 11:35:22 +00:00
|
|
|
assert((uintptr_t)buffer % SelectedDrive.SectorSize == 0);
|
|
|
|
|
|
|
|
// Clear buffer
|
|
|
|
memset(buffer, fast_zeroing ? 0xff : 0x00, BufSize);
|
|
|
|
|
|
|
|
cmp_buffer = (uint8_t*)_mm_malloc(BufSize, SelectedDrive.SectorSize);
|
|
|
|
if (cmp_buffer == NULL) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
uprintf("Could not allocate disk comparison buffer");
|
2016-03-04 16:34:50 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2018-07-06 11:35:22 +00:00
|
|
|
assert((uintptr_t)cmp_buffer % SelectedDrive.SectorSize == 0);
|
2016-03-04 16:34:50 +00:00
|
|
|
|
|
|
|
// Don't bother trying for something clever, using double buffering overlapped and whatnot:
|
|
|
|
// With Windows' default optimizations, sync read + sync write for sequential operations
|
|
|
|
// will be as fast, if not faster, than whatever async scheme you can come up with.
|
|
|
|
rSize = BufSize;
|
|
|
|
for (wb = 0, wSize = 0; wb < (uint64_t)SelectedDrive.DiskSize; wb += wSize) {
|
2017-11-13 14:29:48 +00:00
|
|
|
if (GetTickCount64() > LastRefresh + MAX_REFRESH) {
|
|
|
|
LastRefresh = GetTickCount64();
|
2016-03-04 16:34:50 +00:00
|
|
|
format_percent = (100.0f*wb) / (1.0f*target_size);
|
2018-07-06 11:35:22 +00:00
|
|
|
PrintInfo(0, hSourceImage?MSG_261:fast_zeroing?MSG_306:MSG_286, format_percent);
|
2016-03-04 16:34:50 +00:00
|
|
|
UpdateProgress(OP_FORMAT, format_percent);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hSourceImage != NULL) {
|
2016-06-10 11:42:43 +00:00
|
|
|
s = ReadFile(hSourceImage, buffer, BufSize, &rSize, NULL);
|
2016-03-04 16:34:50 +00:00
|
|
|
if (!s) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_READ_FAULT;
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Read error: %s", WindowsErrorString());
|
2016-03-04 16:34:50 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (rSize == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Don't overflow our projected size (mostly for VHDs)
|
|
|
|
if (wb + rSize > target_size) {
|
|
|
|
rSize = (DWORD)(target_size - wb);
|
|
|
|
}
|
|
|
|
|
|
|
|
// WriteFile fails unless the size is a multiple of sector size
|
2016-05-23 11:19:11 +00:00
|
|
|
if (rSize % SelectedDrive.SectorSize != 0)
|
|
|
|
rSize = ((rSize + SelectedDrive.SectorSize - 1) / SelectedDrive.SectorSize) * SelectedDrive.SectorSize;
|
2018-07-06 11:35:22 +00:00
|
|
|
|
|
|
|
// Fast-zeroing: Depending on your hardware, reading from flash may be much faster than writing, so
|
|
|
|
// we might speed things up by skipping empty blocks, or skipping the write if the data is the same.
|
|
|
|
// Notes: A block is declared empty when all bits are either 0 (zeros) or 1 (flash block erased).
|
|
|
|
// Also, a back-off strategy is used to limit reading.
|
|
|
|
if (throttle_fast_zeroing) {
|
|
|
|
throttle_fast_zeroing--;
|
2018-07-15 11:27:21 +00:00
|
|
|
} else if (fast_zeroing) {
|
|
|
|
assert(hSourceImage == NULL); // Only enabled for zeroing
|
2018-07-06 11:35:22 +00:00
|
|
|
CHECK_FOR_USER_CANCEL;
|
|
|
|
|
|
|
|
// Read block and compare against the block that needs to be written
|
|
|
|
s = ReadFile(hPhysicalDrive, cmp_buffer, rSize, &xSize, NULL);
|
|
|
|
if ((!s) || (xSize != rSize) ) {
|
|
|
|
uprintf("Read error: Could not read data for comparison - %s", WindowsErrorString());
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-07-15 11:27:21 +00:00
|
|
|
// Check for an empty block
|
|
|
|
ptr = (int*)(cmp_buffer);
|
|
|
|
// Get first element
|
|
|
|
zero_data = ptr[0];
|
|
|
|
// Check all bits are the same
|
|
|
|
if ((zero_data == 0) || (zero_data == -1)) {
|
2018-07-06 11:35:22 +00:00
|
|
|
// Compare the rest of the block against the first element
|
2018-07-15 11:27:21 +00:00
|
|
|
for (i = 1; i < (int)(rSize / sizeof(int)); i++) {
|
|
|
|
if (ptr[i] != zero_data)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i >= (int)(rSize / sizeof(int))) {
|
|
|
|
// Block is empty, skip write
|
|
|
|
wSize = rSize;
|
|
|
|
continue;
|
2018-07-06 11:35:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move the file pointer position back for writing
|
|
|
|
li.QuadPart = wb;
|
|
|
|
if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN)) {
|
|
|
|
uprintf("Error: Could not reset position - %s", WindowsErrorString());
|
|
|
|
goto out;
|
|
|
|
}
|
2018-07-15 11:27:21 +00:00
|
|
|
// Throttle read operations
|
2018-07-06 11:35:22 +00:00
|
|
|
throttle_fast_zeroing = 15;
|
|
|
|
}
|
|
|
|
|
2018-06-13 18:23:24 +00:00
|
|
|
for (i = 1; i <= WRITE_RETRIES; i++) {
|
2016-03-04 16:34:50 +00:00
|
|
|
CHECK_FOR_USER_CANCEL;
|
2016-06-10 11:42:43 +00:00
|
|
|
s = WriteFile(hPhysicalDrive, buffer, rSize, &wSize, NULL);
|
2016-03-04 16:34:50 +00:00
|
|
|
if ((s) && (wSize == rSize))
|
|
|
|
break;
|
|
|
|
if (s)
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Write error: Wrote %d bytes, expected %d bytes", wSize, rSize);
|
2016-03-04 16:34:50 +00:00
|
|
|
else
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Write error at sector %" PRIi64 ": %s", wb / SelectedDrive.SectorSize, WindowsErrorString());
|
|
|
|
if (i < WRITE_RETRIES) {
|
2016-03-04 16:34:50 +00:00
|
|
|
li.QuadPart = wb;
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000);
|
|
|
|
Sleep(WRITE_TIMEOUT);
|
2017-01-04 17:23:53 +00:00
|
|
|
if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN)) {
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Write error: Could not reset position - %s", WindowsErrorString());
|
2017-01-04 17:23:53 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2016-03-04 16:34:50 +00:00
|
|
|
} else {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_WRITE_FAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2017-02-14 12:44:25 +00:00
|
|
|
Sleep(200);
|
2016-03-04 16:34:50 +00:00
|
|
|
}
|
2018-06-13 18:23:24 +00:00
|
|
|
if (i > WRITE_RETRIES)
|
|
|
|
goto out;
|
2016-03-04 16:34:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
RefreshDriveLayout(hPhysicalDrive);
|
|
|
|
ret = TRUE;
|
|
|
|
out:
|
2016-06-10 11:42:43 +00:00
|
|
|
safe_mm_free(buffer);
|
2018-07-06 11:35:22 +00:00
|
|
|
safe_mm_free(cmp_buffer);
|
2016-03-04 16:34:50 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-12-01 17:20:52 +00:00
|
|
|
/*
|
|
|
|
* Standalone thread for the formatting operation
|
2013-04-07 23:10:58 +00:00
|
|
|
* According to http://msdn.microsoft.com/en-us/library/windows/desktop/aa364562.aspx
|
|
|
|
* To change a volume file system
|
|
|
|
* Open a volume.
|
|
|
|
* Lock the volume.
|
|
|
|
* Format the volume.
|
|
|
|
* Dismount the volume.
|
|
|
|
* Unlock the volume.
|
|
|
|
* Close the volume handle.
|
2011-12-01 17:20:52 +00:00
|
|
|
*/
|
2014-02-09 02:54:07 +00:00
|
|
|
DWORD WINAPI FormatThread(void* param)
|
2011-12-01 17:20:52 +00:00
|
|
|
{
|
2018-03-22 23:14:20 +00:00
|
|
|
int i, r;
|
2016-03-04 16:34:50 +00:00
|
|
|
BOOL ret, use_large_fat32, windows_to_go;
|
|
|
|
DWORD DriveIndex = (DWORD)(uintptr_t)param;
|
2011-12-01 17:20:52 +00:00
|
|
|
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
|
|
|
|
HANDLE hLogicalVolume = INVALID_HANDLE_VALUE;
|
2014-02-09 02:54:07 +00:00
|
|
|
HANDLE hSourceImage = INVALID_HANDLE_VALUE;
|
2011-12-30 21:23:13 +00:00
|
|
|
SYSTEMTIME lt;
|
2014-02-09 02:54:07 +00:00
|
|
|
FILE* log_fd;
|
2016-03-04 16:34:50 +00:00
|
|
|
uint8_t *buffer = NULL, extra_partitions = 0;
|
2015-01-16 01:51:24 +00:00
|
|
|
char *bb_msg, *guid_volume = NULL;
|
2012-02-05 19:54:48 +00:00
|
|
|
char drive_name[] = "?:\\";
|
2016-03-04 16:34:50 +00:00
|
|
|
char drive_letters[27], fs_type[32];
|
2015-01-16 01:51:24 +00:00
|
|
|
char logfile[MAX_PATH], *userdir;
|
2013-01-19 04:04:54 +00:00
|
|
|
char efi_dst[] = "?:\\efi\\boot\\bootx64.efi";
|
2014-05-15 20:17:12 +00:00
|
|
|
char kolibri_dst[] = "?:\\MTLD_F32";
|
2014-11-14 23:40:00 +00:00
|
|
|
char grub4dos_dst[] = "?:\\grldr";
|
2015-10-18 20:31:47 +00:00
|
|
|
|
2013-09-22 02:28:56 +00:00
|
|
|
use_large_fat32 = (fs == FS_FAT32) && ((SelectedDrive.DiskSize > LARGE_FAT32_SIZE) || (force_large_fat32));
|
2018-07-05 23:40:52 +00:00
|
|
|
windows_to_go = (image_options & IMOP_WINTOGO) && (bt == BT_IMAGE) && HAS_WINTOGO(img_report) &&
|
2018-03-22 23:14:20 +00:00
|
|
|
(ComboBox_GetCurSel(GetDlgItem(hMainDialog, IDC_IMAGE_OPTION)) == 1);
|
2016-09-06 16:56:36 +00:00
|
|
|
large_drive = (SelectedDrive.DiskSize > (1*TB));
|
|
|
|
if (large_drive)
|
|
|
|
uprintf("Notice: Large drive detected (may produce short writes)");
|
2015-01-20 02:56:17 +00:00
|
|
|
// Find out if we need to add any extra partitions
|
2018-04-16 15:05:23 +00:00
|
|
|
if ((windows_to_go) && (tt == TT_UEFI) && (pt == PARTITION_STYLE_GPT))
|
2015-01-20 02:56:17 +00:00
|
|
|
// According to Microsoft, every GPT disk (we RUN Windows from) must have an MSR due to not having hidden sectors
|
|
|
|
// http://msdn.microsoft.com/en-us/library/windows/hardware/dn640535.aspx#gpt_faq_what_disk_require_msr
|
|
|
|
extra_partitions = XP_MSR | XP_EFI;
|
2015-07-01 20:26:15 +00:00
|
|
|
else if ( (fs == FS_NTFS) && ((bt == BT_UEFI_NTFS) ||
|
2018-03-22 23:14:20 +00:00
|
|
|
((bt == BT_IMAGE) && IS_EFI_BOOTABLE(img_report) && ((tt == TT_UEFI) || (windows_to_go) || (allow_dual_uefi_bios)))) )
|
2015-03-16 20:34:04 +00:00
|
|
|
extra_partitions = XP_UEFI_NTFS;
|
2018-03-22 23:14:20 +00:00
|
|
|
else if (IsChecked(IDC_OLD_BIOS_FIXES))
|
2015-01-20 21:50:24 +00:00
|
|
|
extra_partitions = XP_COMPAT;
|
2013-01-20 22:46:11 +00:00
|
|
|
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_225);
|
2018-11-28 10:50:00 +00:00
|
|
|
hPhysicalDrive = GetPhysicalHandle(DriveIndex, lock_drive, FALSE, !lock_drive);
|
2011-12-01 17:20:52 +00:00
|
|
|
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
|
|
|
|
2018-11-28 10:50:00 +00:00
|
|
|
// At this stage we have both a handle and a lock to the physical drive
|
2014-01-14 20:17:07 +00:00
|
|
|
if (!GetDriveLetters(DriveIndex, drive_letters)) {
|
2013-11-14 01:21:50 +00:00
|
|
|
uprintf("Failed to get a drive letter\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER);
|
|
|
|
goto out;
|
|
|
|
}
|
2014-01-14 20:17:07 +00:00
|
|
|
if (drive_letters[0] == 0) {
|
2013-04-07 23:10:58 +00:00
|
|
|
uprintf("No drive letter was assigned...\n");
|
|
|
|
drive_name[0] = GetUnusedDriveLetter();
|
2014-01-14 20:17:07 +00:00
|
|
|
if (drive_name[0] == 0) {
|
2013-04-07 23:10:58 +00:00
|
|
|
uprintf("Could not find a suitable drive letter\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER);
|
2013-02-10 21:54:47 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2014-01-14 20:17:07 +00:00
|
|
|
} else {
|
|
|
|
// Unmount all mounted volumes that belong to this drive
|
|
|
|
// Do it in reverse so that we always end on the first volume letter
|
2018-11-28 10:50:00 +00:00
|
|
|
for (i = (int)safe_strlen(drive_letters); i > 0; i--) {
|
2014-01-14 20:17:07 +00:00
|
|
|
drive_name[0] = drive_letters[i-1];
|
2018-03-22 23:14:20 +00:00
|
|
|
if (bt == BT_IMAGE) {
|
2014-08-08 23:10:12 +00:00
|
|
|
// If we are using an image, check that it isn't located on the drive we are trying to format
|
|
|
|
if ((PathGetDriveNumberU(image_path) + 'A') == drive_letters[i-1]) {
|
|
|
|
uprintf("ABORTED: Cannot use an image that is located on the target drive!\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
2014-01-14 20:17:07 +00:00
|
|
|
if (!DeleteVolumeMountPointA(drive_name)) {
|
|
|
|
uprintf("Failed to delete mountpoint %s: %s\n", drive_name, WindowsErrorString());
|
|
|
|
// Try to continue. We will bail out if this causes an issue.
|
|
|
|
}
|
|
|
|
}
|
2013-04-07 23:10:58 +00:00
|
|
|
}
|
2013-06-25 01:55:25 +00:00
|
|
|
uprintf("Will use '%c:' as volume mountpoint\n", drive_name[0]);
|
2013-04-07 23:10:58 +00:00
|
|
|
|
2018-11-28 10:50:00 +00:00
|
|
|
// It kind of blows, but we have to relinquish access to the physical drive
|
|
|
|
// for VDS to be able to delete the partitions that reside on it...
|
|
|
|
safe_unlockclose(hPhysicalDrive);
|
|
|
|
PrintInfoDebug(0, MSG_239);
|
|
|
|
DeletePartitions(DriveIndex);
|
|
|
|
|
|
|
|
// Now get RW access to the physical drive...
|
|
|
|
hPhysicalDrive = GetPhysicalHandle(DriveIndex, lock_drive, TRUE, !lock_drive);
|
|
|
|
if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_OPEN_FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ...and get a lock to the logical drive so that we can actually write something
|
2017-05-03 13:48:24 +00:00
|
|
|
hLogicalVolume = GetLogicalHandle(DriveIndex, TRUE, FALSE, !lock_drive);
|
2013-04-07 23:10:58 +00:00
|
|
|
if (hLogicalVolume == INVALID_HANDLE_VALUE) {
|
|
|
|
uprintf("Could not lock volume\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
|
|
|
goto out;
|
2013-06-25 01:55:25 +00:00
|
|
|
} else if (hLogicalVolume == NULL) {
|
|
|
|
// NULL is returned for cases where the drive is not yet partitioned
|
|
|
|
uprintf("Drive does not appear to be partitioned\n");
|
2013-06-25 17:39:07 +00:00
|
|
|
} else if (!UnmountVolume(hLogicalVolume)) {
|
|
|
|
uprintf("Trying to continue regardless...\n");
|
2011-12-11 02:19:38 +00:00
|
|
|
}
|
2013-06-25 17:39:07 +00:00
|
|
|
CHECK_FOR_USER_CANCEL;
|
2011-12-11 02:19:38 +00:00
|
|
|
|
2018-05-08 19:28:23 +00:00
|
|
|
if (!zero_drive && !write_as_image) {
|
2015-11-04 13:58:19 +00:00
|
|
|
PrintInfoDebug(0, MSG_226);
|
2018-10-03 17:14:40 +00:00
|
|
|
AnalyzeMBR(hPhysicalDrive, "Drive", FALSE);
|
2015-11-04 13:58:19 +00:00
|
|
|
UpdateProgress(OP_ANALYZE_MBR, -1.0f);
|
2013-06-25 01:55:25 +00:00
|
|
|
}
|
2011-12-13 23:29:09 +00:00
|
|
|
|
2016-05-21 15:34:34 +00:00
|
|
|
if (zero_drive) {
|
|
|
|
WriteDrive(hPhysicalDrive, NULL);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2018-11-28 11:12:54 +00:00
|
|
|
// Zap partition records. This helps prevent access errors.
|
2016-05-21 15:34:34 +00:00
|
|
|
// Note, Microsoft's way of cleaning partitions (IOCTL_DISK_CREATE_DISK, which is what we apply
|
|
|
|
// in InitializeDisk) is *NOT ENOUGH* to reset a disk and can render it inoperable for partitioning
|
|
|
|
// or formatting under Windows. See https://github.com/pbatard/rufus/issues/759 for details.
|
2018-05-08 19:28:23 +00:00
|
|
|
if ((bt != BT_IMAGE) || (img_report.is_iso && !write_as_image)) {
|
2016-08-31 11:21:10 +00:00
|
|
|
if ((!ClearMBRGPT(hPhysicalDrive, SelectedDrive.DiskSize, SelectedDrive.SectorSize, use_large_fat32)) ||
|
|
|
|
(!InitializeDisk(hPhysicalDrive))) {
|
|
|
|
uprintf("Could not reset partitions\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_PARTITION_FAILURE;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-07-05 21:20:46 +00:00
|
|
|
}
|
2015-11-04 13:58:19 +00:00
|
|
|
|
2018-03-22 23:14:20 +00:00
|
|
|
if (IsChecked(IDC_BAD_BLOCKS)) {
|
2011-12-11 02:19:38 +00:00
|
|
|
do {
|
2018-06-28 15:25:13 +00:00
|
|
|
int sel = ComboBox_GetCurSel(hNBPasses);
|
2011-12-30 21:23:13 +00:00
|
|
|
// create a log file for bad blocks report. Since %USERPROFILE% may
|
2013-06-25 17:39:07 +00:00
|
|
|
// have localized characters, we use the UTF-8 API.
|
2011-12-30 21:23:13 +00:00
|
|
|
userdir = getenvU("USERPROFILE");
|
2017-08-10 18:43:04 +00:00
|
|
|
static_strcpy(logfile, userdir);
|
2011-12-30 21:23:13 +00:00
|
|
|
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 {
|
2013-06-06 22:40:37 +00:00
|
|
|
fprintf(log_fd, APPLICATION_NAME " bad blocks check started on: %04d.%02d.%02d %02d:%02d:%02d\n",
|
2011-12-30 21:23:13 +00:00
|
|
|
lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond);
|
|
|
|
fflush(log_fd);
|
|
|
|
}
|
|
|
|
|
2018-06-28 15:25:13 +00:00
|
|
|
if (!BadBlocks(hPhysicalDrive, SelectedDrive.DiskSize, (sel >= 2) ? 4 : sel +1,
|
|
|
|
(sel < 2) ? 0 : sel - 2, &report, log_fd)) {
|
2012-03-03 22:59:58 +00:00
|
|
|
uprintf("Bad blocks: Check failed.\n");
|
2013-06-25 17:39:07 +00:00
|
|
|
if (!IS_ERROR(FormatStatus))
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_BADBLOCKS_FAILURE);
|
2016-05-23 11:19:11 +00:00
|
|
|
ClearMBRGPT(hPhysicalDrive, SelectedDrive.DiskSize, SelectedDrive.SectorSize, FALSE);
|
2012-03-03 22:59:58 +00:00
|
|
|
fclose(log_fd);
|
[net] add Windows retail ISO downloads
* This is accomplished through Fido (https://github.com/pbatard/Fido), a *SIGNED*
PowerShell script, that is downloaded from GitHub and that resides in memory for
the duration of a session.
* The reason we use a downloaded PS script, rather than an embedded on, is because:
- Microsoft have regularly been changing the deal with regards to how retail ISOs
can be downloaded, and not for the better, so we can't simply embed a static
means of downloading ISOs and expect that to work forever.
- By using an external script, we can immediately respond to whatever new means of
*ANNOYING* their legitimate users Microsoft will come up with next, as well as
make sure that, the minute a new retail version of Windows becomes available, it
also becomes available for download in Rufus.
* Note that if you are concerned about downloading a remote PS script that is being
run at the same level as an elevated application, you should understand that:
- Only scripts downloaded from GitHub, from an account that is protected with 2FA,
are allowed to run (i.e. someone would first have to steal a *physical* 2FA key
to be in a position to upload a malicious script).
- On top of this, only scripts that are signed with a separate private key (RSA +
AES-256), that is itself also protected with a strong unique password which only
a single person knows (and must manually enter each time they want to make a new
version of the script available for download), are allowed to run.
The above means that there's about as much chance for someone to manage to upload
a malicious script on the GitHub servers, that Rufus would allow to run, as there
is for someone to upload a malicious version of Rufus itself.
Still, if you are paranoid and have concerns that, even as you can validate from
its source that Rufus does not attempt to execute any remote script unless a user
actively selected and clicked the DOWNLOAD button, you can also completely disable
the remote script download feature, if you just set the update check to disabled
(which, by the way, Rufus *EXPLICITLY* asks you to choose whether you want to
enable or not, the very first time you run the application).
* Also remove _unlinkU() which duplicates what DeleteFileU() already does.
2019-03-02 23:28:56 +00:00
|
|
|
DeleteFileU(logfile);
|
2011-12-09 01:39:13 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2014-03-29 00:42:49 +00:00
|
|
|
uprintf("Bad Blocks: Check completed, %d 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) {
|
2014-03-29 00:42:49 +00:00
|
|
|
bb_msg = lmprintf(MSG_011, report.bb_count, report.num_read_errors, report.num_write_errors,
|
2011-12-11 02:19:38 +00:00
|
|
|
report.num_corruption_errors);
|
2013-10-15 21:58:27 +00:00
|
|
|
fprintf(log_fd, bb_msg);
|
2012-03-03 22:59:58 +00:00
|
|
|
GetLocalTime(<);
|
2013-06-06 22:40:37 +00:00
|
|
|
fprintf(log_fd, APPLICATION_NAME " bad blocks check ended on: %04d.%02d.%02d %02d:%02d:%02d\n",
|
2012-03-03 22:59:58 +00:00
|
|
|
lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond);
|
2011-12-30 21:23:13 +00:00
|
|
|
fclose(log_fd);
|
2015-10-18 20:31:47 +00:00
|
|
|
r = MessageBoxExU(hMainDialog, lmprintf(MSG_012, bb_msg, logfile),
|
|
|
|
lmprintf(MSG_010), MB_ABORTRETRYIGNORE|MB_ICONWARNING|MB_IS_RTL, selected_langid);
|
2011-12-30 21:23:13 +00:00
|
|
|
} else {
|
|
|
|
// We didn't get any errors => delete the log file
|
|
|
|
fclose(log_fd);
|
[net] add Windows retail ISO downloads
* This is accomplished through Fido (https://github.com/pbatard/Fido), a *SIGNED*
PowerShell script, that is downloaded from GitHub and that resides in memory for
the duration of a session.
* The reason we use a downloaded PS script, rather than an embedded on, is because:
- Microsoft have regularly been changing the deal with regards to how retail ISOs
can be downloaded, and not for the better, so we can't simply embed a static
means of downloading ISOs and expect that to work forever.
- By using an external script, we can immediately respond to whatever new means of
*ANNOYING* their legitimate users Microsoft will come up with next, as well as
make sure that, the minute a new retail version of Windows becomes available, it
also becomes available for download in Rufus.
* Note that if you are concerned about downloading a remote PS script that is being
run at the same level as an elevated application, you should understand that:
- Only scripts downloaded from GitHub, from an account that is protected with 2FA,
are allowed to run (i.e. someone would first have to steal a *physical* 2FA key
to be in a position to upload a malicious script).
- On top of this, only scripts that are signed with a separate private key (RSA +
AES-256), that is itself also protected with a strong unique password which only
a single person knows (and must manually enter each time they want to make a new
version of the script available for download), are allowed to run.
The above means that there's about as much chance for someone to manage to upload
a malicious script on the GitHub servers, that Rufus would allow to run, as there
is for someone to upload a malicious version of Rufus itself.
Still, if you are paranoid and have concerns that, even as you can validate from
its source that Rufus does not attempt to execute any remote script unless a user
actively selected and clicked the DOWNLOAD button, you can also completely disable
the remote script download feature, if you just set the update check to disabled
(which, by the way, Rufus *EXPLICITLY* asks you to choose whether you want to
enable or not, the very first time you run the application).
* Also remove _unlinkU() which duplicates what DeleteFileU() already does.
2019-03-02 23:28:56 +00:00
|
|
|
DeleteFileU(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
|
|
|
}
|
2014-02-09 02:54:07 +00:00
|
|
|
|
2016-05-21 15:34:34 +00:00
|
|
|
// Especially after destructive badblocks test, you must zero the MBR/GPT completely
|
|
|
|
// before repartitioning. Else, all kind of bad things happen.
|
2016-05-23 11:19:11 +00:00
|
|
|
if (!ClearMBRGPT(hPhysicalDrive, SelectedDrive.DiskSize, SelectedDrive.SectorSize, use_large_fat32)) {
|
2016-05-21 15:34:34 +00:00
|
|
|
uprintf("unable to zero MBR/GPT\n");
|
|
|
|
if (!IS_ERROR(FormatStatus))
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2014-08-07 00:45:46 +00:00
|
|
|
}
|
|
|
|
|
2014-02-09 02:54:07 +00:00
|
|
|
// Write an image file
|
2018-03-22 23:14:20 +00:00
|
|
|
if ((bt == BT_IMAGE) && write_as_image) {
|
2014-11-11 19:17:39 +00:00
|
|
|
hSourceImage = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
|
|
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
2014-02-09 02:54:07 +00:00
|
|
|
if (hSourceImage == INVALID_HANDLE_VALUE) {
|
2014-05-22 00:52:25 +00:00
|
|
|
uprintf("Could not open image '%s': %s", image_path, WindowsErrorString());
|
2014-02-09 02:54:07 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
2014-12-29 20:34:41 +00:00
|
|
|
|
2016-03-04 16:34:50 +00:00
|
|
|
WriteDrive(hPhysicalDrive, hSourceImage);
|
2014-08-07 00:45:46 +00:00
|
|
|
|
|
|
|
// If the image contains a partition we might be able to access, try to re-mount it
|
|
|
|
safe_unlockclose(hPhysicalDrive);
|
|
|
|
safe_unlockclose(hLogicalVolume);
|
|
|
|
Sleep(200);
|
|
|
|
WaitForLogical(DriveIndex);
|
|
|
|
if (GetDrivePartitionData(SelectedDrive.DeviceNumber, fs_type, sizeof(fs_type), TRUE)) {
|
|
|
|
guid_volume = GetLogicalName(DriveIndex, TRUE, TRUE);
|
|
|
|
if ((guid_volume != NULL) && (MountVolume(drive_name, guid_volume)))
|
|
|
|
uprintf("Remounted %s on %s\n", guid_volume, drive_name);
|
|
|
|
}
|
2014-02-09 02:54:07 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2014-08-07 00:45:46 +00:00
|
|
|
UpdateProgress(OP_ZERO_MBR, -1.0f);
|
|
|
|
CHECK_FOR_USER_CANCEL;
|
|
|
|
|
2018-04-16 15:05:23 +00:00
|
|
|
if (!CreatePartition(hPhysicalDrive, pt, fs, (pt==PARTITION_STYLE_MBR) && (tt==TT_UEFI), extra_partitions)) {
|
2014-08-07 00:45:46 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
UpdateProgress(OP_PARTITION, -1.0f);
|
|
|
|
|
2013-06-25 17:39:07 +00:00
|
|
|
// Close the (unmounted) volume before formatting
|
2013-07-05 21:20:46 +00:00
|
|
|
if ((hLogicalVolume != NULL) && (hLogicalVolume != INVALID_HANDLE_VALUE)) {
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_227);
|
2013-06-25 01:55:25 +00:00
|
|
|
if (!CloseHandle(hLogicalVolume)) {
|
|
|
|
uprintf("Could not close volume: %s\n", WindowsErrorString());
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
|
|
|
|
goto out;
|
|
|
|
}
|
2013-04-07 23:10:58 +00:00
|
|
|
}
|
|
|
|
hLogicalVolume = INVALID_HANDLE_VALUE;
|
|
|
|
|
2013-06-25 17:39:07 +00:00
|
|
|
// Wait for the logical drive we just created to appear
|
|
|
|
uprintf("Waiting for logical drive to reappear...\n");
|
|
|
|
Sleep(200);
|
2014-12-21 01:56:36 +00:00
|
|
|
if (!WaitForLogical(DriveIndex))
|
|
|
|
uprintf("Logical drive was not found!"); // We try to continue even if this fails, just in case
|
2013-06-25 17:39:07 +00:00
|
|
|
CHECK_FOR_USER_CANCEL;
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2015-10-18 20:31:47 +00:00
|
|
|
// If FAT32 is requested and we have a large drive (>32 GB) use
|
2012-11-03 17:40:33 +00:00
|
|
|
// large FAT32 format, else use MS's FormatEx.
|
2013-09-22 02:28:56 +00:00
|
|
|
ret = use_large_fat32?FormatFAT32(DriveIndex):FormatDrive(DriveIndex);
|
2012-11-03 17:40:33 +00:00
|
|
|
if (!ret) {
|
2011-12-01 17:20:52 +00:00
|
|
|
// Error will be set by FormatDrive() in FormatStatus
|
2013-12-19 23:56:40 +00:00
|
|
|
uprintf("Format error: %s\n", StrError(FormatStatus, TRUE));
|
2011-12-01 17:20:52 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2013-06-25 17:39:07 +00:00
|
|
|
// Thanks to Microsoft, we must fix the MBR AFTER the drive has been formatted
|
2019-03-16 13:01:55 +00:00
|
|
|
if ((pt == PARTITION_STYLE_MBR) || ((bt != BT_NON_BOOTABLE) && (pt == PARTITION_STYLE_GPT))) {
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_228); // "Writing master boot record..."
|
2014-11-17 23:41:46 +00:00
|
|
|
if ((!WriteMBR(hPhysicalDrive)) || (!WriteSBR(hPhysicalDrive))) {
|
2013-06-25 17:39:07 +00:00
|
|
|
if (!IS_ERROR(FormatStatus))
|
2013-01-18 01:39:24 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
UpdateProgress(OP_FIX_MBR, -1.0f);
|
2011-12-01 17:20:52 +00:00
|
|
|
}
|
2013-06-25 17:39:07 +00:00
|
|
|
Sleep(200);
|
|
|
|
WaitForLogical(DriveIndex);
|
|
|
|
// Try to continue
|
|
|
|
CHECK_FOR_USER_CANCEL;
|
|
|
|
|
|
|
|
guid_volume = GetLogicalName(DriveIndex, TRUE, TRUE);
|
|
|
|
if (guid_volume == NULL) {
|
|
|
|
uprintf("Could not get GUID volume name\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_VOLUME_ID;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
uprintf("Found volume GUID %s\n", guid_volume);
|
2011-12-01 17:20:52 +00:00
|
|
|
|
2013-06-25 01:55:25 +00:00
|
|
|
if (!MountVolume(drive_name, guid_volume)) {
|
2013-04-07 23:10:58 +00:00
|
|
|
uprintf("Could not remount %s on %s: %s\n", guid_volume, drive_name, WindowsErrorString());
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_MOUNT_VOLUME);
|
|
|
|
goto out;
|
|
|
|
}
|
2013-06-25 17:39:07 +00:00
|
|
|
CHECK_FOR_USER_CANCEL;
|
2013-04-07 23:10:58 +00:00
|
|
|
|
2018-04-19 15:02:07 +00:00
|
|
|
// Disable file indexing, unless it was force-enabled by the user
|
|
|
|
if ((!enable_file_indexing) && ((fs == FS_NTFS) || (fs == FS_UDF) || (fs == FS_REFS))) {
|
|
|
|
uprintf("Disabling file indexing...");
|
|
|
|
if (!SetFileAttributesA(guid_volume, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED))
|
2016-08-27 17:04:54 +00:00
|
|
|
uprintf("Could not disable file indexing: %s", WindowsErrorString());
|
2018-04-19 15:02:07 +00:00
|
|
|
}
|
2016-08-27 17:04:54 +00:00
|
|
|
|
2016-06-26 20:24:16 +00:00
|
|
|
// Refresh the drive label - This is needed as Windows may have altered it from
|
|
|
|
// the name we proposed, and we require an exact label, to patch config files.
|
|
|
|
if (!GetVolumeInformationU(drive_name, img_report.usb_label, ARRAYSIZE(img_report.usb_label),
|
|
|
|
NULL, NULL, NULL, NULL, 0)) {
|
|
|
|
uprintf("Warning: Failed to refresh label: %s", WindowsErrorString());
|
|
|
|
}
|
|
|
|
|
2018-03-22 23:14:20 +00:00
|
|
|
if (bt != BT_NON_BOOTABLE) {
|
2015-07-01 20:26:15 +00:00
|
|
|
if (bt == BT_UEFI_NTFS) {
|
2015-03-18 21:34:28 +00:00
|
|
|
// All good
|
2015-07-01 20:26:15 +00:00
|
|
|
} else if (tt == TT_UEFI) {
|
2013-01-18 01:39:24 +00:00
|
|
|
// For once, no need to do anything - just check our sanity
|
2018-06-30 21:45:15 +00:00
|
|
|
assert((bt == BT_IMAGE) && IS_EFI_BOOTABLE(img_report) && (fs <= FS_NTFS));
|
2018-03-22 23:14:20 +00:00
|
|
|
if ( (bt != BT_IMAGE) || !IS_EFI_BOOTABLE(img_report) || (fs > FS_NTFS) ) {
|
2013-01-18 01:39:24 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE;
|
|
|
|
goto out;
|
|
|
|
}
|
2015-07-01 20:26:15 +00:00
|
|
|
} else if ( (bt == BT_SYSLINUX_V4) || (bt == BT_SYSLINUX_V6) ||
|
2018-03-22 23:14:20 +00:00
|
|
|
((bt == BT_IMAGE) && (HAS_SYSLINUX(img_report) || HAS_REACTOS(img_report)) &&
|
2016-12-15 16:28:00 +00:00
|
|
|
(!HAS_WINDOWS(img_report) || !allow_dual_uefi_bios)) ) {
|
2015-02-25 01:45:47 +00:00
|
|
|
if (!InstallSyslinux(DriveIndex, drive_name[0], fs)) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE;
|
2017-02-16 14:13:30 +00:00
|
|
|
goto out;
|
2015-02-25 01:45:47 +00:00
|
|
|
}
|
|
|
|
} else {
|
2015-10-18 20:31:47 +00:00
|
|
|
// We still have a lock, which we need to modify the volume boot record
|
2012-01-12 02:52:40 +00:00
|
|
|
// => no need to reacquire the lock...
|
2017-04-08 20:58:10 +00:00
|
|
|
hLogicalVolume = GetLogicalHandle(DriveIndex, FALSE, TRUE, FALSE);
|
2013-06-25 01:55:25 +00:00
|
|
|
if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL)) {
|
2012-01-12 02:52:40 +00:00
|
|
|
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
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_229);
|
2012-02-14 01:23:42 +00:00
|
|
|
if (!WritePBR(hLogicalVolume)) {
|
2013-06-25 17:39:07 +00:00
|
|
|
if (!IS_ERROR(FormatStatus))
|
2012-02-14 01:23:42 +00:00
|
|
|
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);
|
2011-12-01 17:20:52 +00:00
|
|
|
}
|
2012-02-21 19:46:28 +00:00
|
|
|
} else {
|
2018-03-22 23:14:20 +00:00
|
|
|
if (IsChecked(IDC_EXTENDED_LABEL))
|
2012-02-21 19:46:28 +00:00
|
|
|
SetAutorun(drive_name);
|
2011-12-01 17:20:52 +00:00
|
|
|
}
|
2013-06-25 17:39:07 +00:00
|
|
|
CHECK_FOR_USER_CANCEL;
|
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
|
2013-06-25 01:55:25 +00:00
|
|
|
if (!RemountVolume(drive_name))
|
2012-02-21 00:08:31 +00:00
|
|
|
goto out;
|
2013-06-25 17:39:07 +00:00
|
|
|
CHECK_FOR_USER_CANCEL;
|
2012-02-14 01:23:42 +00:00
|
|
|
|
2018-03-22 23:14:20 +00:00
|
|
|
if (bt != BT_NON_BOOTABLE) {
|
2015-07-01 20:26:15 +00:00
|
|
|
if ((bt == BT_MSDOS) || (bt == BT_FREEDOS)) {
|
2012-03-29 19:27:53 +00:00
|
|
|
UpdateProgress(OP_DOS, -1.0f);
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_230);
|
2012-02-14 01:23:42 +00:00
|
|
|
if (!ExtractDOS(drive_name)) {
|
2013-06-25 17:39:07 +00:00
|
|
|
if (!IS_ERROR(FormatStatus))
|
2012-02-14 01:23:42 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY;
|
|
|
|
goto out;
|
|
|
|
}
|
2015-07-01 20:26:15 +00:00
|
|
|
} else if (bt == BT_GRUB4DOS) {
|
2014-11-14 23:40:00 +00:00
|
|
|
grub4dos_dst[0] = drive_name[0];
|
|
|
|
IGNORE_RETVAL(_chdirU(app_dir));
|
2016-05-25 11:20:20 +00:00
|
|
|
uprintf("Installing: %s (Grub4DOS loader) %s\n", grub4dos_dst,
|
|
|
|
IsFileInDB(FILES_DIR "\\grub4dos-" GRUB4DOS_VERSION "\\grldr")?"✓":"✗");
|
2015-02-16 22:29:23 +00:00
|
|
|
if (!CopyFileU(FILES_DIR "\\grub4dos-" GRUB4DOS_VERSION "\\grldr", grub4dos_dst, FALSE))
|
2014-11-14 23:40:00 +00:00
|
|
|
uprintf("Failed to copy file: %s", WindowsErrorString());
|
2018-03-22 23:14:20 +00:00
|
|
|
} else if ((bt == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso)) {
|
2015-01-20 21:50:24 +00:00
|
|
|
UpdateProgress(OP_DOS, 0.0f);
|
|
|
|
drive_name[2] = 0; // Ensure our drive is something like 'D:'
|
|
|
|
if (windows_to_go) {
|
|
|
|
PrintInfoDebug(0, MSG_268);
|
|
|
|
if (!SetupWinToGo(drive_name, (extra_partitions & XP_EFI))) {
|
|
|
|
if (!IS_ERROR(FormatStatus))
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_231);
|
2015-01-20 21:50:24 +00:00
|
|
|
if (!ExtractISO(image_path, drive_name, FALSE)) {
|
2013-06-25 17:39:07 +00:00
|
|
|
if (!IS_ERROR(FormatStatus))
|
2015-01-19 01:23:32 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
|
2012-02-14 01:23:42 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2016-12-14 23:27:04 +00:00
|
|
|
if (HAS_KOLIBRIOS(img_report)) {
|
2014-05-15 20:17:12 +00:00
|
|
|
kolibri_dst[0] = drive_name[0];
|
|
|
|
uprintf("Installing: %s (KolibriOS loader)\n", kolibri_dst);
|
2014-05-22 00:52:25 +00:00
|
|
|
if (ExtractISOFile(image_path, "HD_Load/USB_Boot/MTLD_F32", kolibri_dst,
|
2014-05-15 20:17:12 +00:00
|
|
|
FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM) == 0) {
|
|
|
|
uprintf("Warning: loader installation failed - KolibriOS will not boot!\n");
|
|
|
|
}
|
|
|
|
}
|
2015-03-11 21:45:06 +00:00
|
|
|
// EFI mode selected, with no 'boot###.efi' but Windows 7 x64's 'bootmgr.efi' (bit #0)
|
2019-03-27 12:21:41 +00:00
|
|
|
if (((tt == TT_UEFI) || allow_dual_uefi_bios) && HAS_WIN7_EFI(img_report)) {
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_232);
|
2019-01-08 18:30:07 +00:00
|
|
|
img_report.wininst_path[0][0] = drive_name[0];
|
2013-01-19 04:04:54 +00:00
|
|
|
efi_dst[0] = drive_name[0];
|
|
|
|
efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = 0;
|
|
|
|
if (!CreateDirectoryA(efi_dst, 0)) {
|
2017-08-09 15:27:11 +00:00
|
|
|
uprintf("Could not create directory '%s': %s\n", efi_dst, WindowsErrorString());
|
2013-01-19 04:04:54 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH);
|
|
|
|
} else {
|
|
|
|
efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = '\\';
|
2019-01-08 18:30:07 +00:00
|
|
|
if (!WimExtractFile(img_report.wininst_path[0], 1, "Windows\\Boot\\EFI\\bootmgfw.efi", efi_dst)) {
|
2013-01-19 04:04:54 +00:00
|
|
|
uprintf("Failed to setup Win7 EFI boot\n");
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-14 23:27:04 +00:00
|
|
|
if ( (tt == TT_BIOS) && HAS_WINPE(img_report) ) {
|
2015-01-20 21:50:24 +00:00
|
|
|
// Apply WinPe fixup
|
|
|
|
if (!SetupWinPE(drive_name[0]))
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH);
|
|
|
|
}
|
2012-03-16 18:30:44 +00:00
|
|
|
}
|
2012-02-05 19:54:48 +00:00
|
|
|
}
|
2012-03-29 19:27:53 +00:00
|
|
|
UpdateProgress(OP_FINALIZE, -1.0f);
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_233);
|
2018-03-22 23:14:20 +00:00
|
|
|
if (IsChecked(IDC_EXTENDED_LABEL))
|
2012-02-21 19:46:28 +00:00
|
|
|
SetAutorun(drive_name);
|
2012-02-21 00:08:31 +00:00
|
|
|
// Issue another complete remount before we exit, to ensure we're clean
|
2013-06-25 01:55:25 +00:00
|
|
|
RemountVolume(drive_name);
|
2012-03-09 01:38:52 +00:00
|
|
|
// NTFS fixup (WinPE/AIK images don't seem to boot without an extra checkdisk)
|
2018-03-22 23:14:20 +00:00
|
|
|
if ((bt == BT_IMAGE) && (img_report.is_iso) && (fs == FS_NTFS)) {
|
2013-12-28 01:27:09 +00:00
|
|
|
// Try to ensure that all messages from Checkdisk will be in English
|
2017-11-13 14:29:48 +00:00
|
|
|
if (PRIMARYLANGID(GetThreadUILanguage()) != LANG_ENGLISH) {
|
|
|
|
SetThreadUILanguage(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US));
|
|
|
|
if (PRIMARYLANGID(GetThreadUILanguage()) != LANG_ENGLISH)
|
2013-12-28 01:27:09 +00:00
|
|
|
uprintf("Note: CheckDisk messages may be localized");
|
|
|
|
}
|
2012-03-09 01:38:52 +00:00
|
|
|
CheckDisk(drive_name[0]);
|
2012-03-29 19:27:53 +00:00
|
|
|
UpdateProgress(OP_FINALIZE, -1.0f);
|
|
|
|
}
|
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:
|
2015-11-04 13:58:19 +00:00
|
|
|
zero_drive = FALSE;
|
2013-04-07 23:10:58 +00:00
|
|
|
safe_free(guid_volume);
|
2014-02-17 22:41:04 +00:00
|
|
|
safe_free(buffer);
|
2014-02-09 23:38:16 +00:00
|
|
|
safe_closehandle(hSourceImage);
|
2011-12-01 17:20:52 +00:00
|
|
|
safe_unlockclose(hLogicalVolume);
|
2013-04-07 23:10:58 +00:00
|
|
|
safe_unlockclose(hPhysicalDrive); // This can take a while
|
2014-01-05 19:54:19 +00:00
|
|
|
if (IS_ERROR(FormatStatus)) {
|
|
|
|
guid_volume = GetLogicalName(DriveIndex, TRUE, FALSE);
|
|
|
|
if (guid_volume != NULL) {
|
|
|
|
if (MountVolume(drive_name, guid_volume))
|
|
|
|
uprintf("Re-mounted volume as '%c:' after error\n", drive_name[0]);
|
|
|
|
free(guid_volume);
|
|
|
|
}
|
|
|
|
}
|
2015-06-29 22:43:49 +00:00
|
|
|
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)TRUE, 0);
|
2012-02-07 02:05:58 +00:00
|
|
|
ExitThread(0);
|
2011-12-01 17:20:52 +00:00
|
|
|
}
|
2014-05-23 00:03:01 +00:00
|
|
|
|
|
|
|
DWORD WINAPI SaveImageThread(void* param)
|
|
|
|
{
|
|
|
|
BOOL s;
|
2015-06-07 21:51:54 +00:00
|
|
|
DWORD rSize, wSize;
|
2016-12-06 11:47:19 +00:00
|
|
|
IMG_SAVE *img_save = (IMG_SAVE*)param;
|
2014-05-23 00:03:01 +00:00
|
|
|
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
|
|
|
|
HANDLE hDestImage = INVALID_HANDLE_VALUE;
|
|
|
|
LARGE_INTEGER li;
|
|
|
|
uint8_t *buffer = NULL;
|
|
|
|
uint64_t wb;
|
|
|
|
int i;
|
|
|
|
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfoDebug(0, MSG_225);
|
2014-12-29 20:34:41 +00:00
|
|
|
LastRefresh = 0;
|
2016-12-06 11:47:19 +00:00
|
|
|
switch (img_save->Type) {
|
|
|
|
case IMG_SAVE_TYPE_VHD:
|
2017-05-01 23:56:07 +00:00
|
|
|
hPhysicalDrive = GetPhysicalHandle(img_save->DeviceNum, TRUE, FALSE, FALSE);
|
2016-12-06 11:47:19 +00:00
|
|
|
break;
|
|
|
|
case IMG_SAVE_TYPE_ISO:
|
|
|
|
hPhysicalDrive = CreateFileA(img_save->DevicePath, GENERIC_READ, FILE_SHARE_READ,
|
|
|
|
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
|
|
|
break;
|
|
|
|
default:
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Invalid image type");
|
2016-12-06 11:47:19 +00:00
|
|
|
}
|
2014-05-23 00:03:01 +00:00
|
|
|
if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write an image file
|
2016-12-06 11:47:19 +00:00
|
|
|
// We may have poked the MBR and other stuff, so need to rewind
|
2014-05-23 00:03:01 +00:00
|
|
|
li.QuadPart = 0;
|
|
|
|
if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN))
|
|
|
|
uprintf("Warning: Unable to rewind device position - wrong data might be copied!");
|
2016-12-06 11:47:19 +00:00
|
|
|
hDestImage = CreateFileU(img_save->ImagePath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
|
2014-11-11 19:17:39 +00:00
|
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
2014-05-23 00:03:01 +00:00
|
|
|
if (hDestImage == INVALID_HANDLE_VALUE) {
|
2016-12-06 11:47:19 +00:00
|
|
|
uprintf("Could not open image '%s': %s", img_save->ImagePath, WindowsErrorString());
|
2014-05-23 00:03:01 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:47:19 +00:00
|
|
|
buffer = (uint8_t*)_mm_malloc(img_save->BufSize, 16);
|
2014-05-23 00:03:01 +00:00
|
|
|
if (buffer == NULL) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
uprintf("could not allocate buffer");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2016-12-06 11:47:19 +00:00
|
|
|
uprintf("Will use a buffer size of %s", SizeToHumanReadable(img_save->BufSize, FALSE, FALSE));
|
|
|
|
uprintf("Saving to image '%s'...", img_save->ImagePath);
|
|
|
|
|
2014-05-23 00:03:01 +00:00
|
|
|
// Don't bother trying for something clever, using double buffering overlapped and whatnot:
|
|
|
|
// With Windows' default optimizations, sync read + sync write for sequential operations
|
|
|
|
// will be as fast, if not faster, than whatever async scheme you can come up with.
|
|
|
|
for (wb = 0; ; wb += wSize) {
|
2016-12-06 11:47:19 +00:00
|
|
|
if (img_save->Type == IMG_SAVE_TYPE_ISO) {
|
|
|
|
// Optical drives do not appear to increment the sectors to read automatically
|
|
|
|
li.QuadPart = wb;
|
|
|
|
if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN))
|
|
|
|
uprintf("Warning: Unable to set device position - wrong data might be copied!");
|
|
|
|
}
|
2015-10-18 20:31:47 +00:00
|
|
|
s = ReadFile(hPhysicalDrive, buffer,
|
2016-12-06 11:47:19 +00:00
|
|
|
(DWORD)MIN(img_save->BufSize, img_save->DeviceSize - wb), &rSize, NULL);
|
2014-05-23 00:03:01 +00:00
|
|
|
if (!s) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_READ_FAULT;
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Read error: %s", WindowsErrorString());
|
2014-05-23 00:03:01 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (rSize == 0)
|
|
|
|
break;
|
2017-11-13 14:29:48 +00:00
|
|
|
if (GetTickCount64() > LastRefresh + MAX_REFRESH) {
|
|
|
|
LastRefresh = GetTickCount64();
|
2016-12-06 11:47:19 +00:00
|
|
|
format_percent = (100.0f*wb)/(1.0f*img_save->DeviceSize);
|
2015-01-01 23:39:28 +00:00
|
|
|
PrintInfo(0, MSG_261, format_percent);
|
2014-05-23 00:03:01 +00:00
|
|
|
UpdateProgress(OP_FORMAT, format_percent);
|
|
|
|
}
|
2018-06-13 18:23:24 +00:00
|
|
|
for (i = 1; i <= WRITE_RETRIES; i++) {
|
2014-05-23 00:03:01 +00:00
|
|
|
CHECK_FOR_USER_CANCEL;
|
|
|
|
s = WriteFile(hDestImage, buffer, rSize, &wSize, NULL);
|
|
|
|
if ((s) && (wSize == rSize))
|
|
|
|
break;
|
|
|
|
if (s)
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Write error: Wrote %d bytes, expected %d bytes", wSize, rSize);
|
2014-05-23 00:03:01 +00:00
|
|
|
else
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Write error: %s", WindowsErrorString());
|
|
|
|
if (i < WRITE_RETRIES) {
|
2014-05-23 00:03:01 +00:00
|
|
|
li.QuadPart = wb;
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000);
|
|
|
|
Sleep(WRITE_TIMEOUT);
|
2017-01-04 17:23:53 +00:00
|
|
|
if (!SetFilePointerEx(hDestImage, li, NULL, FILE_BEGIN)) {
|
2018-06-13 18:23:24 +00:00
|
|
|
uprintf("Write error: Could not reset position - %s", WindowsErrorString());
|
2017-01-04 17:23:53 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2014-05-23 00:03:01 +00:00
|
|
|
} else {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2017-02-14 12:44:25 +00:00
|
|
|
Sleep(200);
|
2014-05-23 00:03:01 +00:00
|
|
|
}
|
2018-06-13 18:23:24 +00:00
|
|
|
if (i > WRITE_RETRIES)
|
|
|
|
goto out;
|
2014-05-23 00:03:01 +00:00
|
|
|
}
|
2016-12-06 11:47:19 +00:00
|
|
|
if (wb != img_save->DeviceSize) {
|
|
|
|
uprintf("Error: wrote %s, expected %s", SizeToHumanReadable(wb, FALSE, FALSE),
|
|
|
|
SizeToHumanReadable(img_save->DeviceSize, FALSE, FALSE));
|
2014-05-23 00:03:01 +00:00
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2016-12-06 11:47:19 +00:00
|
|
|
if (img_save->Type == IMG_SAVE_TYPE_VHD) {
|
|
|
|
uprintf("Appending VHD footer...");
|
|
|
|
if (!AppendVHDFooter(img_save->ImagePath)) {
|
|
|
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2014-05-23 00:03:01 +00:00
|
|
|
}
|
2016-12-06 11:47:19 +00:00
|
|
|
uprintf("Operation complete (Wrote %s).", SizeToHumanReadable(wb, FALSE, FALSE));
|
2014-05-23 00:03:01 +00:00
|
|
|
|
|
|
|
out:
|
2016-12-06 11:47:19 +00:00
|
|
|
safe_free(img_save->ImagePath);
|
2016-06-10 11:42:43 +00:00
|
|
|
safe_mm_free(buffer);
|
2014-05-23 00:03:01 +00:00
|
|
|
safe_closehandle(hDestImage);
|
|
|
|
safe_unlockclose(hPhysicalDrive);
|
2015-06-29 22:43:49 +00:00
|
|
|
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)TRUE, 0);
|
2014-05-23 00:03:01 +00:00
|
|
|
ExitThread(0);
|
|
|
|
}
|