/* * Rufus: The Reliable USB Formatting Utility * Copyright © 2011-2012 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */ #ifdef _CRTDBG_MAP_ALLOC #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "msapi_utf8.h" #include "resource.h" #include "rufus.h" #include "sys_types.h" #include "registry.h" /* Redefinitions for the WDK */ #ifndef PBM_SETSTATE #define PBM_SETSTATE (WM_USER+16) #endif #ifndef PBST_NORMAL #define PBST_NORMAL 1 #endif #ifndef PBST_ERROR #define PBST_ERROR 2 #endif #ifndef PBST_PAUSED #define PBST_PAUSED 3 #endif #ifndef BUTTON_IMAGELIST_ALIGN_CENTER #define BUTTON_IMAGELIST_ALIGN_CENTER 4 #endif #ifndef BCM_SETIMAGELIST #define BCM_SETIMAGELIST 0x1602 #endif // MinGW fails to link those typedef HIMAGELIST (WINAPI *ImageList_Create_t)( int cx, int cy, UINT flags, int cInitial, int cGrow ); ImageList_Create_t pImageList_Create = NULL; typedef int (WINAPI *ImageList_ReplaceIcon_t)( HIMAGELIST himl, int i, HICON hicon ); ImageList_ReplaceIcon_t pImageList_ReplaceIcon = NULL; struct { HIMAGELIST himl; RECT margin; UINT uAlign; } bi_iso = {0}, bi_up = {0}, bi_down = {0}; // BUTTON_IMAGELIST static const char* FileSystemLabel[FS_MAX] = { "FAT", "FAT32", "NTFS", "exFAT" }; // Don't ask me - just following the MS standard here static const char* ClusterSizeLabel[] = { "512 bytes", "1024 bytes","2048 bytes","4096 bytes","8192 bytes", "16 kilobytes", "32 kilobytes", "64 kilobytes", "128 kilobytes", "256 kilobytes", "512 kilobytes", "1024 kilobytes","2048 kilobytes","4096 kilobytes","8192 kilobytes","16 megabytes","32 megabytes" }; static BOOL existing_key = FALSE; // For LGP set/restore static BOOL iso_size_check = TRUE; static BOOL log_displayed = FALSE; static int selection_default; BOOL enable_fixed_disks = FALSE, advanced_mode = TRUE; /* * Globals */ HINSTANCE hMainInstance; HWND hMainDialog; char szFolderPath[MAX_PATH], app_dir[MAX_PATH]; char* iso_path = NULL; float fScale = 1.0f; int default_fs; HWND hDeviceList, hCapacity, hFileSystem, hClusterSize, hLabel, hDOSType, hNBPasses, hLog = NULL; HWND hISOProgressDlg = NULL, hLogDlg = NULL, hISOProgressBar, hISOFileName, hDiskID; BOOL use_own_vesamenu = FALSE, detect_fakes = TRUE, mbr_selected_by_user = FALSE; int rufus_version[4]; extern char szStatusMessage[256]; static HANDLE format_thid = NULL; static HWND hProgress = NULL, hDOS = NULL, hSelectISO = NULL; static HICON hIconDisc, hIconDown, hIconUp; static StrArray DriveID, DriveLabel; static char szTimer[12] = "00:00:00"; static unsigned int timer; static int64_t last_iso_blocking_status; /* * The following is used to allocate slots within the progress bar * 0 means unused (no operation or no progress allocated to it) * +n means allocate exactly n bars (n percents of the progress bar) * -n means allocate a weighted slot of n from all remaining * bars. Eg if 80 slots remain and the sum of all negative entries * is 10, -4 will allocate 4/10*80 = 32 bars (32%) for OP progress */ static int nb_slots[OP_MAX]; static float slot_end[OP_MAX+1]; // shifted +1 so that we can substract 1 to OP indexes static float previous_end; /* * Convert a partition type to its human readable form using * (slightly modified) entries from GNU fdisk */ static const char* GetPartitionType(BYTE Type) { int i; for (i=0; i 4 GB if (SelectedDrive.DiskSize < i*MB) { SelectedDrive.ClusterSize[FS_FAT16].Default = 16*(ULONG)i; break; } SelectedDrive.ClusterSize[FS_FAT16].Allowed <<= 1; } SelectedDrive.ClusterSize[FS_FAT16].Allowed &= 0x0001FE00; } // FAT 32 // > 32GB FAT32 is not supported by MS and FormatEx but is achieved using fat32fomat // See: http://www.ridgecrop.demon.co.uk/index.htm?fat32format.htm // < 32 MB FAT32 is not allowed by FormatEx, so we don't bother if ((SelectedDrive.DiskSize >= 32*MB) && (SelectedDrive.DiskSize < 2*TB)) { SelectedDrive.ClusterSize[FS_FAT32].Allowed = 0x000001F8; for (i=32; i<=(32*1024); i<<=1) { // 32 MB -> 32 GB if (SelectedDrive.DiskSize < i*MB) { SelectedDrive.ClusterSize[FS_FAT32].Default = 8*(ULONG)i; break; } SelectedDrive.ClusterSize[FS_FAT32].Allowed <<= 1; } SelectedDrive.ClusterSize[FS_FAT32].Allowed &= 0x0001FE00; // Default cluster sizes in the 256MB to 32 GB range do not follow the rule above if ((SelectedDrive.DiskSize >= 256*MB) && (SelectedDrive.DiskSize < 32*GB)) { for (i=8; i<=32; i<<=1) { // 256 MB -> 32 GB if (SelectedDrive.DiskSize < i*GB) { SelectedDrive.ClusterSize[FS_FAT32].Default = ((ULONG)i/2)*1024; break; } } } // More adjustments for large drives if (SelectedDrive.DiskSize >= 32*GB) { SelectedDrive.ClusterSize[FS_FAT32].Allowed &= 0x0001C000; SelectedDrive.ClusterSize[FS_FAT32].Default = 0x00008000; } } // NTFS if (SelectedDrive.DiskSize < 256*TB) { SelectedDrive.ClusterSize[FS_NTFS].Allowed = 0x0001FE00; for (i=16; i<=256; i<<=1) { // 7 MB -> 256 TB if (SelectedDrive.DiskSize < i*TB) { SelectedDrive.ClusterSize[FS_NTFS].Default = ((ULONG)i/4)*1024; break; } } } // exFAT if (SelectedDrive.DiskSize < 256*TB) { SelectedDrive.ClusterSize[FS_EXFAT].Allowed = 0x03FFFE00; if (SelectedDrive.DiskSize < 256*MB) // < 256 MB SelectedDrive.ClusterSize[FS_EXFAT].Default = 4*1024; else if (SelectedDrive.DiskSize < 32*GB) // < 32 GB SelectedDrive.ClusterSize[FS_EXFAT].Default = 32*1024; else SelectedDrive.ClusterSize[FS_EXFAT].Default = 28*1024; } out: // Only add the filesystems we can service for (fs=0; fs= FS_MAX)) { return FALSE; } if ( (SelectedDrive.ClusterSize[FSType].Allowed == 0) || (SelectedDrive.ClusterSize[FSType].Default == 0) ) { uprintf("The drive is incompatible with FS type #%d\n", FSType); return FALSE; } for(i=0,j=0x200,k=0;j<0x10000000;i++,j<<=1) { if (j & SelectedDrive.ClusterSize[FSType].Allowed) { safe_sprintf(szClustSize, sizeof(szClustSize), "%s", ClusterSizeLabel[i]); if (j == SelectedDrive.ClusterSize[FSType].Default) { safe_strcat(szClustSize, sizeof(szClustSize), " (Default)"); default_index = k; } IGNORE_RETVAL(ComboBox_SetItemData(hClusterSize, ComboBox_AddStringU(hClusterSize, szClustSize), j)); k++; } } IGNORE_RETVAL(ComboBox_SetCurSel(hClusterSize, default_index)); return TRUE; } // Convert a file size to human readable static __inline char* size_to_hr(LARGE_INTEGER size) { int suffix = 0; static char str_size[24]; const char* sizes[] = { "", "KB", "MB", "GB", "TB" }; double hr_size = (double)size.QuadPart; while ((suffix < ARRAYSIZE(sizes)) && (hr_size >= 1024.0)) { hr_size /= 1024.0; suffix++; } if (suffix == 0) { safe_sprintf(str_size, sizeof(str_size), "%d bytes", (int)hr_size); } else { safe_sprintf(str_size, sizeof(str_size), "%0.1f %s", hr_size, sizes[suffix]); } return str_size; } /* * Fill the drive properties (size, FS, etc) */ static BOOL GetDriveInfo(void) { BOOL r; HANDLE hDrive; DWORD size; BYTE geometry[128], layout[1024], part_type; void* disk_geometry = (void*)geometry; void* drive_layout = (void*)layout; PDISK_GEOMETRY_EX DiskGeometry = (PDISK_GEOMETRY_EX)disk_geometry; PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)drive_layout; char DrivePath[] = "#:\\", tmp[512], fs_type[32]; DWORD i, nb_partitions = 0; int tmp_pos; SelectedDrive.DiskSize = 0; hDrive = GetDriveHandle(SelectedDrive.DeviceNumber, DrivePath, FALSE, FALSE); if (hDrive == INVALID_HANDLE_VALUE) return FALSE; r = DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, geometry, sizeof(geometry), &size, NULL); if (!r || size <= 0) { uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX failed for drive %c: %s\n", DrivePath[0], WindowsErrorString()); safe_closehandle(hDrive); return FALSE; } SelectedDrive.DiskSize = DiskGeometry->DiskSize.QuadPart; memcpy(&SelectedDrive.Geometry, &DiskGeometry->Geometry, sizeof(DISK_GEOMETRY)); uprintf("Cylinders: %lld, TracksPerCylinder: %d, SectorsPerTrack: %d, BytesPerSector: %d\n", DiskGeometry->Geometry.Cylinders, DiskGeometry->Geometry.TracksPerCylinder, DiskGeometry->Geometry.SectorsPerTrack, DiskGeometry->Geometry.BytesPerSector); r = DeviceIoControl(hDrive, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, layout, sizeof(layout), &size, NULL ); if (!r || size <= 0) { uprintf("IOCTL_DISK_GET_DRIVE_LAYOUT_EX failed for drive %c: %s\n", DrivePath[0], WindowsErrorString()); } else { switch (DriveLayout->PartitionStyle) { case PARTITION_STYLE_MBR: for (tmp_pos=0, i=0; (iPartitionCount)&&(tmp_pos>=0); i++) { if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) { nb_partitions++; uprintf("Partition %d:\n", i+1); part_type = DriveLayout->PartitionEntry[i].Mbr.PartitionType; uprintf(" Type: %s (0x%02x)\r\n Size: %s\r\n Boot: %s\r\n Recognized: %s\r\n Hidden Sectors: %d\n", GetPartitionType(part_type), part_type, size_to_hr(DriveLayout->PartitionEntry[i].PartitionLength), DriveLayout->PartitionEntry[i].Mbr.BootIndicator?"Yes":"No", DriveLayout->PartitionEntry[i].Mbr.RecognizedPartition?"Yes":"No", DriveLayout->PartitionEntry[i].Mbr.HiddenSectors); tmp_pos = safe_sprintf(&tmp[tmp_pos], sizeof(tmp)-tmp_pos, "Partition %d: %s (%s)\n", i+1, GetPartitionType(part_type), size_to_hr(DriveLayout->PartitionEntry[i].PartitionLength)); } } uprintf("Partition type: MBR, NB Partitions: %d\n", nb_partitions); tmp[sizeof(tmp)-1] = 0; CreateTooltip(hCapacity, tmp, -1); break; case PARTITION_STYLE_GPT: uprintf("Partition type: GPT, NB Partitions: %d\n", DriveLayout->PartitionCount); break; default: uprintf("Partition type: RAW\n"); break; } } safe_closehandle(hDrive); if (!DefineClusterSizes()) { uprintf("no file system is selectable for this drive\n"); return FALSE; } // re-select existing FS if it's one we know if (GetVolumeInformationA(DrivePath, NULL, 0, NULL, NULL, NULL, fs_type, sizeof(fs_type))) { for (SelectedDrive.FSType=FS_MAX-1; SelectedDrive.FSType>=0; SelectedDrive.FSType--) { if (safe_strcmp(fs_type, FileSystemLabel[SelectedDrive.FSType]) == 0) { break; } } } else { SelectedDrive.FSType = FS_UNKNOWN; } for (i=0; i pick default for (i=0; i enable formatting EnableWindow(GetDlgItem(hMainDialog, IDC_START), TRUE); return SetClusterSizes((int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))); } static void SetFSFromISO(void) { int i, fs, selected_fs = FS_UNKNOWN; uint32_t fs_mask = 0; if (iso_path == NULL) return; // Create a mask of all the FS's available for (i=0; i