diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc
index b046ca78..4d05a422 100644
--- a/res/localization/rufus.loc
+++ b/res/localization/rufus.loc
@@ -259,9 +259,16 @@ t MSG_093 "IMPORTANT: THIS DRIVE CONTAINS MULTIPLE PARTITIONS!!\n\n"
"Should you wish to proceed, you are responsible for any data loss on these partitions."
t MSG_094 "Multiple partitions detected"
t MSG_095 "DD Image"
-t MSG_096 "Only FAT/FAT32 is supported for this type of ISO. Please select FAT/FAT32 as the File system."
-t MSG_097 "Only 'bootmgr' or 'WinPE' based ISO images can currently be used with NTFS."
-t MSG_098 "FAT/FAT32 can only be used for isolinux based ISO images or when the Target Type is UEFI."
+t MSG_096 "The file system currently selected can not be used with this type of ISO. "
+ "Please select a different file system or use a different ISO."
+t MSG_097 "'Windows To Go' can only be applied if the file system is NTFS."
+t MSG_098 "IMPORTANT: You are trying to install 'Windows To Go', but your USB drive doesn't "
+ "have the 'FIXED' attribute. Because of this Windows will most likely freeze during boot, "
+ "as Microsoft hasn't designed it to work with drives that are 'REMOVABLE'.\n\n"
+ "Do you still want to proceed?\n\n"
+ "Note: the 'FIXED/REMOVABLE' attribute is a hardware property that can only be changed "
+ "using custom tools from the drive manufacturer. However those tools are ALMOST NEVER "
+ "provided to the public..."
t MSG_099 "Filesystem limitation"
t MSG_100 "This ISO image contains a file larger than 4GB, which is more than the "
"maximum size allowed for a FAT or FAT32 file system."
@@ -364,6 +371,7 @@ t MSG_186 "Rufus does not install or run background services, therefore update c
t MSG_187 "Invalid image for selected boot option"
t MSG_188 "The current image doesn't match the boot option selected. Please use a different image or choose a different boot option."
t MSG_189 "This ISO image is not compatible with the selected filesystem"
+t MSG_190 "Incompatible drive detected"
t MSG_191 "Write pass"
t MSG_192 "Read pass"
t MSG_193 "Downloaded %s"
diff --git a/res/togo/san_policy.xml b/res/togo/san_policy.xml
new file mode 100644
index 00000000..b85de4dc
--- /dev/null
+++ b/res/togo/san_policy.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ 4
+
+
+ 4
+
+
+
\ No newline at end of file
diff --git a/res/togo/unattend.xml b/res/togo/unattend.xml
new file mode 100644
index 00000000..0f2847d2
--- /dev/null
+++ b/res/togo/unattend.xml
@@ -0,0 +1,11 @@
+
+
+
+
+ true
+
+
+ true
+
+
+
\ No newline at end of file
diff --git a/src/.msvc/rufus.vcxproj b/src/.msvc/rufus.vcxproj
index 64360b8b..bffa495e 100644
--- a/src/.msvc/rufus.vcxproj
+++ b/src/.msvc/rufus.vcxproj
@@ -223,7 +223,6 @@
-
diff --git a/src/.msvc/rufus.vcxproj.filters b/src/.msvc/rufus.vcxproj.filters
index 7da8b596..ca115177 100644
--- a/src/.msvc/rufus.vcxproj.filters
+++ b/src/.msvc/rufus.vcxproj.filters
@@ -139,9 +139,6 @@
Resource Files
-
- Resource Files
-
diff --git a/src/bled/libbb.h b/src/bled/libbb.h
index fe5e8add..9019e9ed 100644
--- a/src/bled/libbb.h
+++ b/src/bled/libbb.h
@@ -187,6 +187,11 @@ static inline ssize_t full_read(int fd, void *buf, size_t count) {
return rb;
}
+static inline struct tm *localtime_r(const time_t *timep, struct tm *result) {
+ result = localtime(timep);
+ return result;
+}
+
#define full_write _write
#define safe_read full_read
#define lstat stat
@@ -197,11 +202,6 @@ static inline ssize_t full_read(int fd, void *buf, size_t count) {
#define mkdir(x, y) _mkdirU(x)
#if defined(_MSC_VER)
-static inline struct tm *localtime_r(const time_t *timep, struct tm *result) {
- result = localtime(timep);
- return result;
-}
-
#define _S_IFBLK 0x3000
#define S_IFMT _S_IFMT
diff --git a/src/drive.c b/src/drive.c
index 09501210..7e9b9aaf 100644
--- a/src/drive.c
+++ b/src/drive.c
@@ -751,7 +751,7 @@ BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSys
SelectedDrive.nPartitions++;
tmp[0] = 0;
wchar_to_utf8_no_alloc(DriveLayout->PartitionEntry[i].Gpt.Name, tmp, sizeof(tmp));
- suprintf("Partition %d:\r\n Type: %s\r\n Name: '%s'\n", DriveLayout->PartitionEntry[i].PartitionNumber,
+ suprintf("Partition %d:\r\n Type: %s\r\n Name: '%s'\n", i+1,
GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionType), tmp);
suprintf(" ID: %s\r\n Size: %s (%lld bytes)\r\n Start Sector: %lld, Attributes: 0x%016llX\n",
GuidToString(&DriveLayout->PartitionEntry[i].Gpt.PartitionId), SizeToHumanReadable(DriveLayout->PartitionEntry[i].PartitionLength.QuadPart, TRUE, FALSE),
diff --git a/src/format.c b/src/format.c
index 5b675bc1..d4bc27fc 100644
--- a/src/format.c
+++ b/src/format.c
@@ -1225,6 +1225,79 @@ out:
return r;
}
+// http://technet.microsoft.com/en-ie/library/jj721578.aspx
+static BOOL SetupWinToGo(const char* drive_name)
+{
+ char san_policy_path[] = "?:\\san_policy.xml", unattend_path[] = "?:\\Windows\\System32\\sysprep\\unattend.xml";
+ char *mounted_iso, image[128], cmd[128];
+ unsigned char *buffer;
+ DWORD bufsize;
+ FILE* fd;
+
+ uprintf("Windows To Go mode selected");
+
+ // 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;
+ }
+ uprintf("Mounted ISO as '%s'", mounted_iso);
+
+ // Now we use the WIM API to apply that image
+ static_sprintf(image, "%s\\sources\\install.wim", mounted_iso);
+ if (!WimApplyImage(image, 1, drive_name)) {
+ 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();
+
+ uprintf("Setting up boot for Windows To Go...");
+ static_sprintf(cmd, "%C:\\Windows\\System32\\bcdboot.exe %C:\\Windows /f ALL /s %C:",
+ drive_name[0], drive_name[0], drive_name[0]);
+ if (RunCommand(cmd, NULL, TRUE) != 0) {
+ // Fatal, as the UFD is unlikely to boot then
+ uprintf("Command '%s' failed to run", cmd);
+ FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
+ return FALSE;
+ }
+ UpdateProgress(OP_DOS, 99.0f);
+
+ // The following are non fatal if they fail
+ buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_TOGO_SAN_POLICY_XML),
+ _RT_RCDATA, "san_policy.xml", &bufsize, FALSE);
+ san_policy_path[0] = drive_name[0];
+ uprintf("Applying san_policy.xml...");
+ 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);
+ static_sprintf(cmd, "dism /Image:%C:\\ /Apply-Unattend:%s", drive_name[0], san_policy_path);
+ if (RunCommand(cmd, NULL, TRUE) != 0)
+ uprintf("Command '%s' failed to run");
+ }
+
+ uprintf("Copying 'unattend.xml'");
+ 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);
+ UpdateProgress(OP_DOS, 100.0f);
+
+ return TRUE;
+}
+
/*
* Detect if a Windows Format prompt is active, by enumerating the
* whole Windows tree and looking for the relevant popup
@@ -1305,10 +1378,10 @@ DWORD WINAPI FormatThread(void* param)
LARGE_INTEGER li;
uint64_t wb;
uint8_t *buffer = NULL, *aligned_buffer;
- char *bb_msg, *guid_volume = NULL, *mounted_iso;
+ char *bb_msg, *guid_volume = NULL;
char drive_name[] = "?:\\";
char drive_letters[27];
- char logfile[MAX_PATH], image[128], *userdir;
+ char logfile[MAX_PATH], *userdir;
char wim_image[] = "?:\\sources\\install.wim";
char efi_dst[] = "?:\\efi\\boot\\bootx64.efi";
char kolibri_dst[] = "?:\\MTLD_F32";
@@ -1693,28 +1766,24 @@ DWORD WINAPI FormatThread(void* param)
UpdateProgress(OP_DOS, 0.0f);
PrintInfoDebug(0, MSG_231);
drive_name[2] = 0;
- // TODO: Check that we have apply-wim support
if (HAS_TOGO(iso_report) && (Button_GetCheck(GetDlgItem(hMainDialog, IDC_WINDOWS_TO_GO)) == BST_CHECKED)) {
- uprintf("Windows To Go mode selected");
- 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);
- } else {
- uprintf("Mounted ISO as '%s'", mounted_iso);
- static_sprintf(image, "%s\\sources\\install.wim", mounted_iso);
- if (!WimApplyImage(image, 1, drive_name)) {
- uprintf("Failed to setup Windows To Go");
- if (!IS_ERROR(FormatStatus))
- FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT);
- }
- UnMountISO();
- }
- if (IS_ERROR(FormatStatus))
+ // Sanity checks
+ if (fs != FS_NTFS) {
+ FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INCOMPATIBLE_FS);
goto out;
+ }
+ if ((nWindowsVersion < WINDOWS_8) || ((WimExtractCheck() & 4) == 0)) {
+ FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_SUPPORTED;
+ goto out;
+ }
+ if (!SetupWinToGo(drive_name)) {
+ if (!IS_ERROR(FormatStatus))
+ FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ISO_EXTRACT;
+ goto out;
+ }
} else if (!ExtractISO(image_path, drive_name, FALSE)) {
if (!IS_ERROR(FormatStatus))
- FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY;
+ FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ISO_EXTRACT;
goto out;
}
if (iso_report.has_kolibrios) {
diff --git a/src/iso.c b/src/iso.c
index 2d97fd03..9075a8b1 100644
--- a/src/iso.c
+++ b/src/iso.c
@@ -925,8 +925,8 @@ out:
/*
* The following is used for native ISO mounting in Windows 8 or later
*/
-const GUID VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT =
- { 0xEC984AECL, 0xA0F9, 0x47e9, { 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B } };
+#define VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT \
+ { 0xEC984AECL, 0xA0F9, 0x47e9, { 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B } }
typedef enum _VIRTUAL_DISK_ACCESS_MASK {
VIRTUAL_DISK_ACCESS_NONE = 0x00000000,
@@ -1015,7 +1015,7 @@ static HANDLE mounted_handle = INVALID_HANDLE_VALUE;
char* MountISO(const char* path)
{
VIRTUAL_STORAGE_TYPE vtype = { 1, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT };
- ATTACH_VIRTUAL_DISK_PARAMETERS vparams = { ATTACH_VIRTUAL_DISK_VERSION_1, 0 };
+ ATTACH_VIRTUAL_DISK_PARAMETERS vparams = {0};
DWORD r;
wchar_t wtmp[128];
ULONG size = ARRAYSIZE(wtmp);
@@ -1037,6 +1037,7 @@ char* MountISO(const char* path)
goto out;
}
+ vparams.Version = ATTACH_VIRTUAL_DISK_VERSION_1;
r = pfAttachVirtualDisk(mounted_handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY |
ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER, 0, &vparams, NULL);
if (r != ERROR_SUCCESS) {
diff --git a/src/localization.c b/src/localization.c
index a4604a6d..f3586890 100644
--- a/src/localization.c
+++ b/src/localization.c
@@ -407,11 +407,11 @@ char* lmprintf(int msg_id, ...)
#define MSG_INFO 1
#define MSG_LOW_PRI 0
#define MSG_HIGH_PRI 1
-char szMessage[2][2][MSG_LEN] = { 0 };
+char szMessage[2][2][MSG_LEN] = { {"", ""}, {"", ""} };
char* szStatusMessage = szMessage[MSG_STATUS][MSG_HIGH_PRI];
static BOOL bStatusTimerArmed = FALSE;
-static __inline OutputMessage(BOOL info, char* msg)
+static void __inline OutputMessage(BOOL info, char* msg)
{
if (info)
SetWindowTextU(hInfo, msg);
diff --git a/src/msapi_utf8.h b/src/msapi_utf8.h
index 87609fe0..32c0eb57 100644
--- a/src/msapi_utf8.h
+++ b/src/msapi_utf8.h
@@ -506,9 +506,9 @@ static __inline int SHDeleteDirectoryExU(HWND hwnd, const char* pszPath, FILEOP_
// which is always expected to be larger than our UTF-16 one, and add 2 chars for good measure.
size_t wpszPath_len = strlen(pszPath) + 2;
wchar_t* wpszPath = (wchar_t*)calloc(wpszPath_len, sizeof(wchar_t));
+ SHFILEOPSTRUCTW shfo = { hwnd, FO_DELETE, wpszPath, NULL, fFlags, FALSE, NULL, NULL };
utf8_to_wchar_no_alloc(pszPath, wpszPath, wpszPath_len);
// FOF_SILENT | FOF_NOERRORUI | FOF_NOCONFIRMATION,
- SHFILEOPSTRUCTW shfo = { hwnd, FO_DELETE, wpszPath, NULL, fFlags, FALSE, NULL, NULL };
ret = SHFileOperationW(&shfo);
wfree(pszPath);
return ret;
diff --git a/src/resource.h b/src/resource.h
index 1910b489..8b804f88 100644
--- a/src/resource.h
+++ b/src/resource.h
@@ -70,6 +70,8 @@
#define IDR_LC_RUFUS_LOC 500
#define IDR_XT_HOGGER 501
#define IDR_UEFI_TOGO 502
+#define IDR_TOGO_SAN_POLICY_XML 503
+#define IDR_TOGO_UNATTEND_XML 504
#define IDC_DEVICE 1001
#define IDC_FILESYSTEM 1002
#define IDC_START 1003
@@ -411,7 +413,7 @@
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
-#define _APS_NEXT_RESOURCE_VALUE 502
+#define _APS_NEXT_RESOURCE_VALUE 505
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1071
#define _APS_NEXT_SYMED_VALUE 4000
diff --git a/src/rufus.c b/src/rufus.c
index 2d10f341..96ad85d5 100644
--- a/src/rufus.c
+++ b/src/rufus.c
@@ -933,8 +933,11 @@ static void DisplayISOProps(void)
uprintf(" Uses ReactOS: %s", YesNo(IS_REACTOS(iso_report)));
uprintf(" Uses WinPE: %s%s", YesNo(IS_WINPE(iso_report.winpe)), (iso_report.uses_minint) ? " (with /minint)" : "");
- if ( ((!togo_mode) && (HAS_TOGO(iso_report))) || ((togo_mode) && (!HAS_TOGO(iso_report))) )
- ToggleToGo();
+ // We don't support ToGo on Windows 7 or earlier, for lack of ISO mount capabilities
+ // TODO: add install.wim extraction workaround for Windows 7
+ if (nWindowsVersion >= WINDOWS_8)
+ if ( ((!togo_mode) && (HAS_TOGO(iso_report))) || ((togo_mode) && (!HAS_TOGO(iso_report))) )
+ ToggleToGo();
}
// The scanning process can be blocking for message processing => use a thread
@@ -1186,7 +1189,18 @@ static BOOL BootCheck(void)
}
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
- if (bt == BT_UEFI) {
+ if ((togo_mode) && (Button_GetCheck(GetDlgItem(hMainDialog, IDC_WINDOWS_TO_GO)) == BST_CHECKED)) {
+ if (fs != FS_NTFS) {
+ // Windows To Go only works for NTFS
+ MessageBoxU(hMainDialog, lmprintf(MSG_097), lmprintf(MSG_092), MB_OK|MB_ICONERROR|MB_IS_RTL);
+ return FALSE;
+ } else if (SelectedDrive.Geometry.MediaType != FixedMedia) {
+ // I never had any success with drives that have the REMOVABLE attribute set, no matter the
+ // method or tool I tried. If you manage to get this working, I'd like to hear from you!
+ if (MessageBoxU(hMainDialog, lmprintf(MSG_098), lmprintf(MSG_190), MB_YESNO|MB_ICONWARNING|MB_IS_RTL) != IDYES)
+ return FALSE;
+ }
+ } else if (bt == BT_UEFI) {
if (!iso_report.has_efi) {
// Unsupported ISO
MessageBoxU(hMainDialog, lmprintf(MSG_091), lmprintf(MSG_090), MB_OK|MB_ICONERROR|MB_IS_RTL);
@@ -1198,24 +1212,16 @@ static BOOL BootCheck(void)
ShellExecuteA(hMainDialog, "open", SEVENZIP_URL, NULL, NULL, SW_SHOWNORMAL);
return FALSE;
}
- } else if ((fs == FS_NTFS) && (!iso_report.has_bootmgr) && (!IS_WINPE(iso_report.winpe)) && (!IS_GRUB(iso_report))) {
- if (HAS_SYSLINUX(iso_report)) {
- // Only FAT/FAT32 is supported for this type of ISO
- MessageBoxU(hMainDialog, lmprintf(MSG_096), lmprintf(MSG_092), MB_OK|MB_ICONERROR|MB_IS_RTL);
- } else {
- // Only 'bootmgr' or 'WinPE' based ISO images can currently be used with NTFS
- MessageBoxU(hMainDialog, lmprintf(MSG_097), lmprintf(MSG_090), MB_OK|MB_ICONERROR|MB_IS_RTL);
- }
+ } else if ( ((fs == FS_NTFS) && (!iso_report.has_bootmgr) && (!IS_WINPE(iso_report.winpe)) && (!IS_GRUB(iso_report)))
+ || (((fs == FS_FAT16)||(fs == FS_FAT32)) && (!HAS_SYSLINUX(iso_report)) && (!allow_dual_uefi_bios) &&
+ (!IS_REACTOS(iso_report)) && (!iso_report.has_kolibrios) && (!IS_GRUB(iso_report))) ) {
+ // Incompatible FS and ISO
+ MessageBoxU(hMainDialog, lmprintf(MSG_096), lmprintf(MSG_092), MB_OK|MB_ICONERROR|MB_IS_RTL);
return FALSE;
} else if ((fs == FS_FAT16) && (iso_report.has_kolibrios)) {
// KolibriOS doesn't support FAT16
MessageBoxU(hMainDialog, lmprintf(MSG_189), lmprintf(MSG_099), MB_OK|MB_ICONERROR|MB_IS_RTL);
return FALSE;
- } else if (((fs == FS_FAT16)||(fs == FS_FAT32)) && (!HAS_SYSLINUX(iso_report)) && (!allow_dual_uefi_bios) &&
- (!IS_REACTOS(iso_report)) && (!iso_report.has_kolibrios) && (!IS_GRUB(iso_report))) {
- // FAT/FAT32 can only be used for isolinux based ISO images or when the Target Type is UEFI
- MessageBoxU(hMainDialog, lmprintf(MSG_098), lmprintf(MSG_090), MB_OK|MB_ICONERROR|MB_IS_RTL);
- return FALSE;
}
if (((fs == FS_FAT16)||(fs == FS_FAT32)) && (iso_report.has_4GB_file)) {
// This ISO image contains a file larger than 4GB file (FAT32)
@@ -2153,6 +2159,16 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD);
}
break;
+ case IDC_WINDOWS_TO_GO:
+ if (Button_GetCheck(GetDlgItem(hMainDialog, IDC_WINDOWS_TO_GO)) == BST_CHECKED) {
+ for (i=0; i