[iso] bootable NTFS from ISO image [EXPERIMENTAL]

* bootmgr ISOs only
* extraction and ISO support UI improvements
* UTF8 support through CreateFileU
* cancellation on ISO file extraction
* switch to using CreateThread
This commit is contained in:
Pete Batard 2012-02-07 02:05:58 +00:00
parent 22276ccb5a
commit 472db8b592
7 changed files with 232 additions and 117 deletions

View File

@ -371,7 +371,8 @@ static BOOL WritePBR(HANDLE hLogicalVolume, BOOL bFreeDOS)
uprintf("Confirmed new volume has an NTFS boot sector\n");
if (!write_ntfs_br(&fake_fd)) break;
// Note: NTFS requires a full remount after writing the PBR. We dismount when we lock
// so that's not an issue, but if you don't remount, you don't boot!
// 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!
return TRUE;
default:
uprintf("unsupported FS for FS BR processing\n");
@ -384,7 +385,7 @@ static BOOL WritePBR(HANDLE hLogicalVolume, BOOL bFreeDOS)
/*
* Standalone thread for the formatting operation
*/
void __cdecl FormatThread(void* param)
DWORD WINAPI FormatThread(LPVOID param)
{
DWORD num = (DWORD)(uintptr_t)param;
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
@ -397,11 +398,6 @@ void __cdecl FormatThread(void* param)
FILE* log_fd;
int r;
#ifdef RUFUS_TEST
ExtractISO(ISO_IMAGE, ISO_DEST, FALSE);
goto out;
#endif
hPhysicalDrive = GetDriveHandle(num, NULL, TRUE, TRUE);
if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
@ -542,21 +538,29 @@ void __cdecl FormatThread(void* param)
if (ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType)) != DT_ISO) {
PrintStatus(0, TRUE, "Copying DOS files...");
if (!ExtractDOS(drive_name)) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY;
if (!FormatStatus)
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY;
goto out;
}
} else if (iso_path != NULL) {
PrintStatus(0, TRUE, "Copying ISO files...");
drive_name[2] = 0;
if ( (!ExtractISO(iso_path, drive_name, FALSE)) && (!FormatStatus)) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY;
}
drive_name[2] = '\\';
}
break;
// Syslinux requires patching of the PBR after the files have been extracted
case DT_SYSLINUX:
if (!InstallSyslinux(num, drive_name)) {
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE;
goto out;
}
break;
}
}
// TODO: the only way to properly recover from a cancel will be through a device reset
// We issue a complete remount of the filesystem at the end on account of:
// - Ensuring the file explorer properly detects that the volume was updated
// - Ensuring that an NTFS system will be reparsed so that it becomes bootable
@ -579,5 +583,5 @@ out:
safe_unlockclose(hLogicalVolume);
safe_unlockclose(hPhysicalDrive);
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
_endthread();
ExitThread(0);
}

164
src/iso.c
View File

