From 0bfed6553d08131fd8e0bd725642ff8509a2a1d4 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Sat, 1 Jul 2023 15:16:46 +0200 Subject: Windows: Fix formatting issue during volume creation by using /Y for format.com and specifying removal parameter in FormatEx The usage of /Y parameter in format.com simplifies the logic and makes the code robust since we don't need to send \n to the format.com process. Specifying RemovableMedia parameter to FormatEx fixes its failure in Windows 10 and later to perform quick format. This is also more adequate since we are mounting the volume as removable media for the formatting process. We also add better error management in order to display adequate error message to the user in case of failure --- src/Common/Format.c | 104 +++++++++++++++++++++++++++++++++++------------- src/Common/Format.h | 8 ++-- src/Common/Language.xml | 2 + 3 files changed, 83 insertions(+), 31 deletions(-) (limited to 'src/Common') diff --git a/src/Common/Format.c b/src/Common/Format.c index 15ca9518..d5514bf9 100644 --- a/src/Common/Format.c +++ b/src/Common/Format.c @@ -797,16 +797,26 @@ error: } retCode = ExternalFormatFs (driveNo, volParams->clusterSize, fsType); - if (retCode != TRUE) + if (retCode != 0) { + wchar_t auxLine[2048]; + StringCbPrintfW (auxLine, sizeof(auxLine), GetString ("FORMAT_EXTERNAL_FAILED"), retCode); + WarningDirect(auxLine, volParams->hwndDlg); + /* fallback to using FormatEx function from fmifs.dll */ if (!Silent && !IsAdmin () && IsUacSupported ()) retCode = UacFormatFs (volParams->hwndDlg, driveNo, volParams->clusterSize, fsType); else retCode = FormatFs (driveNo, volParams->clusterSize, fsType); + + if (retCode != 0) + { + StringCbPrintfW (auxLine, sizeof(auxLine), GetString ("FORMATEX_API_FAILED"), FormatExGetMessage(retCode)); + ErrorDirect(auxLine, volParams->hwndDlg); + } } - if (retCode != TRUE) + if (retCode != 0) { if (!UnmountVolumeAfterFormatExCall (volParams->hwndDlg, driveNo) && !Silent) MessageBoxW (volParams->hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND); @@ -1030,6 +1040,46 @@ fail: volatile BOOLEAN FormatExError; +volatile int FormatExErrorCommand; + +LPCWSTR FormatExGetMessage (int command) +{ + static WCHAR h_szMsg[32]; + switch (command) + { + case FMIFS_DONE: + return L"FORMAT_FINISHED"; + case FMIFS_STRUCTURE_PROGRESS: + return L"FORMAT_STRUCTURE_PROGRESS"; + case FMIFS_MEDIA_WRITE_PROTECTED: + return L"FORMAT_MEDIA_WRITE_PROTECTED"; + case FMIFS_INCOMPATIBLE_FILE_SYSTEM: + return L"FORMAT_INCOMPATIBLE_FILE_SYSTEM"; + case FMIFS_ACCESS_DENIED: + return L"FORMAT_ACCESS_DENIED"; + case FMIFS_VOLUME_IN_USE: + return L"FORMAT_VOLUME_IN_USE"; + case FMIFS_CLUSTER_SIZE_TOO_SMALL: + return L"FORMAT_CLUSTER_SIZE_TOO_SMALL"; + case FMIFS_CLUSTER_SIZE_TOO_BIG: + return L"FORMAT_CLUSTER_SIZE_TOO_BIG"; + case FMIFS_VOLUME_TOO_SMALL: + return L"FORMAT_VOLUME_TOO_SMALL"; + case FMIFS_VOLUME_TOO_BIG: + return L"FORMAT_VOLUME_TOO_BIG"; + case FMIFS_NO_MEDIA_IN_DRIVE: + return L"FORMAT_NO_MEDIA_IN_DRIVE"; + case FMIFS_DEVICE_NOT_READY: + return L"FORMAT_DEVICE_NOT_READY"; + case FMIFS_BAD_LABEL: + return L"FORMAT_BAD_LABEL"; + case FMIFS_CANT_QUICK_FORMAT: + return L"FORMAT_CANT_QUICK_FORMAT"; + default: + StringCbPrintfW (h_szMsg, sizeof(h_szMsg), L"0x%.8X", command); + return h_szMsg; + } +} BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID parameter) { @@ -1086,10 +1136,14 @@ BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID paramet FormatExError = TRUE; break; } + if (FormatExError) + { + FormatExErrorCommand = command; + } return (FormatExError? FALSE : TRUE); } -BOOL FormatFs (int driveNo, int clusterSize, int fsType) +int FormatFs (int driveNo, int clusterSize, int fsType) { wchar_t dllPath[MAX_PATH] = {0}; WCHAR dir[8] = { (WCHAR) driveNo + L'A', 0 }; @@ -1135,29 +1189,31 @@ BOOL FormatFs (int driveNo, int clusterSize, int fsType) StringCchCatW (dir, ARRAYSIZE(dir), L":\\"); FormatExError = TRUE; + FormatExErrorCommand = 0; // Windows sometimes fails to format a volume (hosted on a removable medium) as NTFS. // It often helps to retry several times. for (i = 0; i < 50 && FormatExError; i++) { FormatExError = FALSE; - FormatEx (dir, FMIFS_HARDDISK, szFsFormat, szLabel, TRUE, clusterSize * FormatSectorSize, FormatExCallback); + FormatExErrorCommand = 0; + FormatEx (dir, FMIFS_REMOVAL, szFsFormat, szLabel, TRUE, clusterSize * FormatSectorSize, FormatExCallback); } // The device may be referenced for some time after FormatEx() returns Sleep (4000); FreeLibrary (hModule); - return FormatExError? FALSE : TRUE; + return FormatExError? FormatExErrorCommand : 0; } -BOOL FormatNtfs (int driveNo, int clusterSize) +int FormatNtfs (int driveNo, int clusterSize) { return FormatFs (driveNo, clusterSize, FILESYS_NTFS); } /* call Windows format.com program to perform formatting */ -BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType) +int ExternalFormatFs (int driveNo, int clusterSize, int fsType) { wchar_t exePath[MAX_PATH] = {0}; HANDLE hChildStd_IN_Rd = NULL; @@ -1170,6 +1226,7 @@ BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType) PROCESS_INFORMATION piProcInfo; BOOL bSuccess = FALSE; SECURITY_ATTRIBUTES saAttr; + int iRet = 0; switch (fsType) { @@ -1222,7 +1279,7 @@ BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType) else StringCchCopyW(exePath, ARRAYSIZE(exePath), L"C:\\Windows\\System32\\format.com"); - StringCbPrintf (szCmdline, sizeof(szCmdline), L"%s %c: /FS:%s /Q /X /V:\"\"", exePath, (WCHAR) driveNo + L'A', szFsFormat); + StringCbPrintf (szCmdline, sizeof(szCmdline), L"%s %c: /FS:%s /Q /X /V:\"\" /Y", exePath, (WCHAR) driveNo + L'A', szFsFormat); if (clusterSize) { @@ -1269,42 +1326,33 @@ BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType) if (bSuccess) { - /* Unblock the format process by simulating hit on ENTER key */ - DWORD dwExitCode, dwWritten; - LPCSTR newLine = "\n"; - - if (WriteFile(hChildStd_IN_Wr, (LPCVOID) newLine, 1, &dwWritten, NULL)) - { - /* wait for the format process to finish */ - WaitForSingleObject (piProcInfo.hProcess, INFINITE); - } - else - { - /* we failed to write "\n". Maybe process exited too quickly. We wait 1 second */ - WaitForSingleObject (piProcInfo.hProcess, 1000); - } + DWORD dwExitCode; + + /* wait for the format process to finish */ + WaitForSingleObject (piProcInfo.hProcess, INFINITE); /* check if it was successfull */ if (GetExitCodeProcess (piProcInfo.hProcess, &dwExitCode)) { - if (dwExitCode == 0) - bSuccess = TRUE; - else - bSuccess = FALSE; + iRet = (int) dwExitCode; /* dwExitCode will be 0 in case of success */ } else - bSuccess = FALSE; + iRet = (int) GetLastError(); CloseHandle (piProcInfo.hThread); CloseHandle (piProcInfo.hProcess); } + else + { + iRet = (int) GetLastError(); + } CloseHandle(hChildStd_OUT_Wr); CloseHandle(hChildStd_OUT_Rd); CloseHandle(hChildStd_IN_Rd); CloseHandle(hChildStd_IN_Wr); - return bSuccess; + return iRet; } BOOL WriteSector (void *dev, char *sector, diff --git a/src/Common/Format.h b/src/Common/Format.h index 826b8f6c..204feee1 100644 --- a/src/Common/Format.h +++ b/src/Common/Format.h @@ -69,14 +69,16 @@ FORMAT_VOL_PARAMETERS; #define FMIFS_CHECKDISK_PROGRESS 0x19 #define FMIFS_READ_ONLY_MODE 0x20 +#define FMIFS_REMOVAL 0xB #define FMIFS_HARDDISK 0xC extern int FormatWriteBufferSize; int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams); -BOOL FormatNtfs (int driveNo, int clusterSize); -BOOL FormatFs (int driveNo, int clusterSize, int fsType); -BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType); +int FormatNtfs (int driveNo, int clusterSize); +int FormatFs (int driveNo, int clusterSize, int fsType); +int ExternalFormatFs (int driveNo, int clusterSize, int fsType); +LPCWSTR FormatExGetMessage (int command); uint64 GetVolumeDataAreaSize (BOOL hiddenVolume, uint64 volumeSize); int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, unsigned __int64 num_sectors, void *dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat, BOOL bDevice); BOOL WriteSector ( void *dev , char *sector , char *write_buf , int *write_buf_cnt , unsigned __int64 *nSecNo , unsigned __int64 startSector, PCRYPTO_INFO cryptoInfo ); diff --git a/src/Common/Language.xml b/src/Common/Language.xml index a34187a5..3399ccbc 100644 --- a/src/Common/Language.xml +++ b/src/Common/Language.xml @@ -1622,6 +1622,8 @@ EMV path is invalid. Unable to build a keyfile from the EMV card's data.\n\nOne of the following is missing:\n- ICC Public Key Certificate.\n- Issuer Public Key Certificate.\n- CPCL data. No card in the reader.\n\nPlease make sure the card is correctly slotted. + Windows format.com command failed to format the volume as NTFS/exFAT/ReFS: Error 0x%.8X.\n\nFalling back to using Windows FormatEx API. + Windows FormatEx API failed to format the volume as NTFS/exFAT/ReFS.\n\nFailure status = %s. -- cgit v1.2.3