[core] Add VHD source image support

* As part of #321
* Also improve FileDialog so that it can support multiple extensions
* Also fix a typo in rufus.loc
This commit is contained in:
Pete Batard 2014-05-22 01:52:25 +01:00
parent 36d226e101
commit bfa1656488
7 changed files with 207 additions and 99 deletions

View File

@ -264,7 +264,7 @@ t MSG_096 "Only FAT/FAT32 is supported for this type of ISO. Please select FAT/F
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_099 "Filesystem limitation"
t MSG_100 "This ISO image contains a file larger than 4GB file, which is more than the "
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."
t MSG_101 "Missing WIM support"
t MSG_102 "Your platform cannot extract files from WIM archives. WIM extraction "

View File

@ -1360,12 +1360,13 @@ DWORD WINAPI FormatThread(void* param)
// Write an image file
if (dt == DT_IMG) {
// We poked the MBR, so we need to rewind
// We poked the MBR and other stuff, so we need to rewind
li.QuadPart = 0;
SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN);
hSourceImage = CreateFileU(iso_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN))
uprintf("Warning: Unable to rewind image position - wrong data might be copied!");
hSourceImage = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hSourceImage == INVALID_HANDLE_VALUE) {
uprintf("Could not open image '%s': %s", iso_path, WindowsErrorString());
uprintf("Could not open image '%s': %s", image_path, WindowsErrorString());
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
goto out;
}
@ -1397,6 +1398,10 @@ DWORD WINAPI FormatThread(void* param)
UpdateProgress(OP_FORMAT, format_percent);
}
CHECK_FOR_USER_CANCEL;
// Don't overflow our projected size (mostly for VHDs)
if (wb + rSize > iso_report.projected_size) {
rSize = (DWORD)(iso_report.projected_size - wb);
}
for (i=0; i<WRITE_RETRIES; i++) {
s = WriteFile(hPhysicalDrive, buffer, rSize, &wSize, NULL);
if ((s) && (wSize == rSize))
@ -1549,11 +1554,11 @@ DWORD WINAPI FormatThread(void* param)
goto out;
}
} else if (dt == DT_ISO) {
if (iso_path != NULL) {
if (image_path != NULL) {
UpdateProgress(OP_DOS, 0.0f);
PrintStatus(0, TRUE, MSG_231);
drive_name[2] = 0;
if (!ExtractISO(iso_path, drive_name, FALSE)) {
if (!ExtractISO(image_path, drive_name, FALSE)) {
if (!IS_ERROR(FormatStatus))
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY;
goto out;
@ -1561,7 +1566,7 @@ DWORD WINAPI FormatThread(void* param)
if (iso_report.has_kolibrios) {
kolibri_dst[0] = drive_name[0];
uprintf("Installing: %s (KolibriOS loader)\n", kolibri_dst);
if (ExtractISOFile(iso_path, "HD_Load/USB_Boot/MTLD_F32", kolibri_dst,
if (ExtractISOFile(image_path, "HD_Load/USB_Boot/MTLD_F32", kolibri_dst,
FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM) == 0) {
uprintf("Warning: loader installation failed - KolibriOS will not boot!\n");
}

View File

@ -113,7 +113,7 @@ OPENED_LIBRARIES_VARS;
HINSTANCE hMainInstance;
HWND hMainDialog;
char szFolderPath[MAX_PATH], app_dir[MAX_PATH];
char* iso_path = NULL;
char* image_path = NULL;
float fScale = 1.0f;
int default_fs;
uint32_t dur_mins, dur_secs;
@ -438,7 +438,7 @@ static void SetFSFromISO(void)
uint32_t fs_mask = 0;
int bt = GETBIOSTYPE((int)ComboBox_GetItemData(hPartitionScheme, ComboBox_GetCurSel(hPartitionScheme)));
if (iso_path == NULL)
if (image_path == NULL)
return;
// Create a mask of all the FS's available
@ -477,7 +477,7 @@ static void SetMBRProps(void)
int dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType));
BOOL needs_masquerading = (IS_WINPE(iso_report.winpe) && (!iso_report.uses_minint));
if ((!mbr_selected_by_user) && ((iso_path == NULL) || (dt != DT_ISO) || (fs != FS_NTFS))) {
if ((!mbr_selected_by_user) && ((image_path == NULL) || (dt != DT_ISO) || (fs != FS_NTFS))) {
CheckDlgButton(hMainDialog, IDC_RUFUS_MBR, BST_UNCHECKED);
IGNORE_RETVAL(ComboBox_SetCurSel(hDiskID, 0));
return;
@ -593,7 +593,7 @@ static BOOL PopulateProperties(int ComboIndex)
}
// If no existing label is available and no ISO is selected, propose one according to the size (eg: "256MB", "8GB")
if ((iso_path == NULL) || (iso_report.label[0] == 0)) {
if ((image_path == NULL) || (iso_report.label[0] == 0)) {
if ( (safe_stricmp(no_label, DriveLabel.String[ComboIndex]) == 0)
|| (safe_stricmp(lmprintf(MSG_207), DriveLabel.String[ComboIndex]) == 0) ) {
SetWindowTextU(hLabel, SelectedDrive.proposed_label);
@ -766,6 +766,9 @@ BOOL CALLBACK LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
long lfHeight;
DWORD log_size;
char *log_buffer = NULL, *filepath;
const char* log_x[] = { "*.log" };
const char* log_d[] = { lmprintf(MSG_108) };
ext_t log_ext = {ARRAYSIZE(log_x), "rufus.log", log_x, log_d };
switch (message) {
case WM_INITDIALOG:
@ -799,7 +802,7 @@ BOOL CALLBACK LogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
log_size = GetDlgItemTextU(hDlg, IDC_LOG_EDIT, log_buffer, log_size);
if (log_size != 0) {
log_size--; // remove NUL terminator
filepath = FileDialog(TRUE, app_dir, "rufus.log", "log", lmprintf(MSG_108), 0);
filepath = FileDialog(TRUE, app_dir, &log_ext, 0);
if (filepath != NULL) {
FileIO(TRUE, filepath, &log_buffer, &log_size);
}
@ -905,34 +908,6 @@ BOOL CALLBACK ISOProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
return FALSE;
}
BOOL IsImage(const char* src_img)
{
HANDLE handle = INVALID_HANDLE_VALUE;
LARGE_INTEGER liImageSize;
handle = CreateFileU(src_img, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (handle == INVALID_HANDLE_VALUE) {
uprintf("Could not open image '%s'", src_img);
goto out;
}
iso_report.is_bootable_img = AnalyzeMBR(handle, "Image");
if (!GetFileSizeEx(handle, &liImageSize)) {
uprintf("Could not get image size: %s", WindowsErrorString());
goto out;
}
iso_report.projected_size = (uint64_t)liImageSize.QuadPart;
if (iso_report.is_bootable_img) {
uprintf("Using bootable disk image: '%s'", src_img);
selection_default = DT_IMG;
}
out:
safe_closehandle(handle);
return iso_report.is_bootable_img;
}
// The scanning process can be blocking for message processing => use a thread
DWORD WINAPI ISOScanThread(LPVOID param)
{
@ -940,21 +915,24 @@ DWORD WINAPI ISOScanThread(LPVOID param)
BOOL r;
char isolinux_str[16] = "No";
if (iso_path == NULL)
if (image_path == NULL)
goto out;
PrintStatus(0, TRUE, MSG_202);
user_notified = FALSE;
EnableControls(FALSE);
r = ExtractISO(iso_path, "", TRUE) || IsImage(iso_path);
r = ExtractISO(image_path, "", TRUE) || IsHDImage(image_path);
EnableControls(TRUE);
if (!r) {
SendMessage(hISOProgressDlg, UM_PROGRESS_EXIT, 0, 0);
PrintStatus(0, TRUE, MSG_203);
safe_free(iso_path);
safe_free(image_path);
goto out;
}
if (!iso_report.is_bootable_img) {
if (iso_report.is_bootable_img) {
uprintf("Using bootable %s image: '%s'", iso_report.is_vhd?"VHD":"disk", image_path);
selection_default = DT_IMG;
} else {
if (HAS_SYSLINUX(iso_report)) {
safe_sprintf(isolinux_str, sizeof(isolinux_str), "Yes (%s)", iso_report.sl_version_str);
}
@ -974,7 +952,7 @@ DWORD WINAPI ISOScanThread(LPVOID param)
if ( (!iso_report.has_bootmgr) && (!HAS_SYSLINUX(iso_report)) && (!IS_WINPE(iso_report.winpe))
&& (!iso_report.has_efi) && (!IS_REACTOS(iso_report) && (!iso_report.has_kolibrios) && (!iso_report.is_bootable_img)) ) {
MessageBoxU(hMainDialog, lmprintf(MSG_082), lmprintf(MSG_081), MB_OK|MB_ICONINFORMATION|MB_IS_RTL);
safe_free(iso_path);
safe_free(image_path);
SetMBRProps();
} else {
// Enable bootable and set Target System and FS accordingly
@ -992,8 +970,8 @@ DWORD WINAPI ISOScanThread(LPVOID param)
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_FILESYSTEM,
ComboBox_GetCurSel(hFileSystem));
}
for (i=(int)safe_strlen(iso_path); (i>0)&&(iso_path[i]!='\\'); i--);
PrintStatus(0, TRUE, MSG_205, &iso_path[i+1]);
for (i=(int)safe_strlen(image_path); (i>0)&&(image_path[i]!='\\'); i--);
PrintStatus(0, TRUE, MSG_205, &image_path[i+1]);
// Lose the focus on the select ISO (but place it on Close)
SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)FALSE, 0);
// Lose the focus from Close and set it back to Start
@ -1100,7 +1078,7 @@ static BOOL BootCheck(void)
syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0;
dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType));
if ((dt == DT_ISO) || (dt == DT_IMG)) {
if (iso_path == NULL) {
if (image_path == NULL) {
// Please click on the disc button to select a bootable ISO
MessageBoxU(hMainDialog, lmprintf(MSG_087), lmprintf(MSG_086), MB_OK|MB_ICONERROR|MB_IS_RTL);
return FALSE;
@ -1530,6 +1508,13 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
static LPITEMIDLIST pidlDesktop = NULL;
static MY_SHChangeNotifyEntry NotifyEntry;
loc_cmd* lcmd = NULL;
// TODO: Add "*.img;*.vhd" / "All Supported Images" to the list below and use a generic "%s Image" in the .loc
const char* img_x[] = { "*.img", "*.vhd" };
const char* img_d[] = { lmprintf(MSG_095), "VHD Image" };
ext_t img_ext = {ARRAYSIZE(img_x), NULL, img_x, img_d};
const char* iso_x[] = { "*.iso" };
const char* iso_d[] = { lmprintf(MSG_036) };
ext_t iso_ext = {ARRAYSIZE(iso_x), NULL, iso_x, iso_d };
switch (message) {
@ -1809,7 +1794,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
EnableAdvancedBootOptions(TRUE, TRUE);
ToggleImage(!IsChecked(IDC_BOOT) || (selection_default != DT_IMG));
if ((selection_default == DT_ISO) || (selection_default == DT_IMG)) {
if ((iso_path == NULL) || (iso_report.label[0] == 0)) {
if ((image_path == NULL) || (iso_report.label[0] == 0)) {
// Set focus to the Select ISO button
SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)FALSE, 0);
SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)hSelectISO, TRUE);
@ -1830,21 +1815,21 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
return (INT_PTR)TRUE;
case IDC_SELECT_ISO:
if (iso_provided) {
uprintf("Image provided: '%s'\n", iso_path);
uprintf("Image provided: '%s'\n", image_path);
iso_provided = FALSE; // One off thing...
} else {
safe_free(iso_path);
safe_free(image_path);
if (selection_default == DT_IMG)
iso_path = FileDialog(FALSE, NULL, "*.img", "img", "DD Image", 0);
image_path = FileDialog(FALSE, NULL, &img_ext, 0);
else
iso_path = FileDialog(FALSE, NULL, "*.iso", "iso", lmprintf(MSG_036), 0);
if (iso_path == NULL) {
image_path = FileDialog(FALSE, NULL, &iso_ext, 0);
if (image_path == NULL) {
CreateTooltip(hSelectISO, lmprintf(MSG_173), -1);
break;
}
}
selection_default = DT_ISO;
CreateTooltip(hSelectISO, iso_path, -1);
CreateTooltip(hSelectISO, image_path, -1);
FormatStatus = 0;
if (CreateThread(NULL, 0, ISOScanThread, NULL, 0, NULL) == NULL) {
uprintf("Unable to start ISO scanning thread");
@ -2095,7 +2080,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
break;
case 'i':
if (_access(optarg, 0) != -1) {
iso_path = safe_strdup(optarg);
image_path = safe_strdup(optarg);
iso_provided = TRUE;
} else {
printf("Could not find ISO image '%s'\n", optarg);
@ -2282,7 +2267,7 @@ relaunch:
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'I')) {
enable_iso = !enable_iso;
PrintStatus2000(lmprintf(MSG_262), enable_iso);
if (iso_path != NULL) {
if (image_path != NULL) {
iso_provided = TRUE;
PostMessage(hDlg, WM_COMMAND, IDC_SELECT_ISO, 0);
}
@ -2354,7 +2339,7 @@ out:
DeleteFileU(loc_file);
DestroyAllTooltips();
exit_localization();
safe_free(iso_path);
safe_free(image_path);
safe_free(locale_name);
safe_free(update.download_url);
safe_free(update.release_notes);

View File

@ -247,6 +247,7 @@ typedef struct {
BOOL has_kolibrios;
BOOL uses_minint;
BOOL is_bootable_img;
BOOL is_vhd;
uint16_t sl_version; // Syslinux/Isolinux version
char sl_version_str[12];
} RUFUS_ISO_REPORT;
@ -285,6 +286,15 @@ enum WindowsVersion {
WINDOWS_MAX
};
/* Extensions structure used by FileDialog() */
typedef struct ext_t {
const size_t count;
const char* filename;
const char** extension;
const char** description;
} ext_t;
/*
* Globals
*/
@ -294,7 +304,7 @@ extern HWND hPartitionScheme, hFileSystem, hClusterSize, hLabel, hBootType, hNBP
extern HWND hISOProgressDlg, hISOProgressBar, hISOFileName, hDiskID;
extern float fScale;
extern char szFolderPath[MAX_PATH], app_dir[MAX_PATH];
extern char* iso_path;
extern char* image_path;
extern DWORD FormatStatus;
extern DWORD syslinux_ldlinux_len[2];
extern RUFUS_DRIVE_INFO SelectedDrive;
@ -342,7 +352,7 @@ extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter);
DWORD WINAPI FormatThread(void* param);
extern BOOL CreateProgress(void);
extern BOOL SetAutorun(const char* path);
extern char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_desc, DWORD options);
extern char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options);
extern BOOL FileIO(BOOL save, char* path, char** buffer, DWORD* size);
extern unsigned char* GetResource(HMODULE module, char* name, char* type, const char* desc, DWORD* len, BOOL duplicate);
extern BOOL GetUSBDevices(DWORD devnum);
@ -362,6 +372,7 @@ extern char* replace_in_token_data(const char* filename, const char* token, cons
extern void parse_update(char* buf, size_t len);
extern BOOL WimExtractCheck(void);
extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst);
extern BOOL IsHDImage(const char* path);
extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid);
static __inline BOOL UnlockDrive(HANDLE hDrive)

View File

@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 329
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Rufus 1.4.8.479"
CAPTION "Rufus 1.4.8.480"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
@ -165,7 +165,7 @@ END
RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
CAPTION "Rufus 1.4.8.479"
CAPTION "Rufus 1.4.8.480"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
@ -427,8 +427,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,4,8,479
PRODUCTVERSION 1,4,8,479
FILEVERSION 1,4,8,480
PRODUCTVERSION 1,4,8,480
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -445,13 +445,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.4.8.479"
VALUE "FileVersion", "1.4.8.480"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "1.4.8.479"
VALUE "ProductVersion", "1.4.8.480"
END
END
BLOCK "VarFileInfo"

View File

@ -237,13 +237,13 @@ fallback:
* CoInitializeEx() for *EACH* thread you invoke FileDialog from, as
* GetDisplayName() will return error 0x8001010E otherwise.
*/
char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_desc, DWORD options)
char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options)
{
DWORD tmp;
OPENFILENAMEA ofn;
char selected_name[MAX_PATH];
char *ext_string = NULL, *all_files = NULL;
size_t i, ext_strlen;
size_t i, j, ext_strlen;
BOOL r;
char* filepath = NULL;
@ -251,25 +251,26 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des
HRESULT hr = FALSE;
IFileDialog *pfd = NULL;
IShellItem *psiResult;
COMDLG_FILTERSPEC filter_spec[2];
char* ext_filter;
COMDLG_FILTERSPEC* filter_spec;
wchar_t *wpath = NULL, *wfilename = NULL;
IShellItem *si_path = NULL; // Automatically freed
#endif
if ((ext == NULL) || (ext->count == 0) || (ext->extension == NULL) || (ext->description == NULL))
return NULL;
dialog_showing++;
memset(filter_spec, 0, sizeof(filter_spec));
#if (_WIN32_WINNT >= 0x0600) // Vista and later
INIT_VISTA_SHELL32;
if (IS_VISTA_SHELL32_AVAILABLE) {
filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC));
if ((IS_VISTA_SHELL32_AVAILABLE) && (filter_spec != NULL)) {
// Setup the file extension filter table
ext_filter = (char*)malloc(safe_strlen(ext)+3);
if (ext_filter != NULL) {
safe_sprintf(ext_filter, safe_strlen(ext)+3, "*.%s", ext);
filter_spec[0].pszSpec = utf8_to_wchar(ext_filter);
safe_free(ext_filter);
filter_spec[0].pszName = utf8_to_wchar(ext_desc);
filter_spec[1].pszSpec = L"*.*";
filter_spec[1].pszName = utf8_to_wchar(lmprintf(MSG_107));
for (i=0; i<ext->count; i++) {
filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]);
filter_spec[i].pszName = utf8_to_wchar(ext->description[i]);
}
filter_spec[i].pszSpec = L"*.*";
filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107));
hr = CoCreateInstance(save?&CLSID_FileSaveDialog:&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC,
&IID_IFileDialog, (LPVOID)&pfd);
@ -282,7 +283,7 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des
}
// Set the file extension filters
pfd->lpVtbl->SetFileTypes(pfd, 2, filter_spec);
pfd->lpVtbl->SetFileTypes(pfd, ext->count+1, filter_spec);
// Set the default directory
wpath = utf8_to_wchar(path);
@ -293,7 +294,7 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des
safe_free(wpath);
// Set the default filename
wfilename = utf8_to_wchar(filename);
wfilename = utf8_to_wchar((ext->filename == NULL)?ext->extension[0]:ext->filename);
if (wfilename != NULL) {
pfd->lpVtbl->SetFileName(pfd, wfilename);
}
@ -303,9 +304,12 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des
// Cleanup
safe_free(wfilename);
safe_free(filter_spec[0].pszSpec);
safe_free(filter_spec[0].pszName);
safe_free(filter_spec[1].pszName);
for (i=0; i<ext->count; i++) {
safe_free(filter_spec[i].pszSpec);
safe_free(filter_spec[i].pszName);
}
safe_free(filter_spec[i].pszName);
safe_free(filter_spec);
if (SUCCEEDED(hr)) {
// Obtain the result of the user's interaction with the dialog.
@ -336,24 +340,30 @@ fallback:
if (pfd != NULL) {
pfd->lpVtbl->Release(pfd);
}
#else
dialog_showing++;
#endif
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hMainDialog;
// File name
safe_strcpy(selected_name, MAX_PATH, filename);
// Selected File name
static_sprintf(selected_name, "%s", (ext->filename == NULL)?ext->extension[0]:ext->filename);
ofn.lpstrFile = selected_name;
ofn.nMaxFile = MAX_PATH;
// Set the file extension filters
all_files = lmprintf(MSG_107);
ext_strlen = safe_strlen(ext_desc) + 2*safe_strlen(ext) + sizeof(" (*.)\0*.\0 (*.*)\0*.*\0\0") + safe_strlen(all_files);
ext_string = (char*)malloc(ext_strlen);
ext_strlen = 0;
for (i=0; i<ext->count; i++) {
ext_strlen += safe_strlen(ext->description[i]) + 2*safe_strlen(ext->extension[i]) + sizeof(" ()\r\r");
}
ext_strlen += safe_strlen(all_files) + sizeof(" (*.*)\r*.*\r");
ext_string = (char*)malloc(ext_strlen+1);
ext_string[0] = 0;
if (ext_string == NULL)
return NULL;
safe_sprintf(ext_string, ext_strlen, "%s (*.%s)\r*.%s\r%s (*.*)\r*.*\r\0", ext_desc, ext, ext, all_files);
for (i=0, j=0; i<ext->count; i++) {
j += _snprintf(&ext_string[j], ext_strlen-j, "%s (%s)\r%s\r", ext->description[i], ext->extension[i], ext->extension[i]);
}
j = _snprintf(&ext_string[j], ext_strlen-j, "%s (*.*)\r*.*\r", all_files);
// Microsoft could really have picked a better delimiter!
for (i=0; i<ext_strlen; i++) {
if (ext_string[i] == '\r') {
@ -361,7 +371,7 @@ fallback:
}
}
ofn.lpstrFilter = ext_string;
// Initial dir
ofn.nFilterIndex = 1;
ofn.lpstrInitialDir = path;
ofn.Flags = OFN_OVERWRITEPROMPT | options;
// Show Dialog
@ -1177,6 +1187,9 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR
STARTUPINFOA si;
PROCESS_INFORMATION pi;
HFONT hyperlink_font = NULL;
const char* dl_x[] = { "*.exe" };
const char* dl_d[] = { lmprintf(MSG_037) };
ext_t dl_ext = { ARRAYSIZE(dl_x), "rufus.log", dl_x, dl_d };
switch (message) {
case WM_INITDIALOG:
@ -1245,7 +1258,8 @@ INT_PTR CALLBACK NewVersionCallback(HWND hDlg, UINT message, WPARAM wParam, LPAR
break;
}
for (i=(int)strlen(update.download_url); (i>0)&&(update.download_url[i]!='/'); i--);
filepath = FileDialog(TRUE, app_dir, (char*)&update.download_url[i+1], "exe", lmprintf(MSG_037), OFN_NOCHANGEDIR);
dl_ext.filename = &update.download_url[i+1];
filepath = FileDialog(TRUE, app_dir, &dl_ext, OFN_NOCHANGEDIR);
if (filepath == NULL) {
uprintf("Could not get save path\n");
break;

101
src/vhd.c
View File

@ -18,17 +18,56 @@
*/
#include <windows.h>
#include <stdlib.h>
#include <io.h>
#include "rufus.h"
#include "msapi_utf8.h"
#include "drive.h"
#include "registry.h"
static BOOL has_wimgapi = FALSE, has_7z = FALSE;
static char sevenzip_path[MAX_PATH];
#if defined(_MSC_VER)
#define bswap_uint64 _byteswap_uint64
#define bswap_uint32 _byteswap_ulong
#define bswap_uint16 _byteswap_ushort
#else
#define bswap_uint64 __builtin_bswap64
#define bswap_uint32 __builtin_bswap32
#define bswap_uint16 __builtin_bswap16
#endif
// TODO: Add a call to generate a Fixed Hard Disk VHD footer, This would allow the saving of an existing USB to VHD. See VHD specs at:
// http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc
#define VHD_FOOTER_COOKIE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x' }
#define VHD_FOOTER_FILE_FORMAT_V1_0 0x00010000
#define VHD_FOOTER_TYPE_FIXED_HARD_DISK 0x00000002
#define VHD_FOOTER_TYPE_DYNAMIC_HARD_DISK 0x00000003
#define VHD_FOOTER_TYPE_DIFFER_HARD_DISK 0x00000004
/*
* VHD Fixed HD footer (Big Endian)
* http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc
*/
#pragma pack(push, 1)
typedef struct vhd_footer {
char cookie[8];
uint32_t features;
uint32_t file_format_version;
uint64_t data_offset;
uint32_t timestamp;
uint32_t creator_app;
uint32_t creator_version;
uint32_t creator_host_os;
uint64_t original_size;
uint64_t current_size;
uint32_t disk_geometry;
uint32_t disk_type;
uint32_t checksum;
uuid_t unique_id;
uint8_t saved_state;
uint8_t reserved[427];
} vhd_footer;
#pragma pack(pop)
// WIM API Prototypes
#define WIM_GENERIC_READ GENERIC_READ
@ -39,6 +78,9 @@ PF_TYPE_DECL(WINAPI, HANDLE, WIMLoadImage, (HANDLE, DWORD));
PF_TYPE_DECL(WINAPI, BOOL, WIMExtractImagePath, (HANDLE, PWSTR, PWSTR, DWORD));
PF_TYPE_DECL(WINAPI, BOOL, WIMCloseHandle, (HANDLE));
static BOOL has_wimgapi = FALSE, has_7z = FALSE;
static char sevenzip_path[MAX_PATH];
static BOOL Get7ZipPath(void)
{
if ( (GetRegistryKeyStr(REGKEY_HKCU, "7-Zip\\Path", sevenzip_path, sizeof(sevenzip_path)))
@ -49,6 +91,57 @@ static BOOL Get7ZipPath(void)
return FALSE;
}
BOOL IsHDImage(const char* path)
{
const char conectix_str[] = VHD_FOOTER_COOKIE;
HANDLE handle = INVALID_HANDLE_VALUE;
LARGE_INTEGER liImageSize;
vhd_footer* footer = NULL;
DWORD size;
LARGE_INTEGER ptr;
handle = CreateFileU(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (handle == INVALID_HANDLE_VALUE) {
uprintf("Could not open image '%s'", path);
goto out;
}
iso_report.is_bootable_img = AnalyzeMBR(handle, "Image");
if (!GetFileSizeEx(handle, &liImageSize)) {
uprintf("Could not get image size: %s", WindowsErrorString());
goto out;
}
iso_report.projected_size = (uint64_t)liImageSize.QuadPart;
size = sizeof(vhd_footer);
if (iso_report.projected_size >= (512 + size)) {
footer = (vhd_footer*)malloc(size);
ptr.QuadPart = iso_report.projected_size - size;
if ( (footer == NULL) || (!SetFilePointerEx(handle, ptr, NULL, FILE_BEGIN)) ||
(!ReadFile(handle, footer, size, &size, NULL)) || (size != sizeof(vhd_footer)) ) {
uprintf("Could not read VHD footer");
goto out;
}
if (memcmp(footer->cookie, conectix_str, sizeof(footer->cookie)) == 0) {
iso_report.projected_size -= sizeof(vhd_footer);
if ( (bswap_uint32(footer->file_format_version) != VHD_FOOTER_FILE_FORMAT_V1_0)
|| (bswap_uint32(footer->disk_type) != VHD_FOOTER_TYPE_FIXED_HARD_DISK)) {
uprintf("Unsupported type of VHD image");
iso_report.is_bootable_img = FALSE;
goto out;
}
// Need to remove the footer from our payload
uprintf("Image is a Fixed Hard Disk VHD file");
iso_report.is_vhd = TRUE;
}
}
out:
safe_free(footer);
safe_closehandle(handle);
return iso_report.is_bootable_img;
}
// Find out if we have any way to extract WIM files on this platform
BOOL WimExtractCheck(void)
{