diff --git a/src/format.c b/src/format.c index efb2a7d6..a010e264 100644 --- a/src/format.c +++ b/src/format.c @@ -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); } diff --git a/src/iso.c b/src/iso.c index a9bc4fe2..e0fad696 100644 --- a/src/iso.c +++ b/src/iso.c @@ -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 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 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); } diff --git a/src/libcdio/udf/udf_fs.c b/src/libcdio/udf/udf_fs.c index 98830cf7..5241d8dc 100644 --- a/src/libcdio/udf/udf_fs.c +++ b/src/libcdio/udf/udf_fs.c @@ -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; } diff --git a/src/rufus.c b/src/rufus.c index 9ade53d5..f5dc92aa 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -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 diff --git a/src/rufus.h b/src/rufus.h index aa25ec71..c3c17f07 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -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); diff --git a/src/rufus.rc b/src/rufus.rc index 40be212a..9c0346fc 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -8,7 +8,7 @@ // Generated from the TEXTINCLUDE 2 resource. // #include -#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 "http://rufus.akeo.ie",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 \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" diff --git a/src/stdio.c b/src/stdio.c index 5b2f94e6..f7a3aa38 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -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);