From 14fa3de4b67fbb23766810fe6ae4067eada6fcb4 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Mon, 29 Jun 2020 00:45:24 +0200 Subject: Windows: Fallback to Windows native formatting tool if we fail to format a volume as NTFS/exFAT/ReFS using FormatEx function from fmifs.dll --- src/Common/Format.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/Common/Format.h | 1 + 2 files changed, 153 insertions(+), 2 deletions(-) diff --git a/src/Common/Format.c b/src/Common/Format.c index da6054e6..76923c6b 100644 --- a/src/Common/Format.c +++ b/src/Common/Format.c @@ -762,7 +762,7 @@ error: } mountOptions.ReadOnly = FALSE; - mountOptions.Removable = FALSE; + mountOptions.Removable = TRUE; /* mount as removal media to allow formatting without admin rights */ mountOptions.ProtectHiddenVolume = FALSE; mountOptions.PreserveTimestamp = bPreserveTimestamp; mountOptions.PartitionInInactiveSysEncScope = FALSE; @@ -778,12 +778,18 @@ error: nStatus = ERR_VOL_MOUNT_FAILED; goto fv_end; } - + if (!Silent && !IsAdmin () && IsUacSupported ()) retCode = UacFormatFs (volParams->hwndDlg, driveNo, volParams->clusterSize, fsType); else retCode = FormatFs (driveNo, volParams->clusterSize, fsType); + if (retCode != TRUE) + { + /* fallback to calling Windows native formatting tool */ + retCode = ExternalFormatFs (driveNo, volParams->clusterSize, fsType); + } + if (retCode != TRUE) { if (!UnmountVolumeAfterFormatExCall (volParams->hwndDlg, driveNo) && !Silent) @@ -1094,6 +1100,150 @@ BOOL 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) +{ + wchar_t exePath[MAX_PATH] = {0}; + HANDLE hChildStd_IN_Rd = NULL; + HANDLE hChildStd_IN_Wr = NULL; + HANDLE hChildStd_OUT_Rd = NULL; + HANDLE hChildStd_OUT_Wr = NULL; + WCHAR szFsFormat[16]; + TCHAR szCmdline[2 * MAX_PATH]; + STARTUPINFO siStartInfo; + PROCESS_INFORMATION piProcInfo; + BOOL bSuccess = FALSE; + SECURITY_ATTRIBUTES saAttr; + + switch (fsType) + { + case FILESYS_NTFS: + StringCchCopyW (szFsFormat, ARRAYSIZE (szFsFormat),L"NTFS"); + break; + case FILESYS_EXFAT: + StringCchCopyW (szFsFormat, ARRAYSIZE (szFsFormat),L"exFAT"); + break; + case FILESYS_REFS: + StringCchCopyW (szFsFormat, ARRAYSIZE (szFsFormat),L"ReFS"); + break; + default: + return FALSE; + } + + /* Set the bInheritHandle flag so pipe handles are inherited. */ + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + /* Create a pipe for the child process's STDOUT. */ + if ( !CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0) ) + return FALSE; + + /* Ensure the read handle to the pipe for STDOUT is not inherited. */ + /* Create a pipe for the child process's STDIN. */ + if ( !SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) + || !CreatePipe(&hChildStd_IN_Rd, &hChildStd_IN_Wr, &saAttr, 0)) + { + CloseHandle (hChildStd_OUT_Rd); + CloseHandle (hChildStd_OUT_Wr); + return FALSE; + } + + /* Ensure the write handle to the pipe for STDIN is not inherited. */ + if ( !SetHandleInformation(hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) + { + CloseHandle (hChildStd_OUT_Rd); + CloseHandle (hChildStd_OUT_Wr); + CloseHandle (hChildStd_IN_Rd); + CloseHandle (hChildStd_IN_Wr); + return FALSE; + } + + if (GetSystemDirectory (exePath, MAX_PATH)) + { + StringCchCatW(exePath, ARRAYSIZE(exePath), L"\\format.com"); + } + 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); + + if (clusterSize) + { + WCHAR szSize[8]; + uint32 unitSize = (uint32) clusterSize * FormatSectorSize; + if (unitSize <= 8192) + StringCbPrintf (szSize, sizeof (szSize), L"%d", unitSize); + else if (unitSize < BYTES_PER_MB) + { + StringCbPrintf (szSize, sizeof (szSize), L"%dK", unitSize / BYTES_PER_KB); + } + else + StringCbPrintf (szSize, sizeof (szSize), L"%dM", unitSize / BYTES_PER_MB); + + StringCbCat (szCmdline, sizeof (szCmdline), L" /A:"); + StringCbCat (szCmdline, sizeof (szCmdline), szSize); + } + + + ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); + + /* Set up members of the STARTUPINFO structure. + This structure specifies the STDIN and STDOUT handles for redirection. + */ + ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = hChildStd_OUT_Wr; + siStartInfo.hStdOutput = hChildStd_OUT_Wr; + siStartInfo.hStdInput = hChildStd_IN_Rd; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + /* Create the child process. */ + bSuccess = CreateProcess(NULL, + szCmdline, // command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + &piProcInfo); // receives PROCESS_INFORMATION + + if (bSuccess) + { + /* Unblock the format process by simulating hit on ENTER key */ + DWORD dwExitCode, dwWritten; + LPCSTR newLine = "\n"; + + WriteFile(hChildStd_IN_Wr, (LPCVOID) newLine, 1, &dwWritten, NULL); + + /* 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; + } + else + bSuccess = FALSE; + + CloseHandle (piProcInfo.hThread); + CloseHandle (piProcInfo.hProcess); + } + + CloseHandle(hChildStd_OUT_Wr); + CloseHandle(hChildStd_OUT_Rd); + CloseHandle(hChildStd_IN_Rd); + CloseHandle(hChildStd_IN_Wr); + + return bSuccess; +} + BOOL WriteSector (void *dev, char *sector, char *write_buf, int *write_buf_cnt, __int64 *nSecNo, PCRYPTO_INFO cryptoInfo) diff --git a/src/Common/Format.h b/src/Common/Format.h index 4ce1b8c7..139607e5 100644 --- a/src/Common/Format.h +++ b/src/Common/Format.h @@ -76,6 +76,7 @@ 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); uint64 GetVolumeDataAreaSize (BOOL hiddenVolume, uint64 volumeSize); int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, __int64 num_sectors, void *dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat); BOOL WriteSector ( void *dev , char *sector , char *write_buf , int *write_buf_cnt , __int64 *nSecNo , PCRYPTO_INFO cryptoInfo ); -- cgit v1.2.3