@ -52,8 +52,9 @@
#endif
// How often should we update the progress bar (in 2K blocks) as updating
// the progress bar for every block will bring extraction to a crawl
#define PROGRESS_UPDATE 1024
#define FOUR_GIGABYTES 4294967296LL
#define PROGRESS_THRESHOLD 1024
#define THREADED_CLOSE_THRESHOLD (20 * 1024 * 1024) // 20 MB
#define FOUR_GIGABYTES 4294967296LL
// Needed for UDF ISO access
CdIo_t* cdio_open (const char *psz_source, driver_id_t driver_id) {return NULL;}
@ -64,12 +65,52 @@ static const char *psz_extract_dir;
static uint64_t total_blocks, nb_blocks;
static BOOL scan_only = FALSE;
// TODO: Unicode support, timestamp & permissions preservation
// TODO: Timestamp & permissions preservation
// Convert a file size to human readable
static __inline char* size_to_hr(int64_t size)
{
int suffix = 0;
static char str_size[24];
const char* sizes[] = { "bytes", "KB", "MB", "GB", "TB", "PB" };
double hr_size = (double)size;
while ((suffix < ARRAYSIZE(sizes)) && (hr_size >= 1024.0)) {
hr_size /= 1024.0;
suffix++;
}
safe_sprintf(str_size, sizeof(str_size), " (%0.1f %s)", hr_size, sizes[suffix]);
return str_size;
}
// Interruptible thread for handle closure on large files
DWORD WINAPI ISOCloseHandleThread(LPVOID param)
{
CloseHandle((HANDLE)param);
ExitThread(0);
}
#define SAFE_CLOSEHANDLE_THREADED(handle) \
if (!threaded_close) { \
safe_closehandle(handle); \
} else { \
thid = CreateThread(NULL, 0, ISOCloseHandleThread, (LPVOID)handle, 0, NULL); \
while (WaitForSingleObject(thid, 1000) == WAIT_TIMEOUT) { \
if (!FormatStatus) continue; \
safe_closehandle(thid); \
break; \
} \
handle = NULL; \
threaded_close = FALSE; \
}
// Returns 0 on success, nonzero on error
static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const char *psz_path)
{
FILE *fd = NULL;
HANDLE thid, file_handle = NULL;
DWORD buf_size, wr_size;
BOOL threaded_close = FALSE;
int i_length;
size_t i, nul_pos;
char* psz_fullpath;
const char* psz_basename;
udf_dirent_t *p_udf_dirent2;
@ -82,19 +123,24 @@ static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const cha
while ((p_udf_dirent = udf_readdir(p_udf_dirent)) != NULL) {
if (FormatStatus) goto out;
psz_basename = udf_get_filename(p_udf_dirent);
i_length = (int)(3 + strlen(psz_path) + strlen(psz_basename) + strlen(psz_extract_dir));
i_length = (int)(3 + strlen(psz_path) + strlen(psz_basename) + strlen(psz_extract_dir) + 24);
psz_fullpath = (char*)calloc(sizeof(char), i_length);
if (psz_fullpath == NULL) {
uprintf("Error allocating file name\n");
goto out;
}
i_length = _snprintf(psz_fullpath, i_length, "%s%s/%s", psz_extract_dir, psz_path, psz_basename);
i_length = safe_sprintf(psz_fullpath, i_length, "%s%s/%s", psz_extract_dir, psz_path, psz_basename);
if (i_length < 0) {
goto out;
}
if (udf_is_dir(p_udf_dirent)) {
if (!scan_only)
if (!scan_only) {
_mkdir(psz_fullpath);
} else {
// Check for an "isolinux\" dir in root (psz_path = "")
if ((*psz_path == 0) && (safe_strcmp(psz_basename, "isolinux") == 0))
iso_report.has_isolinux = TRUE;
}
p_udf_dirent2 = udf_opendir(p_udf_dirent);
if (p_udf_dirent2 != NULL) {
if (udf_extract_files(p_udf, p_udf_dirent2, &psz_fullpath[strlen(psz_extract_dir)]))
@ -103,6 +149,9 @@ static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const cha
} else {
i_file_length = udf_get_file_length(p_udf_dirent);
if (scan_only) {
// Check for a "bootmgr" file in root (psz_path = "")
if ((*psz_path == 0) && (safe_strcmp(psz_basename, "bootmgr") == 0))
iso_report.has_bootmgr = TRUE;
if (i_file_length >= FOUR_GIGABYTES)
iso_report.has_4GB_file = TRUE;
total_blocks += i_file_length/UDF_BLOCKSIZE;
@ -111,13 +160,25 @@ static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const cha
safe_free(psz_fullpath);
continue;
}
// Replace slashes with backslashes and append the size to the path for UI display
nul_pos = safe_strlen(psz_fullpath);
for (i=0; i<nul_pos; i++) {
if (psz_fullpath[i] == '/')
psz_fullpath[i] = '\\';
}
safe_strcpy(&psz_fullpath[nul_pos], 24, size_to_hr(i_file_length));
uprintf("Extracting: %s\n", psz_fullpath);
SetWindowTextU(hISOFileName, psz_fullpath);
fd = fopen(psz_fullpath, "wb");
if (fd == NULL) {
uprintf(" Unable to create file\n");
// Remove the appended size for extraction
psz_fullpath[nul_pos] = 0;
file_handle = CreateFileU(psz_fullpath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
uprintf(" Unable to create file: %s\n", WindowsErrorString());
goto out;
}
threaded_close = (i_file_length > THREADED_CLOSE_THRESHOLD);
if (threaded_close) uprintf("will use threaded close\n");
while (i_file_length > 0) {
if (FormatStatus) goto out;
memset(buf, 0, UDF_BLOCKSIZE);
@ -126,17 +187,23 @@ static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const cha
uprintf(" Error reading UDF file %s\n", &psz_fullpath[strlen(psz_extract_dir)]);
goto out;
}
fwrite(buf, (size_t)MIN(i_file_length, i_read), 1, fd);
if (ferror(fd)) {
uprintf(" Error writing file\n");
buf_size = (DWORD)MIN(i_file_length, i_read);
if (!WriteFile(file_handle, buf, buf_size, &wr_size, NULL) || (buf_size != wr_size)) {
uprintf(" Error writing file: %s\n", WindowsErrorString());
goto out;
}
i_file_length -= i_read;
if (nb_blocks++ % PROGRESS_UPDATE == 0)
if (nb_blocks++ % PROGRESS_THRESHOLD == 0) {
SendMessage(hISOProgressBar, PBM_SETPOS, (WPARAM)((MAX_PROGRESS*nb_blocks)/total_blocks), 0);
}
}
fclose(fd);
fd = NULL;
// If you have a fast USB 3.0 device, the default Windows buffering does an
// excellent job at compensating for our small blocks read/writes to max out the
// device's bandwidth.
// The drawback however is with cancellation. With a large file, CloseHandle()
// may take forever to complete on a large file and is not an interruptible
// operation. To compensate for this, we create a thread when needed.
SAFE_CLOSEHANDLE_THREADED(file_handle);
}
safe_free(psz_fullpath);
}
@ -145,30 +212,32 @@ static int udf_extract_files(udf_t *p_udf, udf_dirent_t *p_udf_dirent, const cha
out:
if (p_udf_dirent != NULL)
udf_dirent_free(p_udf_dirent);
if (fd != NULL)
fclose(fd);
SAFE_CLOSEHANDLE_THREADED(file_handle);
safe_free(psz_fullpath);
return 1;
}
// Returns 0 on success, nonzero on error
static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
{
FILE *fd = NULL;
HANDLE thid, file_handle = NULL;
DWORD buf_size, wr_size;
BOOL threaded_close = FALSE;
int i_length, r = 1;
char psz_fullpath[4096], *psz_basename;
char psz_fullpath[1024], *psz_basename;
const char *psz_iso_name = &psz_fullpath[strlen(psz_extract_dir)];
unsigned char buf[ISO_BLOCKSIZE];
CdioListNode_t* p_entnode;
iso9660_stat_t *p_statbuf;
CdioList_t* p_entlist;
size_t i;
size_t i, nul_pos;
lsn_t lsn;
int64_t i_file_length;
if ((p_iso == NULL) || (psz_path == NULL))
return 1;
i_length = _snprintf(psz_fullpath, sizeof(psz_fullpath), "%s%s/", psz_extract_dir, psz_path);
i_length = safe_sprintf(psz_fullpath, sizeof(psz_fullpath), "%s%s/", psz_extract_dir, psz_path);
if (i_length < 0)
return 1;
psz_basename = &psz_fullpath[i_length];
@ -186,13 +255,21 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
continue;
iso9660_name_translate(p_statbuf->filename, psz_basename);
if (p_statbuf->type == _STAT_DIR) {
if (!scan_only)
if (!scan_only) {
_mkdir(psz_fullpath);
} else {
// Check for an "isolinux\" dir in root (psz_path = "")
if ((*psz_path == 0) && (safe_strcmp(psz_basename, "isolinux") == 0))
iso_report.has_isolinux = TRUE;
}
if (iso_extract_files(p_iso, psz_iso_name))
goto out;
} else {
i_file_length = p_statbuf->size;
if (scan_only) {
// Check for a "bootmgr" file in root (psz_path = "")
if ((*psz_path == 0) && (safe_strcmp(psz_basename, "bootmgr") == 0))
iso_report.has_bootmgr = TRUE;
if (i_file_length >= FOUR_GIGABYTES)
iso_report.has_4GB_file = TRUE;
total_blocks += i_file_length/ISO_BLOCKSIZE;
@ -200,12 +277,23 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
total_blocks++;
continue;
}
// Replace slashes with backslashes and append the size to the path for UI display
nul_pos = safe_strlen(psz_fullpath);
for (i=0; i<nul_pos; i++) {
if (psz_fullpath[i] == '/')
psz_fullpath[i] = '\\';
}
safe_strcpy(&psz_fullpath[nul_pos], 24, size_to_hr(i_file_length));
uprintf("Extracting: %s\n", psz_fullpath);
fd = fopen(psz_fullpath, "wb");
if (fd == NULL) {
uprintf(" Unable to create file\n");
SetWindowTextU(hISOFileName, psz_fullpath);
psz_fullpath[nul_pos] = 0;
file_handle = CreateFileU(psz_fullpath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
uprintf(" Unable to create file: %s\n", WindowsErrorString());
goto out;
}
threaded_close = (i_file_length > THREADED_CLOSE_THRESHOLD);
for (i = 0; i_file_length > 0; i++) {
if (FormatStatus) goto out;
memset(buf, 0, ISO_BLOCKSIZE);
@ -215,24 +303,23 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
psz_iso_name, (long unsigned int)lsn);
goto out;
}
fwrite(buf, (size_t)MIN(i_file_length, ISO_BLOCKSIZE), 1, fd);
if (ferror(fd)) {
uprintf(" Error writing file\n");
buf_size = (DWORD)MIN(i_file_length, ISO_BLOCKSIZE);
if (!WriteFile(file_handle, buf, buf_size, &wr_size, NULL) || (buf_size != wr_size)) {
uprintf(" Error writing file: %s\n", WindowsErrorString());
goto out;
}
i_file_length -= ISO_BLOCKSIZE;
if (nb_blocks++ % PROGRESS_UPDATE == 0)
if (nb_blocks++ % PROGRESS_THRESHOLD == 0) {
SendMessage(hISOProgressBar, PBM_SETPOS, (WPARAM)((MAX_PROGRESS*nb_blocks)/total_blocks), 0);
}
}
fclose(fd);
fd = NULL;
SAFE_CLOSEHANDLE_THREADED(file_handle);
}
}
r = 0;
out:
if (fd != NULL)
fclose(fd);
SAFE_CLOSEHANDLE_THREADED(file_handle);
_cdio_list_free(p_entlist, true);
return r;
}
@ -254,10 +341,11 @@ BOOL ExtractISO(const char* src_iso, const char* dest_dir, bool scan)
psz_extract_dir = dest_dir;
progress_style = GetWindowLong(hISOProgressBar, GWL_STYLE);
if (scan_only) {
uprintf(scan_text);
total_blocks = 0;
iso_report.projected_size = 0;
iso_report.has_4GB_file = FALSE;
iso_report.has_bootmgr = FALSE;
iso_report.has_isolinux = FALSE;
// Change the Window title and static text
SetWindowTextU(hISOProgressDlg, scan_text);
SetWindowTextU(hISOFileName, scan_text);
@ -282,6 +370,7 @@ BOOL ExtractISO(const char* src_iso, const char* dest_dir, bool scan)
p_udf = udf_open(src_iso);
if (p_udf == NULL)
goto try_iso;
uprintf("Disc image is an UDF image\n");
p_udf_root = udf_get_root(p_udf, true, 0);
if (p_udf_root == NULL) {
@ -297,6 +386,7 @@ try_iso:
uprintf("Unable to open image '%s'.\n", src_iso);
goto out;
}
uprintf("Disc image is an ISO9660 image\n");
r = iso_extract_files(p_iso, "");
out:
@ -310,6 +400,6 @@ out:
if (p_udf != NULL)
udf_close(p_udf);
if ((r != 0) && (FormatStatus == 0))
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(scan_only?ERROR_ISO_SCAN:ERROR_ISO_EXTRACT);
return r;
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR((scan_only?ERROR_ISO_SCAN:ERROR_ISO_EXTRACT));
return (r == 0);
}

View File

@ -674,8 +674,10 @@ udf_readdir(udf_dirent_t *p_udf_dirent)
const unsigned int i_len = p_udf_dirent->fid->i_file_id;
if (DRIVER_OP_SUCCESS != udf_read_sectors(p_udf, &p_udf_dirent->fe, p_udf->i_part_start
+ p_udf_dirent->fid->icb.loc.lba, 1))
+ p_udf_dirent->fid->icb.loc.lba, 1)) {
udf_dirent_free(p_udf_dirent);
return NULL;
}
if (strlen(p_udf_dirent->psz_name) < i_len)
p_udf_dirent->psz_name = (char *)
@ -687,6 +689,7 @@ udf_readdir(udf_dirent_t *p_udf_dirent)
}
return p_udf_dirent;
}
udf_dirent_free(p_udf_dirent);
return NULL;
}

