diff --git a/license.h b/license.h index 20790422..407d561a 100644 --- a/license.h +++ b/license.h @@ -30,6 +30,11 @@ const char* additional_copyrights = "http://www.gnu.org/software/fdisk\r\n" "GNU General Public License (GPL) v3 or later\r\n" "\r\n" +"fmifs.dll usage based on Formatx by Mark Russinovich:\r\n" +"http://doc.sch130.nsc.ru/www.sysinternals.com/ntw2k/source/fmifs.shtml\r\n" +"http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/fmifs\r\n" +"Public Domain\r\n" +"\r\n" "About and License dialogs inspired by WinSCP\r\n" "Copyright (c) 2000-2011 Martin Prikryl\r\n" "GNU General Public License (GPL) v3 or later"; diff --git a/rufus.c b/rufus.c index 5a50670a..489f4f7c 100644 --- a/rufus.c +++ b/rufus.c @@ -35,12 +35,9 @@ #include #include #include +#include -// http://doc.sch130.nsc.ru/www.sysinternals.com/ntw2k/source/fmifs.shtml -// http://svn.reactos.org/svn/reactos/trunk/reactos/include/reactos/libs/fmifs/ -//#include // http://git.kernel.org/?p=fs/ext2/e2fsprogs.git;a=blob;f=misc/badblocks.c - // http://ms-sys.sourceforge.net/ // http://thestarman.pcministry.com/asm/mbr/MSWIN41.htm @@ -77,6 +74,7 @@ struct { static HWND hDeviceList, hCapacity, hFileSystem, hLabel; static HWND hDeviceTooltip = NULL, hFSTooltip = NULL; static StrArray DriveID, DriveLabel; +static DWORD FormatErr; #ifdef RUFUS_DEBUG void _uprintf(const char *format, ...) @@ -282,12 +280,12 @@ static BOOL GetDriveInfo(void) if (DriveLayout->PartitionEntry[i].Mbr.PartitionType != PARTITION_ENTRY_UNUSED) { uprintf("Partition #%d:\n", ++nb_partitions); if (hFSTooltip == NULL) { - safe_sprintf(tmp, sizeof(tmp), "Current file system: %s (0x%02X)", + safe_sprintf(tmp, sizeof(tmp), "Current file system: %s (0x%02x)", GetPartitionType(DriveLayout->PartitionEntry[i].Mbr.PartitionType), DriveLayout->PartitionEntry[i].Mbr.PartitionType); hFSTooltip = CreateTooltip(hFileSystem, tmp, -1); } - uprintf(" Type: %s (0x%02X)\n Boot: %s\n Recognized: %s\n Hidden Sectors: %d\n", + uprintf(" Type: %s (0x%02x)\n Boot: %s\n Recognized: %s\n Hidden Sectors: %d\n", GetPartitionType(DriveLayout->PartitionEntry[i].Mbr.PartitionType), DriveLayout->PartitionEntry[i].Mbr.PartitionType, DriveLayout->PartitionEntry[i].Mbr.BootIndicator?"Yes":"No", @@ -452,6 +450,7 @@ BOOL CreatePartition(HANDLE hDrive) BOOL r; DWORD size; + StatusPrintf("Partitioning..."); DriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR; DriveLayoutEx->PartitionCount = 4; // Must be multiple of 4 for MBR DriveLayoutEx->Mbr.Signature = GetTickCount(); @@ -484,15 +483,126 @@ BOOL CreatePartition(HANDLE hDrive) safe_closehandle(hDrive); return FALSE; } - StatusPrintf("Successfully Created Partition"); return TRUE; } +/* + * FormatEx callback. Return FALSE to halt operations + */ +BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command, DWORD Action, PVOID Data) +{ + DWORD* percent; + int task_number = 0; + + switch(Command) { + case FCC_PROGRESS: + percent = (DWORD*)Data; +// PostMessage(hMainDialog, UM_FORMAT_PROGRESS, (WPARAM)*percent, (LPARAM)0); + uprintf("%d percent completed.\n", *percent); + break; + case FCC_STRUCTURE_PROGRESS: // No progress on quick format + uprintf("format task %d/n completed.\n", ++task_number); + break; + case FCC_DONE: + if(*(BOOLEAN*)Data == FALSE) { + uprintf("Error while formatting.\n"); + if (FormatErr == 0) + FormatErr = FCC_DONE; + } + break; + case FCC_INCOMPATIBLE_FILE_SYSTEM: + uprintf("Incompatible File System\n"); + FormatErr = Command; + break; + case FCC_ACCESS_DENIED: + uprintf("Access denied\n"); + FormatErr = Command; + break; + case FCC_MEDIA_WRITE_PROTECTED: + uprintf("Media is write protected\n"); + FormatErr = Command; + break; + case FCC_VOLUME_IN_USE: + uprintf("Volume is in use\n"); + FormatErr = Command; + break; + case FCC_CANT_QUICK_FORMAT: + uprintf("Cannot quick format this volume\n"); + FormatErr = Command; + break; + case FCC_BAD_LABEL: + uprintf("Bad label\n"); + break; + case FCC_OUTPUT: + uprintf("%s\n", ((PTEXTOUTPUT)Data)->Output); + break; + case FCC_CLUSTER_SIZE_TOO_SMALL: + uprintf("Allocation unit size is too small\n"); + FormatErr = Command; + break; + case FCC_CLUSTER_SIZE_TOO_BIG: + uprintf("Allocation unit size is too big\n"); + FormatErr = Command; + break; + case FCC_VOLUME_TOO_SMALL: + uprintf("Volume is too small\n"); + FormatErr = Command; + break; + case FCC_VOLUME_TOO_BIG: + uprintf("Volume is too big\n"); + FormatErr = Command; + break; + case FCC_NO_MEDIA_IN_DRIVE: + uprintf("No media\n"); + FormatErr = Command; + break; + default: + uprintf("FormatExCallback: received unhandled command %X\n", Command); + break; + } + return (FormatErr == 0); +} + +BOOL Format(char DriveLetter) +{ + BOOL r = FALSE; + PF_DECL(FormatEx); + WCHAR wDriveRoot[] = L"?:\\"; + WCHAR wFSType[32]; + WCHAR wLabel[128]; + + wDriveRoot[0] = (WCHAR)DriveLetter; + StatusPrintf("Formatting..."); + PF_INIT_OR_OUT(FormatEx, fmifs); + + // TODO: properly set MediaType + FormatErr = 0; + GetWindowText(hFileSystem, wFSType, ARRAYSIZE(wFSType)); + GetWindowText(hLabel, wLabel, ARRAYSIZE(wLabel)); + pfFormatEx(wDriveRoot, RemovableMedia, wFSType, wLabel, + (IsDlgButtonChecked(hMainDialog, IDC_QUICKFORMAT) == BST_CHECKED), + 4096, FormatExCallback); + if (FormatErr == 0) { + uprintf("Format completed.\n"); + StatusPrintf("Done."); + r = TRUE; + } else { + uprintf("Format error: %X\n", FormatErr); + StatusPrintf("FAILED."); + } + +out: + return r; +} + +// TODO: create a thread for this BOOL FormatDrive(DWORD num) { HANDLE hDrive; - BOOL r; + BOOL r = FALSE; + char drive_letter; + int i; if (!GetDriveHandle(num, &hDrive, NULL, TRUE)) { // TODO: report an error for exclusive access @@ -500,8 +610,24 @@ BOOL FormatDrive(DWORD num) } r = CreatePartition(hDrive); + safe_closehandle(hDrive); + if (!r) return FALSE; + + // Make sure we can reopen the drive before trying to format it + for (i=0; i<10; i++) { + Sleep(500); + if (GetDriveHandle(num, &hDrive, &drive_letter, FALSE)) { + break; + } + } + if (i >= 10) { + uprintf("Unable to reopen drive after partitioning\n"); + return FALSE; + } + safe_closehandle(hDrive); + + r = Format(drive_letter); - CloseHandle(hDrive); return r; } @@ -629,8 +755,12 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA switch (message) { case WM_DEVICECHANGE: - GetUSBDevices(); - return (INT_PTR)TRUE; + // TODO: also prevent detect during format + if ((wParam == DBT_DEVICEARRIVAL) || (wParam == DBT_DEVICEREMOVECOMPLETE)) { + GetUSBDevices(); + return (INT_PTR)TRUE; + } + break; case WM_INITDIALOG: hMainDialog = hDlg; @@ -646,8 +776,11 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA CreateStatusBar(); // Display the version in the right area of the status bar SendMessageA(GetDlgItem(hDlg, IDC_STATUS), SB_SETTEXTA, SBT_OWNERDRAW | 1, (LPARAM)APP_VERSION); + // Create the string array StrArrayCreate(&DriveID, MAX_DRIVES); StrArrayCreate(&DriveLabel, MAX_DRIVES); + // Set the quick format checkbox + CheckDlgButton(hDlg, IDC_QUICKFORMAT, BST_CHECKED); GetUSBDevices(); return (INT_PTR)TRUE; @@ -706,6 +839,10 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA PostQuitMessage(0); break; + case UM_FORMAT_PROGRESS: + uprintf("Got UM_FORMAT_PROGRESS with percent %d\n", (DWORD)wParam); + return (INT_PTR)TRUE; + } return (INT_PTR)FALSE; } diff --git a/rufus.h b/rufus.h index dadba189..0b5fa7aa 100644 --- a/rufus.h +++ b/rufus.h @@ -15,6 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include // for MEDIA_TYPE #pragma once @@ -98,6 +99,12 @@ extern void _uprintf(const char *format, ...); #define uprintf(...) #endif +/* Custom Windows messages */ +enum user_message_type { + UM_FORMAT_PROGRESS = WM_APP, + UM_FORMAT_COMPLETED +}; + /* Custom notifications */ enum MessageType { MSG_INFO, @@ -106,6 +113,8 @@ enum MessageType { }; /* File system indexes in our FS combobox */ +// TODO: FormatEx should support "NTFS", "FAT", "FAT32", "UDF", and "EXFAT" as per +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa819439.aspx enum _FSType { FS_FAT16 = 0, FS_FAT32, @@ -118,3 +127,87 @@ typedef struct { ULONG DeviceNumber; ULONG PartitionNumber; } STORAGE_DEVICE_NUMBER_REDEF; + +/* + * typedefs for the function prototypes. Use the something like: + * PF_DECL(FormatEx); + * which translates to: + * FormatEx_t pfFormatEx = NULL; + * in your code, to declare the entrypoint and then use: + * PF_INIT(FormatEx, fmifs); + * which translates to: + * pfFormatEx = (FormatEx_t) GetProcAddress(GetDLLHandle("fmifs"), "FormatEx"); + * to make it accessible. + */ +static __inline HMODULE GetDLLHandle(char* szDLLName) +{ + HMODULE h = NULL; + if ((h = GetModuleHandleA(szDLLName)) == NULL) + h = LoadLibraryA(szDLLName); + return h; +} +#define PF_DECL(proc) proc##_t pf##proc = NULL +#define PF_INIT(proc, dllname) pf##proc = (proc##_t) GetProcAddress(GetDLLHandle(#dllname), #proc) +#define PF_INIT_OR_OUT(proc, dllname) \ + PF_INIT(proc, dllname); if (pf##proc == NULL) { \ + uprintf("unable to access %s DLL: %s", #dllname, \ + WindowsErrorString()); goto out; } + +/* Callback command types (some errorcode were filled from HPUSBFW V2.2.3 and their + designation from msdn.microsoft.com/en-us/library/windows/desktop/aa819439.aspx */ +typedef enum { + FCC_PROGRESS, + FCC_DONE_WITH_STRUCTURE, + FCC_UNKNOWN2, + FCC_INCOMPATIBLE_FILE_SYSTEM, + FCC_UNKNOWN4, + FCC_UNKNOWN5, + FCC_ACCESS_DENIED, + FCC_MEDIA_WRITE_PROTECTED, + FCC_VOLUME_IN_USE, + FCC_CANT_QUICK_FORMAT, + FCC_UNKNOWNA, + FCC_DONE, + FCC_BAD_LABEL, + FCC_UNKNOWND, + FCC_OUTPUT, + FCC_STRUCTURE_PROGRESS, + FCC_CLUSTER_SIZE_TOO_SMALL, + FCC_CLUSTER_SIZE_TOO_BIG, + FCC_VOLUME_TOO_SMALL, + FCC_VOLUME_TOO_BIG, + FCC_NO_MEDIA_IN_DRIVE, +} FILE_SYSTEM_CALLBACK_COMMAND; + +typedef struct { + DWORD Lines; + CHAR* Output; +} TEXTOUTPUT, *PTEXTOUTPUT; + +typedef BOOLEAN (__stdcall *FILE_SYSTEM_CALLBACK)( + FILE_SYSTEM_CALLBACK_COMMAND Command, + ULONG Action, + PVOID Data +); + +/* Parameter naming aligned to + http://msdn.microsoft.com/en-us/library/windows/desktop/aa819439.aspx */ +typedef VOID (WINAPI *FormatEx_t)( + WCHAR* DriveRoot, + MEDIA_TYPE MediaType, // See WinIoCtl.h + WCHAR* FileSystemTypeName, + WCHAR* Label, + BOOL QuickFormat, + ULONG DesiredUnitAllocationSize, + FILE_SYSTEM_CALLBACK Callback +); + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa383357.aspx */ +typedef enum { + FPF_COMPRESSED = 0x01 +} FILE_SYSTEM_PROP_FLAG; + +typedef BOOLEAN (WINAPI* EnableVolumeCompression_t)( + WCHAR* DriveRoot, + ULONG CompressionFlags // FILE_SYSTEM_PROP_FLAG +);