diff options
Diffstat (limited to 'src/Common/Format.c')
-rw-r--r-- | src/Common/Format.c | 65 |
1 files changed, 54 insertions, 11 deletions
diff --git a/src/Common/Format.c b/src/Common/Format.c index 6c3e2fff..7eff80e6 100644 --- a/src/Common/Format.c +++ b/src/Common/Format.c @@ -191,61 +191,61 @@ begin_format: DWORD dwResult; int nPass; if (FakeDosNameForDevice (volParams->volumePath, dosDev, sizeof(dosDev), devName, sizeof(devName), FALSE) != 0) return ERR_OS_ERROR; if (IsDeviceMounted (devName)) { if ((dev = DismountDrive (devName, volParams->volumePath)) == INVALID_HANDLE_VALUE) { Error ("FORMAT_CANT_DISMOUNT_FILESYS", hwndDlg); nStatus = ERR_DONT_REPORT; goto error; } /* Gain "raw" access to the partition (it contains a live filesystem and the filesystem driver would otherwise prevent us from writing to hidden sectors). */ if (!DeviceIoControl (dev, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0, &dwResult, NULL)) { bFailedRequiredDASD = TRUE; } } - else if (IsOSAtLeast (WIN_VISTA) && driveLetter == -1) + else if (driveLetter == -1) { // Windows Vista doesn't allow overwriting sectors belonging to an unformatted partition // to which no drive letter has been assigned under the system. This problem can be worked // around by assigning a drive letter to the partition temporarily. wchar_t szDriveLetter[] = { L'A', L':', 0 }; wchar_t rootPath[] = { L'A', L':', L'\\', 0 }; wchar_t uniqVolName[MAX_PATH+1] = { 0 }; int tmpDriveLetter = -1; BOOL bResult = FALSE; tmpDriveLetter = GetFirstAvailableDrive (); if (tmpDriveLetter != -1) { rootPath[0] += (wchar_t) tmpDriveLetter; szDriveLetter[0] += (wchar_t) tmpDriveLetter; if (DefineDosDevice (DDD_RAW_TARGET_PATH, szDriveLetter, volParams->volumePath)) { bResult = GetVolumeNameForVolumeMountPoint (rootPath, uniqVolName, MAX_PATH); DefineDosDevice (DDD_RAW_TARGET_PATH|DDD_REMOVE_DEFINITION|DDD_EXACT_MATCH_ON_REMOVE, szDriveLetter, volParams->volumePath); if (bResult && SetVolumeMountPoint (rootPath, uniqVolName)) { // The drive letter can be removed now @@ -318,137 +318,180 @@ begin_format: char buf [2 * TC_MAX_VOLUME_SECTOR_SIZE]; DWORD bw; // Perform pseudo "quick format" so that the filesystem driver does not prevent us from // formatting hidden sectors memset (buf, 0, sizeof (buf)); if (!WriteFile (dev, buf, sizeof (buf), &bw, NULL)) { nStatus = ERR_OS_ERROR; goto error; } FlushFileBuffers (dev); CloseHandle (dev); dev = INVALID_HANDLE_VALUE; } } if (DeviceIoControl (dev, FSCTL_IS_VOLUME_MOUNTED, NULL, 0, NULL, 0, &dwResult, NULL)) { Error ("FORMAT_CANT_DISMOUNT_FILESYS", hwndDlg); nStatus = ERR_DONT_REPORT; goto error; } } else { /* File-hosted volume */ BOOL speedupFileCreation = FALSE; + BOOL delayedSpeedupFileCreation = FALSE; // speedup for file creation only makes sens when using quick format for non hidden volumes if (!volParams->hiddenVol && !bInstantRetryOtherFilesys && volParams->quickFormat && volParams->fastCreateFile) { // we set required privileges to speedup file creation before we create the file so that the file handle inherits the privileges if (!SetPrivilege(SE_MANAGE_VOLUME_NAME, TRUE)) { DWORD dwLastError = GetLastError(); - if (Silent || (MessageBoxW(hwndDlg, GetString ("ADMIN_PRIVILEGES_WARN_MANAGE_VOLUME"), lpszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) == IDNO)) + if (!IsAdmin () && IsUacSupported ()) + { + speedupFileCreation = TRUE; + delayedSpeedupFileCreation = TRUE; + } + else if (Silent || (MessageBoxW(hwndDlg, GetString ("ADMIN_PRIVILEGES_WARN_MANAGE_VOLUME"), lpszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) == IDNO)) { SetLastError(dwLastError); nStatus = ERR_OS_ERROR; goto error; } } else { speedupFileCreation = TRUE; } } dev = CreateFile (volParams->volumePath, GENERIC_READ | GENERIC_WRITE, (volParams->hiddenVol || bInstantRetryOtherFilesys) ? (FILE_SHARE_READ | FILE_SHARE_WRITE) : 0, NULL, (volParams->hiddenVol || bInstantRetryOtherFilesys) ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL); if (dev == INVALID_HANDLE_VALUE) { nStatus = ERR_OS_ERROR; goto error; } else if (volParams->hiddenVol && bPreserveTimestamp) { // ensure that Last Access and Last Write timestamps are not modified ftLastAccessTime.dwHighDateTime = 0xFFFFFFFF; ftLastAccessTime.dwLowDateTime = 0xFFFFFFFF; SetFileTime (dev, NULL, &ftLastAccessTime, NULL); if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0) bTimeStampValid = FALSE; else bTimeStampValid = TRUE; } DisableFileCompression (dev); if (!volParams->hiddenVol && !bInstantRetryOtherFilesys) { LARGE_INTEGER volumeSize; volumeSize.QuadPart = dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE; if (volParams->sparseFileSwitch && volParams->quickFormat) { // Create as sparse file container DWORD tmp; if (!DeviceIoControl (dev, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &tmp, NULL)) { nStatus = ERR_OS_ERROR; goto error; } } - // Preallocate the file - if (!SetFilePointerEx (dev, volumeSize, NULL, FILE_BEGIN) - || !SetEndOfFile (dev)) + if (!delayedSpeedupFileCreation) { - nStatus = ERR_OS_ERROR; - goto error; + // Preallocate the file + if (!SetFilePointerEx (dev, volumeSize, NULL, FILE_BEGIN) + || !SetEndOfFile (dev)) + { + nStatus = ERR_OS_ERROR; + goto error; + } } if (speedupFileCreation) { // accelerate file creation by telling Windows not to fill all file content with zeros // this has security issues since it will put existing disk content into file container // We use this mechanism only when switch /fastCreateFile specific and when quick format // also specified and which is documented to have security issues. - // we don't check returned status because failure is not issue for us - if (!SetFileValidData (dev, volumeSize.QuadPart)) + if (delayedSpeedupFileCreation) + { + // in case of delayed speedup we need to set the file size to a minimal value before performing the real preallocation through UAC + LARGE_INTEGER minimalSize; + DWORD dwOpStatus; + // 16K + minimalSize.QuadPart = 16 * 1024; + if (!SetFilePointerEx (dev, minimalSize, NULL, FILE_BEGIN) + || !SetEndOfFile (dev)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + FlushFileBuffers (dev); + CloseHandle (dev); + dev = INVALID_HANDLE_VALUE; + + dwOpStatus = UacFastFileCreation (volParams->hwndDlg, volParams->volumePath, volumeSize.QuadPart); + if (dwOpStatus != 0) + { + SetLastError(dwOpStatus); + nStatus = ERR_OS_ERROR; + goto error; + } + + // open again the file now that it was created + dev = CreateFile (volParams->volumePath, GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if (dev == INVALID_HANDLE_VALUE) + { + nStatus = ERR_OS_ERROR; + goto error; + } + } + else if (!SetFileValidData (dev, volumeSize.QuadPart)) { nStatus = ERR_OS_ERROR; goto error; } } if (SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0) { nStatus = ERR_OS_ERROR; goto error; } } } if (volParams->hwndDlg && volParams->bGuiMode) KillTimer (volParams->hwndDlg, TIMER_ID_RANDVIEW); /* Volume header */ // Hidden volume setup if (volParams->hiddenVol) { LARGE_INTEGER headerOffset; // Check hidden volume size if (volParams->hiddenVolHostSize < TC_MIN_HIDDEN_VOLUME_HOST_SIZE || volParams->hiddenVolHostSize > TC_MAX_HIDDEN_VOLUME_HOST_SIZE) { nStatus = ERR_VOL_SIZE_WRONG; goto error; } @@ -462,61 +505,61 @@ begin_format: nStatus = ERR_OS_ERROR; goto error; } } else if (bInstantRetryOtherFilesys) { // The previous file system format failed and the user wants to try again with a different file system. // The volume header had been written successfully so we need to seek to the byte after the header. LARGE_INTEGER offset; offset.QuadPart = TC_VOLUME_DATA_OFFSET; if (!SetFilePointerEx ((HANDLE) dev, offset, NULL, FILE_BEGIN)) { nStatus = ERR_OS_ERROR; goto error; } } if (!bInstantRetryOtherFilesys) { // Write the volume header if (!WriteEffectiveVolumeHeader (volParams->bDevice, dev, header)) { nStatus = ERR_OS_ERROR; goto error; } // To prevent fragmentation, write zeroes to reserved header sectors which are going to be filled with random data if (!volParams->bDevice && !volParams->hiddenVol) { - byte buf[TC_VOLUME_HEADER_GROUP_SIZE - TC_VOLUME_HEADER_EFFECTIVE_SIZE]; + uint8 buf[TC_VOLUME_HEADER_GROUP_SIZE - TC_VOLUME_HEADER_EFFECTIVE_SIZE]; DWORD bytesWritten; ZeroMemory (buf, sizeof (buf)); if (!WriteFile (dev, buf, sizeof (buf), &bytesWritten, NULL)) { nStatus = ERR_OS_ERROR; goto error; } if (bytesWritten != sizeof (buf)) { nStatus = ERR_PARAMETER_INCORRECT; goto error; } } } if (volParams->hiddenVol) { // Calculate data area position of hidden volume cryptoInfo->hiddenVolumeOffset = dataOffset; // Validate the offset if (dataOffset % FormatSectorSize != 0) { nStatus = ERR_VOL_SIZE_WRONG; goto error; } volParams->quickFormat = TRUE; // To entirely format a hidden volume would be redundant @@ -1322,61 +1365,61 @@ BOOL WriteSector (void *dev, char *sector, char *write_buf, int *write_buf_cnt, unsigned __int64 *nSecNo, unsigned __int64 startSector, PCRYPTO_INFO cryptoInfo) { static __int32 updateTime = 0; (*nSecNo)++; memcpy (write_buf + *write_buf_cnt, sector, FormatSectorSize); (*write_buf_cnt) += FormatSectorSize; if (*write_buf_cnt == FormatWriteBufferSize && !FlushFormatWriteBuffer (dev, write_buf, write_buf_cnt, nSecNo, cryptoInfo)) return FALSE; if (GetTickCount () - updateTime > 25) { if (UpdateProgressBar ((*nSecNo - startSector) * FormatSectorSize)) return FALSE; updateTime = GetTickCount (); } return TRUE; } static volatile BOOL WriteThreadRunning; static volatile BOOL WriteThreadExitRequested; static HANDLE WriteThreadHandle; -static byte *WriteThreadBuffer; +static uint8 *WriteThreadBuffer; static HANDLE WriteBufferEmptyEvent; static HANDLE WriteBufferFullEvent; static volatile HANDLE WriteRequestHandle; static volatile int WriteRequestSize; static volatile DWORD WriteRequestResult; static void __cdecl FormatWriteThreadProc (void *arg) { DWORD bytesWritten; SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST); while (!WriteThreadExitRequested) { if (WaitForSingleObject (WriteBufferFullEvent, INFINITE) == WAIT_FAILED) { handleWin32Error (NULL, SRC_POS); break; } if (WriteThreadExitRequested) break; if (!WriteFile (WriteRequestHandle, WriteThreadBuffer, WriteRequestSize, &bytesWritten, NULL)) WriteRequestResult = GetLastError(); else WriteRequestResult = ERROR_SUCCESS; |