View File

@ -53,19 +53,20 @@ static BOOL existing_key = FALSE;
HINSTANCE hMainInstance;
HWND hMainDialog;
char szFolderPath[MAX_PATH];
char* iso_path = NULL;
float fScale = 1.0f;
int default_fs;
HWND hDeviceList, hCapacity, hFileSystem, hClusterSize, hLabel, hDOSType, hNBPasses;
HWND hISOProgressDlg = NULL, hISOProgressBar, hISOFileName;
BOOL bWithFreeDOS, bWithSyslinux;
static HANDLE format_thid = NULL;
static HWND hDeviceTooltip = NULL, hFSTooltip = NULL, hProgress = NULL;
static HWND hDOS = NULL, hSelectISO = NULL, hISOToolTip = NULL;
static HICON hIconDisc;
static StrArray DriveID, DriveLabel;
static char szTimer[10] = "00:00:00";
static char szTimer[12] = "00:00:00";
static unsigned int timer;
static char* iso_path = NULL;
/*
* The following is used to allocate slots within the progress bar
@ -905,8 +906,10 @@ BOOL CALLBACK ISOProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
switch (LOWORD(wParam)) {
case IDC_ISO_ABORT:
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
PrintStatus(0, FALSE, "Cancelling - please wait...");
uprintf("ISO: USER CANCEL\n");
// if (format_thid != NULL)
// CancelSynchronousIo(format_thid);
PrintStatus(0, FALSE, "Cancelling - This might take a while...");
uprintf("Cancelling (ISO)\n");
return TRUE;
}
case WM_CLOSE: // prevent closure using Alt-F4
@ -916,16 +919,27 @@ BOOL CALLBACK ISOProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
}
// The scanning process can be blocking for message processing => use a thread
void __cdecl ISOScanThread(void* param)
DWORD WINAPI ISOScanThread(LPVOID param)
{
int i;
// ExtractISO(ISO_IMAGE, ISO_DEST, TRUE);
size_t i;
PrintStatus(0, TRUE, "Scanning ISO image...\n");
ExtractISO(iso_path, "", TRUE);
uprintf("Projected size: %lld\nHas 4GB: %s\n", iso_report.projected_size, iso_report.has_4GB_file?"TRUE":"FALSE");
for (i=safe_strlen(iso_path); (i>=0)&&(iso_path[i] != '\\'); i--);
PrintStatus(0, TRUE, "Using ISO: '%s'\n", &iso_path[i+1]);
_endthread();
if (!ExtractISO(iso_path, "", TRUE)) {
PrintStatus(0, TRUE, "Failed to scan ISO image.");
goto out;
}
uprintf("ISO size: %lld bytes, 4GB:%c, bootmgr:%c, isolinux:%c\n", iso_report.projected_size,
iso_report.has_4GB_file?'Y':'N', iso_report.has_bootmgr?'Y':'N', iso_report.has_isolinux?'Y':'N');
if (!iso_report.has_bootmgr) {
MessageBoxU(hMainDialog, "This version of Rufus supports only\n"
"ISO images that rely on 'bootmgr' - sorry.", "Unsupported ISO", MB_OK|MB_ICONINFORMATION);
safe_free(iso_path);
} else {
for (i=safe_strlen(iso_path); (i>=0)&&(iso_path[i] != '\\'); i--);
PrintStatus(0, TRUE, "Using ISO: '%s'\n", &iso_path[i+1]);
}
out:
ExitThread(0);
}
// Helper function to obtain a handle to a DLL
@ -965,6 +979,10 @@ void InitDialog(HWND hDlg)
HICON hSmallIcon, hBigIcon;
char tmp[128];
#ifdef RUFUS_TEST
ShowWindow(GetDlgItem(hDlg, IDC_TEST), SW_SHOW);
#endif
// Quite a burden to carry around as parameters
hMainDialog = hDlg;
hDeviceList = GetDlgItem(hDlg, IDC_DEVICE);
@ -1009,8 +1027,7 @@ void InitDialog(HWND hDlg)
IGNORE_RETVAL(ComboBox_SetCurSel(hNBPasses, 1));
// Fill up the DOS type dropdown
IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "MS-DOS"), DT_WINME));
IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "ISO"), DT_ISO));
IGNORE_RETVAL(ComboBox_SetCurSel(hDOSType, bWithFreeDOS?DT_FREEDOS:DT_WINME));
IGNORE_RETVAL(ComboBox_SetCurSel(hDOSType, DT_WINME));
// Create the string array
StrArrayCreate(&DriveID, MAX_DRIVES);
StrArrayCreate(&DriveLabel, MAX_DRIVES);
@ -1044,13 +1061,12 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
int nDeviceIndex, fs, dt;
DWORD DeviceNum;
char str[MAX_PATH], tmp[128];
static uintptr_t format_thid = -1L;
static UINT uDOSChecked = BST_CHECKED;
switch (message) {
case WM_DEVICECHANGE:
if ( (format_thid == -1L) &&
if ( (format_thid == NULL) &&
((wParam == DBT_DEVICEARRIVAL) || (wParam == DBT_DEVICEREMOVECOMPLETE)) ) {
GetUSBDevices();
return (INT_PTR)TRUE;
@ -1079,15 +1095,16 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
switch(LOWORD(wParam)) {
case IDOK: // close application
case IDCANCEL:
if (format_thid != -1L) {
if (format_thid != NULL) {
if (MessageBoxA(hMainDialog, "Cancelling may leave the device in an UNUSABLE state.\r\n"
"If you are sure you want to cancel, click YES. Otherwise, click NO.",
RUFUS_CANCELBOX_TITLE, MB_YESNO|MB_ICONWARNING) == IDYES) {
// Operation may have completed in the meantime
if (format_thid != -1L) {
if (format_thid != NULL) {
// CancelSynchronousIo(format_thid);
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANCELLED;
PrintStatus(0, FALSE, "Cancelling - please wait...");
uprintf("USER CANCEL\n");
PrintStatus(0, FALSE, "Cancelling - Please wait...");
uprintf("Cancelling (General)\n");
}
}
return (INT_PTR)TRUE;
@ -1103,19 +1120,6 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
break;
#ifdef RUFUS_TEST
case IDC_TEST:
FormatStatus = 0;
// You'd think that Windows would let you instantiate a modeless dialog wherever
// but you'd be wrong. It has to be done in the main callback!
if (!IsWindow(hISOProgressDlg)) {
hISOProgressDlg = CreateDialogA(hMainInstance, MAKEINTRESOURCEA(IDD_ISO_EXTRACT),
hDlg, (DLGPROC)ISOProc);
// The window is not visible by default but takes focus => restore it
SetFocus(hDlg);
}
if (_beginthread(ISOScanThread, 0, NULL) == -1L) {
uprintf("Unable to start ISO scanning thread");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD);
}
break;
#endif
case IDC_DEVICE:
@ -1150,7 +1154,10 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
if (bWithSyslinux)
IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "Syslinux"), DT_SYSLINUX));
}
IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "ISO"), DT_ISO));
if (fs == FS_NTFS) {
// Only allow ISO with NTFS for the time being
IGNORE_RETVAL(ComboBox_SetItemData(hDOSType, ComboBox_AddStringU(hDOSType, "ISO..."), DT_ISO));
}
IGNORE_RETVAL(ComboBox_SetCurSel(hDOSType, (bWithFreeDOS && (fs != FS_NTFS))?1:0));
if (!IsWindowEnabled(hDOS)) {
EnableWindow(hDOS, TRUE);
@ -1189,18 +1196,31 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
// The window is not visible by default but takes focus => restore it
SetFocus(hDlg);
}
if (_beginthread(ISOScanThread, 0, NULL) == -1L) {
if (CreateThread(NULL, 0, ISOScanThread, NULL, 0, 0) == NULL) {
uprintf("Unable to start ISO scanning thread");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD);
}
break;
case IDC_START:
if (format_thid != -1L) {
if (format_thid != NULL) {
return (INT_PTR)TRUE;
}
FormatStatus = 0;
nDeviceIndex = ComboBox_GetCurSel(hDeviceList);
if (nDeviceIndex != CB_ERR) {
if (ComboBox_GetItemData(hDOSType, ComboBox_GetCurSel(hDOSType)) == DT_ISO) {
if (iso_path == NULL) {
MessageBoxA(hMainDialog, "Please click on the disc button to select a bootable ISO,\n"
"or unselect the \"Create bootable disk...\" checkbox.",
"No ISO image selected...", MB_OK|MB_ICONERROR);
break;
}
if (iso_report.projected_size > (uint64_t)SelectedDrive.DiskSize) {
MessageBoxA(hMainDialog, "This ISO image is too big "
"for the selected target.", "ISO image too big...", MB_OK|MB_ICONERROR);
break;
}
}
GetWindowTextA(hDeviceList, tmp, sizeof(tmp));
safe_sprintf(str, sizeof(str), "WARNING: ALL DATA ON DEVICE %s\r\nWILL BE DESTROYED.\r\n"
"To continue with this operation, click OK. To quit click CANCEL.", tmp);
@ -1216,8 +1236,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
// The window is not visible by default but takes focus => restore it
SetFocus(hDlg);
}
format_thid = _beginthread(FormatThread, 0, (void*)(uintptr_t)DeviceNum);
if (format_thid == -1L) {
format_thid = CreateThread(NULL, 0, FormatThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL);
if (format_thid == NULL) {
uprintf("Unable to start formatting thread");
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD);
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
@ -1236,16 +1256,14 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
return (INT_PTR)TRUE;
case WM_CLOSE:
if (format_thid != -1L) {
if (format_thid != NULL) {
return (INT_PTR)TRUE;
}
DestroyAllTooltips();
safe_free(iso_path);
PostQuitMessage(0);
break;
case UM_FORMAT_COMPLETED:
format_thid = -1L;
format_thid = NULL;
// Stop the timer
KillTimer(hMainDialog, TID_APP_TIMER);
// Close the cancel MessageBox if active
@ -1256,7 +1274,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
PrintStatus(0, FALSE, "DONE");
} else if (SCODE_CODE(FormatStatus) == ERROR_CANCELLED) {
PrintStatus(0, FALSE, "Cancelled");
Notification(MSG_INFO, "Cancelled", "Operation cancelled by the user.");
Notification(MSG_INFO, "Cancelled", "Operation cancelled by the user.\n"
"If you aborted during file extraction, you should replug the drive...");
} else {
PrintStatus(0, FALSE, "FAILED");
Notification(MSG_ERROR, "Error", "Error: %s", StrError(FormatStatus));
@ -1321,10 +1340,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
MessageBoxA(NULL, "Could not create Window", "DialogBox failure", MB_ICONSTOP);
goto out;
}
// CenterDialog(hDlg);
#ifndef RUFUS_TEST
ShowWindow(GetDlgItem(hDlg, IDC_TEST), SW_HIDE);
#endif
ShowWindow(hDlg, SW_SHOWNORMAL);
UpdateWindow(hDlg);
@ -1346,6 +1361,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
}
out:
DestroyAllTooltips();
safe_free(iso_path);
#ifdef DISABLE_AUTORUN
SetLGP(TRUE, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", "NoDriveTypeAutorun", 0);
#endif

View File

@ -27,12 +27,6 @@
/* Features not ready for prime time and that may *DESTROY* your data - USE AT YOUR OWN RISKS! */
//#define RUFUS_TEST
//#define ISO_DEST "D:/tmp/iso"
//#define ISO_IMAGE "D:\\Incoming\\Windows 8 Preview\\WindowsDeveloperPreview-64bit-English-Developer.iso"
//#define ISO_IMAGE "D:\\fd11src.iso", "D:/tmp/iso"
//#define ISO_IMAGE "D:\\Incoming\\GRMSDKX_EN_DVD.iso"
//#define ISO_IMAGE "D:\\Incoming\\en_windows_driver_kit_3790.iso"
//#define ISO_IMAGE "D:\\Incoming\\en_windows_7_ultimate_with_sp1_x64_dvd_618240.iso"
#define STR_NO_LABEL "NO_LABEL"
#define RUFUS_CANCELBOX_TITLE "Rufus - Cancellation"
@ -152,6 +146,8 @@ typedef struct {
typedef struct {
uint64_t projected_size;
BOOL has_4GB_file;
BOOL has_bootmgr;
BOOL has_isolinux;
} RUFUS_ISO_REPORT;
/*
@ -163,6 +159,7 @@ extern HWND hFileSystem, hClusterSize, hLabel, hDOSType, hNBPasses;
extern HWND hISOProgressDlg, hISOProgressBar, hISOFileName;
extern float fScale;
extern char szFolderPath[MAX_PATH];
extern char* iso_path;
extern DWORD FormatStatus;
extern RUFUS_DRIVE_INFO SelectedDrive;
extern const int nb_steps[FS_MAX];
@ -187,7 +184,7 @@ extern BOOL Notification(int type, char* title, char* format, ...);
extern BOOL ExtractDOS(const char* path);
extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan);
extern BOOL InstallSyslinux(DWORD num, const char* drive_name);
extern void __cdecl FormatThread(void* param);
DWORD WINAPI FormatThread(void* param);
extern BOOL CreatePartition(HANDLE hDrive);
extern HANDLE GetDriveHandle(DWORD DriveIndex, char* DriveLetter, BOOL bWriteAccess, BOOL bLockDrive);
extern BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label);

View File

@ -8,7 +8,7 @@
// Generated from the TEXTINCLUDE 2 resource.
//
#include <windows.h>
#ifndef __GNUC__
#ifndef __MINGW32__
#include "../ms-config.h"
#endif
#ifndef IDC_STATIC
@ -33,7 +33,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 206, 278
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_APPWINDOW
CAPTION "Rufus v1.0.7.126"
CAPTION "Rufus v1.0.7.127"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Start",IDC_START,94,236,50,14
@ -56,7 +56,7 @@ BEGIN
CONTROL "",IDC_PROGRESS,"msctls_progress32",PBS_SMOOTH | WS_BORDER,7,210,189,9
COMBOBOX IDC_DOSTYPE,118,183,45,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
COMBOBOX IDC_NBPASSES,118,159,45,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Test",IDC_TEST,62,236,20,14
PUSHBUTTON "Test",IDC_TEST,62,236,20,14,NOT WS_VISIBLE
PUSHBUTTON "...",IDC_SELECT_ISO,168,182,23,14,BS_ICON | NOT WS_VISIBLE
END
@ -71,7 +71,7 @@ BEGIN
DEFPUSHBUTTON "OK",IDOK,231,175,50,14,WS_GROUP
CONTROL "<a href=""http://rufus.akeo.ie"">http://rufus.akeo.ie</a>",IDC_ABOUT_RUFUS_URL,
"SysLink",WS_TABSTOP,46,47,114,9
LTEXT "Version 1.0.7 (Build 126)",IDC_STATIC,46,19,78,8
LTEXT "Version 1.0.7 (Build 127)",IDC_STATIC,46,19,78,8
PUSHBUTTON "License...",IDC_ABOUT_LICENSE,46,175,50,14,WS_GROUP
EDITTEXT IDC_ABOUT_COPYRIGHTS,46,107,235,63,ES_MULTILINE | ES_READONLY | WS_VSCROLL
LTEXT "Report bugs or request enhancements at:",IDC_STATIC,46,66,187,8
@ -92,14 +92,14 @@ BEGIN
DEFPUSHBUTTON "Close",IDCANCEL,211,44,50,14
END
IDD_ISO_EXTRACT DIALOGEX 0, 0, 262, 73
IDD_ISO_EXTRACT DIALOGEX 0, 0, 262, 66
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Extracting Files..."
CAPTION "Copying ISO files..."
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "",IDC_ISO_FILENAME,14,9,232,14
CONTROL "",IDC_ISO_PROGRESS,"msctls_progress32",WS_BORDER,14,32,231,8
PUSHBUTTON "Abort",IDC_ISO_ABORT,112,50,50,14
LTEXT "",IDC_ISO_FILENAME,8,10,246,13,SS_PATHELLIPSIS
CONTROL "",IDC_ISO_PROGRESS,"msctls_progress32",WS_BORDER,7,26,247,8
PUSHBUTTON "Cancel",IDC_ISO_ABORT,111,43,50,14
END
IDD_LICENSE DIALOGEX 0, 0, 335, 205
@ -126,7 +126,7 @@ END
2 TEXTINCLUDE
BEGIN
"#include <windows.h>\r\n"
"#ifndef __GNUC__\r\n"
"#ifndef __MINGW32__\r\n"
"#include ""../ms-config.h""\r\n"
"#endif\r\n"
"#ifndef IDC_STATIC\r\n"
@ -207,6 +207,7 @@ BEGIN
IDD_ISO_EXTRACT, DIALOG
BEGIN
BOTTOMMARGIN, 65
END
IDD_LICENSE, DIALOG
@ -222,8 +223,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,7,126
PRODUCTVERSION 1,0,7,126
FILEVERSION 1,0,7,127
PRODUCTVERSION 1,0,7,127
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -240,13 +241,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "akeo.ie"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "1.0.7.126"
VALUE "FileVersion", "1.0.7.127"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "1.0.7.126"
VALUE "ProductVersion", "1.0.7.127"
END
END
BLOCK "VarFileInfo"

View File

@ -213,7 +213,7 @@ const char* StrError(DWORD error_code)
case ERROR_PARTITION_FAILURE:
return "Error while partitioning drive";
case ERROR_CANNOT_COPY:
return "Could not copy MS-DOS files";
return "Could not copy files to target drive";
case ERROR_CANCELLED:
return "Cancelled by user";
case ERROR_CANT_START_THREAD:
@ -224,6 +224,9 @@ const char* StrError(DWORD error_code)
return "ISO image scan failure";
case ERROR_ISO_EXTRACT:
return "ISO image scan failure";
case ERROR_CANT_REMOUNT_VOLUME:
return "Unable to remount volume. You may have to use the\n"
"mountvol.exe command to make your device accessible again";
default:
uprintf("Unknown error: %08X\n", error_code);
SetLastError(error_code);