diff options
Diffstat (limited to 'src/Common/Format.c')
-rw-r--r-- | src/Common/Format.c | 2108 |
1 files changed, 1054 insertions, 1054 deletions
diff --git a/src/Common/Format.c b/src/Common/Format.c index fe12c041..f3114e5e 100644 --- a/src/Common/Format.c +++ b/src/Common/Format.c @@ -1,810 +1,810 @@ -/*
- Legal Notice: Some portions of the source code contained in this file were
- derived from the source code of TrueCrypt 7.1a, which is
- Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
- governed by the TrueCrypt License 3.0, also from the source code of
- Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
- and which is governed by the 'License Agreement for Encryption for the Masses'
- Modifications and additions to the original source code (contained in this file)
- and all other portions of this file are Copyright (c) 2013-2016 IDRIX
- and are governed by the Apache License 2.0 the full text of which is
- contained in the file License.txt included in VeraCrypt binary and source
- code distribution packages. */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "Tcdefs.h"
-
-#include "Common.h"
-#include "Crypto.h"
-#include "Fat.h"
-#include "Format.h"
-#include "Random.h"
-#include "Volumes.h"
-
-#include "Apidrvr.h"
-#include "Dlgcode.h"
-#include "Language.h"
-#include "Progress.h"
-#include "Resource.h"
-#include "Format/FormatCom.h"
-#include "Format/Tcformat.h"
-
-#include <Strsafe.h>
-
-#ifndef SRC_POS
-#define SRC_POS (__FUNCTION__ ":" TC_TO_STRING(__LINE__))
-#endif
-
-int FormatWriteBufferSize = 1024 * 1024;
-static uint32 FormatSectorSize = 0;
-
-
-uint64 GetVolumeDataAreaSize (BOOL hiddenVolume, uint64 volumeSize)
-{
- uint64 reservedSize;
-
- if (hiddenVolume)
- {
- // Reserve free space at the end of the host filesystem. FAT file system fills the last sector with
- // zeroes (marked as free; observed when quick format was performed using the OS format tool).
- // Therefore, when the outer volume is mounted with hidden volume protection, such write operations
- // (e.g. quick formatting the outer volume filesystem as FAT) would needlessly trigger hidden volume
- // protection.
-
-#if TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE > 4096
-# error TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE too large for very small volumes. Revise the code.
-#endif
-
-#if TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH < TC_MAX_VOLUME_SECTOR_SIZE
-# error TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH too small.
-#endif
-
- if (volumeSize < TC_VOLUME_SMALL_SIZE_THRESHOLD)
- reservedSize = TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE;
- else
- reservedSize = TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH; // Ensure size of a hidden volume larger than TC_VOLUME_SMALL_SIZE_THRESHOLD is a multiple of the maximum supported sector size
- }
- else
- {
- reservedSize = TC_TOTAL_VOLUME_HEADERS_SIZE;
- }
-
- if (volumeSize < reservedSize)
- return 0;
-
- return volumeSize - reservedSize;
-}
-
-
-int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams)
-{
- int nStatus;
- PCRYPTO_INFO cryptoInfo = NULL;
- HANDLE dev = INVALID_HANDLE_VALUE;
- DWORD dwError;
- char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
- unsigned __int64 num_sectors, startSector;
- fatparams ft;
- FILETIME ftCreationTime;
- FILETIME ftLastWriteTime;
- FILETIME ftLastAccessTime;
- BOOL bTimeStampValid = FALSE;
- BOOL bInstantRetryOtherFilesys = FALSE;
- WCHAR dosDev[TC_MAX_PATH] = { 0 };
- WCHAR devName[MAX_PATH] = { 0 };
- int driveLetter = -1;
- WCHAR deviceName[MAX_PATH];
- uint64 dataOffset, dataAreaSize;
- LARGE_INTEGER offset;
- BOOL bFailedRequiredDASD = FALSE;
- HWND hwndDlg = volParams->hwndDlg;
-
- FormatSectorSize = volParams->sectorSize;
-
- if (FormatSectorSize < TC_MIN_VOLUME_SECTOR_SIZE
- || FormatSectorSize > TC_MAX_VOLUME_SECTOR_SIZE
- || FormatSectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0)
- {
- Error ("SECTOR_SIZE_UNSUPPORTED", hwndDlg);
- return ERR_DONT_REPORT;
- }
-
- /* WARNING: Note that if Windows fails to format the volume as NTFS and the volume size is
- less than the maximum FAT size, the user is asked within this function whether he wants to instantly
- retry FAT format instead (to avoid having to re-create the whole container again). If the user
- answers yes, some of the input parameters are modified, the code below 'begin_format' is re-executed
- and some destructive operations that were performed during the first attempt must be (and are) skipped.
- Therefore, whenever adding or modifying any potentially destructive operations below 'begin_format',
- determine whether they (or their portions) need to be skipped during such a second attempt; if so,
- use the 'bInstantRetryOtherFilesys' flag to skip them. */
-
- if (volParams->hiddenVol)
- {
- dataOffset = volParams->hiddenVolHostSize - TC_VOLUME_HEADER_GROUP_SIZE - volParams->size;
- }
- else
- {
- if (volParams->size <= TC_TOTAL_VOLUME_HEADERS_SIZE)
- return ERR_VOL_SIZE_WRONG;
-
- dataOffset = TC_VOLUME_DATA_OFFSET;
- }
-
- dataAreaSize = GetVolumeDataAreaSize (volParams->hiddenVol, volParams->size);
-
- num_sectors = dataAreaSize / FormatSectorSize;
-
- if (volParams->bDevice)
- {
- StringCchCopyW (deviceName, ARRAYSIZE(deviceName), volParams->volumePath);
-
- driveLetter = GetDiskDeviceDriveLetter (deviceName);
- }
-
- VirtualLock (header, sizeof (header));
-
- nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
- header,
- volParams->ea,
- FIRST_MODE_OF_OPERATION_ID,
- volParams->password,
- volParams->pkcs5,
- volParams->pim,
- NULL,
- &cryptoInfo,
- dataAreaSize,
- volParams->hiddenVol ? dataAreaSize : 0,
- dataOffset,
- dataAreaSize,
- 0,
- volParams->headerFlags,
- FormatSectorSize,
- FALSE);
-
- if (nStatus != 0)
- {
- burn (header, sizeof (header));
- VirtualUnlock (header, sizeof (header));
- return nStatus;
- }
-
-begin_format:
-
- if (volParams->bDevice)
- {
- /* Device-hosted volume */
-
- 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)
- {
- // 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
- DeleteVolumeMountPoint (rootPath);
- }
- }
- }
- }
-
- // For extra safety, we will try to gain "raw" access to the partition. Note that this should actually be
- // redundant because if the filesystem was mounted, we already tried to obtain DASD above. If we failed,
- // bFailedRequiredDASD was set to TRUE and therefore we will perform pseudo "quick format" below. However,
- // for extra safety, in case IsDeviceMounted() failed to detect a live filesystem, we will blindly
- // send FSCTL_ALLOW_EXTENDED_DASD_IO (possibly for a second time) without checking the result.
-
- DeviceIoControl (dev,
- FSCTL_ALLOW_EXTENDED_DASD_IO,
- NULL,
- 0,
- NULL,
- 0,
- &dwResult,
- NULL);
-
-
- // If DASD is needed but we failed to obtain it, perform open - 'quick format' - close - open
- // so that the filesystem driver does not prevent us from formatting hidden sectors.
- for (nPass = (bFailedRequiredDASD ? 0 : 1); nPass < 2; nPass++)
- {
- int retryCount;
-
- retryCount = 0;
-
- // Try exclusive access mode first
- // Note that when exclusive access is denied, it is worth retrying (usually succeeds after a few tries).
- while (dev == INVALID_HANDLE_VALUE && retryCount++ < EXCL_ACCESS_MAX_AUTO_RETRIES)
- {
- dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
-
- if (retryCount > 1)
- Sleep (EXCL_ACCESS_AUTO_RETRY_DELAY);
- }
-
- if (dev == INVALID_HANDLE_VALUE)
- {
- // Exclusive access denied -- retry in shared mode
- dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
- if (dev != INVALID_HANDLE_VALUE)
- {
- if (!volParams->bForceOperation && (Silent || (IDNO == MessageBoxW (volParams->hwndDlg, GetString ("DEVICE_IN_USE_FORMAT"), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2))))
- {
- nStatus = ERR_DONT_REPORT;
- goto error;
- }
- }
- else
- {
- handleWin32Error (volParams->hwndDlg, SRC_POS);
- Error ("CANT_ACCESS_VOL", hwndDlg);
- nStatus = ERR_DONT_REPORT;
- goto error;
- }
- }
-
- if (volParams->hiddenVol || bInstantRetryOtherFilesys)
- break; // The following "quick format" operation would damage the outer volume
-
- if (nPass == 0)
- {
- 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 */
-
- 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;
- }
-
- 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)
- || SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0)
- {
- nStatus = ERR_OS_ERROR;
- goto error;
- }
- }
- }
-
- if (volParams->hiddenVol && !volParams->bDevice && bPreserveTimestamp)
- {
- if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
- bTimeStampValid = FALSE;
- else
- bTimeStampValid = TRUE;
- }
-
- 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;
- }
-
- // Seek to hidden volume header location
-
- headerOffset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET;
-
- if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
- {
- 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];
- 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
- }
-
- /* Data area */
- startSector = dataOffset / FormatSectorSize;
-
- // Format filesystem
-
- switch (volParams->fileSystem)
- {
- case FILESYS_NONE:
- case FILESYS_NTFS:
- case FILESYS_EXFAT:
-
- if (volParams->bDevice && !StartFormatWriteThread())
- {
- nStatus = ERR_OS_ERROR;
- goto error;
- }
-
- nStatus = FormatNoFs (hwndDlg, startSector, num_sectors, dev, cryptoInfo, volParams->quickFormat);
-
- if (volParams->bDevice)
- StopFormatWriteThread();
-
- break;
-
- case FILESYS_FAT:
- if (num_sectors > 0xFFFFffff)
- {
- nStatus = ERR_VOL_SIZE_WRONG;
- goto error;
- }
-
- // Calculate the fats, root dir etc
- ft.num_sectors = (unsigned int) (num_sectors);
-
-#if TC_MAX_VOLUME_SECTOR_SIZE > 0xFFFF
-#error TC_MAX_VOLUME_SECTOR_SIZE > 0xFFFF
-#endif
-
- ft.sector_size = (uint16) FormatSectorSize;
- ft.cluster_size = volParams->clusterSize;
- memcpy (ft.volume_name, "NO NAME ", 11);
- GetFatParams (&ft);
- *(volParams->realClusterSize) = ft.cluster_size * FormatSectorSize;
-
- if (volParams->bDevice && !StartFormatWriteThread())
- {
- nStatus = ERR_OS_ERROR;
- goto error;
- }
-
- nStatus = FormatFat (hwndDlg, startSector, &ft, (void *) dev, cryptoInfo, volParams->quickFormat);
-
- if (volParams->bDevice)
- StopFormatWriteThread();
-
- break;
-
- default:
- nStatus = ERR_PARAMETER_INCORRECT;
- goto error;
- }
-
- if (nStatus != ERR_SUCCESS)
- goto error;
-
- // Write header backup
- offset.QuadPart = volParams->hiddenVol ? volParams->hiddenVolHostSize - TC_HIDDEN_VOLUME_HEADER_OFFSET : dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE;
-
- if (!SetFilePointerEx ((HANDLE) dev, offset, NULL, FILE_BEGIN))
- {
- nStatus = ERR_OS_ERROR;
- goto error;
- }
-
- nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
- header,
- volParams->ea,
- FIRST_MODE_OF_OPERATION_ID,
- volParams->password,
- volParams->pkcs5,
- volParams->pim,
- cryptoInfo->master_keydata,
- &cryptoInfo,
- dataAreaSize,
- volParams->hiddenVol ? dataAreaSize : 0,
- dataOffset,
- dataAreaSize,
- 0,
- volParams->headerFlags,
- FormatSectorSize,
- FALSE);
-
- if (!WriteEffectiveVolumeHeader (volParams->bDevice, dev, header))
- {
- nStatus = ERR_OS_ERROR;
- goto error;
- }
-
- // Fill reserved header sectors (including the backup header area) with random data
- if (!volParams->hiddenVol)
- {
- nStatus = WriteRandomDataToReservedHeaderAreas (hwndDlg, dev, cryptoInfo, dataAreaSize, FALSE, FALSE);
-
- if (nStatus != ERR_SUCCESS)
- goto error;
- }
-
-#ifndef DEBUG
- if (volParams->quickFormat && volParams->fileSystem != FILESYS_NTFS && volParams->fileSystem != FILESYS_EXFAT)
- Sleep (500); // User-friendly GUI
-#endif
-
-error:
- dwError = GetLastError();
-
- burn (header, sizeof (header));
- VirtualUnlock (header, sizeof (header));
-
- if (dev != INVALID_HANDLE_VALUE)
- {
- if (!volParams->bDevice && !volParams->hiddenVol && nStatus != 0)
- {
- // Remove preallocated part before closing file handle if format failed
- if (SetFilePointer (dev, 0, NULL, FILE_BEGIN) == 0)
- SetEndOfFile (dev);
- }
-
- FlushFileBuffers (dev);
-
- if (bTimeStampValid)
- SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime);
-
- CloseHandle (dev);
- dev = INVALID_HANDLE_VALUE;
- }
-
- if (nStatus != 0)
- {
- SetLastError(dwError);
- goto fv_end;
- }
-
- if (volParams->fileSystem == FILESYS_NTFS || volParams->fileSystem == FILESYS_EXFAT)
- {
- // Quick-format volume as NTFS
- int driveNo = GetLastAvailableDrive ();
- MountOptions mountOptions;
- int retCode;
- int fsType = (volParams->fileSystem == FILESYS_EXFAT)? FILESYS_EXFAT: FILESYS_NTFS;
-
- ZeroMemory (&mountOptions, sizeof (mountOptions));
-
- if (driveNo == -1)
- {
- if (!Silent)
- {
- MessageBoxW (volParams->hwndDlg, GetString ("NO_FREE_DRIVES"), lpszTitle, ICON_HAND);
- MessageBoxW (volParams->hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND);
- }
-
- nStatus = ERR_NO_FREE_DRIVES;
- goto fv_end;
- }
-
- mountOptions.ReadOnly = FALSE;
- mountOptions.Removable = FALSE;
- mountOptions.ProtectHiddenVolume = FALSE;
- mountOptions.PreserveTimestamp = bPreserveTimestamp;
- mountOptions.PartitionInInactiveSysEncScope = FALSE;
- mountOptions.UseBackupHeader = FALSE;
-
- if (MountVolume (volParams->hwndDlg, driveNo, volParams->volumePath, volParams->password, volParams->pkcs5, volParams->pim, FALSE, FALSE, FALSE, TRUE, &mountOptions, FALSE, TRUE) < 1)
- {
- if (!Silent)
- {
- MessageBoxW (volParams->hwndDlg, GetString ("CANT_MOUNT_VOLUME"), lpszTitle, ICON_HAND);
- MessageBoxW (volParams->hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND);
- }
- 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)
- {
- if (!UnmountVolumeAfterFormatExCall (volParams->hwndDlg, driveNo) && !Silent)
- MessageBoxW (volParams->hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND);
-
- if (dataAreaSize <= TC_MAX_FAT_SECTOR_COUNT * FormatSectorSize)
- {
- if (AskErrYesNo ("FORMAT_NTFS_FAILED_ASK_FAT", hwndDlg) == IDYES)
- {
- // NTFS format failed and the user wants to try FAT format immediately
- volParams->fileSystem = FILESYS_FAT;
- bInstantRetryOtherFilesys = TRUE;
- volParams->quickFormat = TRUE; // Volume has already been successfully TC-formatted
- volParams->clusterSize = 0; // Default cluster size
- goto begin_format;
- }
- }
- else
- Error ("FORMAT_NTFS_FAILED", hwndDlg);
-
- nStatus = ERR_DONT_REPORT;
- goto fv_end;
- }
-
- if (!UnmountVolumeAfterFormatExCall (volParams->hwndDlg, driveNo) && !Silent)
- MessageBoxW (volParams->hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND);
- }
-
-fv_end:
- dwError = GetLastError();
-
- if (dosDev[0])
- RemoveFakeDosName (volParams->volumePath, dosDev);
-
- crypto_close (cryptoInfo);
-
- SetLastError (dwError);
- return nStatus;
-}
-
-
-int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, __int64 num_sectors, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat)
-{
- int write_buf_cnt = 0;
- char sector[TC_MAX_VOLUME_SECTOR_SIZE], *write_buf;
- unsigned __int64 nSecNo = startSector;
- int retVal = 0;
- DWORD err;
- char temporaryKey[MASTER_KEYDATA_SIZE];
- char originalK2[MASTER_KEYDATA_SIZE];
-
- LARGE_INTEGER startOffset;
- LARGE_INTEGER newOffset;
-
- // Seek to start sector
- startOffset.QuadPart = startSector * FormatSectorSize;
- if (!SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN)
- || newOffset.QuadPart != startOffset.QuadPart)
- {
- return ERR_OS_ERROR;
- }
-
- write_buf = (char *)TCalloc (FormatWriteBufferSize);
- if (!write_buf)
- return ERR_OUTOFMEMORY;
-
- VirtualLock (temporaryKey, sizeof (temporaryKey));
- VirtualLock (originalK2, sizeof (originalK2));
-
- memset (sector, 0, sizeof (sector));
-
- // Remember the original secondary key (XTS mode) before generating a temporary one
- memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2));
-
- /* Fill the rest of the data area with random data */
-
- if(!quickFormat)
- {
- /* Generate a random temporary key set to be used for "dummy" encryption that will fill
- the free disk space (data area) with random data. This is necessary for plausible
- deniability of hidden volumes. */
-
- // Temporary master key
- if (!RandgetBytes (hwndDlg, temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE))
- goto fail;
-
- // Temporary secondary key (XTS mode)
- if (!RandgetBytes (hwndDlg, cryptoInfo->k2, sizeof cryptoInfo->k2, FALSE))
- goto fail;
-
- retVal = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks);
- if (retVal != ERR_SUCCESS)
- goto fail;
-
- if (!EAInitMode (cryptoInfo))
- {
- retVal = ERR_MODE_INIT_FAILED;
- goto fail;
- }
-
- while (num_sectors--)
- {
- if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
- cryptoInfo) == FALSE)
- goto fail;
- }
-
- if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo))
- goto fail;
- }
- else
- nSecNo = num_sectors;
-
- UpdateProgressBar (nSecNo * FormatSectorSize);
-
- // Restore the original secondary key (XTS mode) in case NTFS format fails and the user wants to try FAT immediately
- memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2));
-
- // Reinitialize the encryption algorithm and mode in case NTFS format fails and the user wants to try FAT immediately
- retVal = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks);
- if (retVal != ERR_SUCCESS)
- goto fail;
- if (!EAInitMode (cryptoInfo))
- {
- retVal = ERR_MODE_INIT_FAILED;
- goto fail;
- }
-
- burn (temporaryKey, sizeof(temporaryKey));
- burn (originalK2, sizeof(originalK2));
- VirtualUnlock (temporaryKey, sizeof (temporaryKey));
- VirtualUnlock (originalK2, sizeof (originalK2));
- TCfree (write_buf);
-
- return 0;
-
-fail:
- err = GetLastError();
-
- burn (temporaryKey, sizeof(temporaryKey));
- burn (originalK2, sizeof(originalK2));
- VirtualUnlock (temporaryKey, sizeof (temporaryKey));
- VirtualUnlock (originalK2, sizeof (originalK2));
- TCfree (write_buf);
-
- SetLastError (err);
- return (retVal ? retVal : ERR_OS_ERROR);
-}
-
-
-volatile BOOLEAN FormatExError;
-
-BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID parameter)
+/* + Legal Notice: Some portions of the source code contained in this file were + derived from the source code of TrueCrypt 7.1a, which is + Copyright (c) 2003-2012 TrueCrypt Developers Association and which is + governed by the TrueCrypt License 3.0, also from the source code of + Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux + and which is governed by the 'License Agreement for Encryption for the Masses' + Modifications and additions to the original source code (contained in this file) + and all other portions of this file are Copyright (c) 2013-2016 IDRIX + and are governed by the Apache License 2.0 the full text of which is + contained in the file License.txt included in VeraCrypt binary and source + code distribution packages. */ + +#include <stdlib.h> +#include <string.h> + +#include "Tcdefs.h" + +#include "Common.h" +#include "Crypto.h" +#include "Fat.h" +#include "Format.h" +#include "Random.h" +#include "Volumes.h" + +#include "Apidrvr.h" +#include "Dlgcode.h" +#include "Language.h" +#include "Progress.h" +#include "Resource.h" +#include "Format/FormatCom.h" +#include "Format/Tcformat.h" + +#include <Strsafe.h> + +#ifndef SRC_POS +#define SRC_POS (__FUNCTION__ ":" TC_TO_STRING(__LINE__)) +#endif + +int FormatWriteBufferSize = 1024 * 1024; +static uint32 FormatSectorSize = 0; + + +uint64 GetVolumeDataAreaSize (BOOL hiddenVolume, uint64 volumeSize) +{ + uint64 reservedSize; + + if (hiddenVolume) + { + // Reserve free space at the end of the host filesystem. FAT file system fills the last sector with + // zeroes (marked as free; observed when quick format was performed using the OS format tool). + // Therefore, when the outer volume is mounted with hidden volume protection, such write operations + // (e.g. quick formatting the outer volume filesystem as FAT) would needlessly trigger hidden volume + // protection. + +#if TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE > 4096 +# error TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE too large for very small volumes. Revise the code. +#endif + +#if TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH < TC_MAX_VOLUME_SECTOR_SIZE +# error TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH too small. +#endif + + if (volumeSize < TC_VOLUME_SMALL_SIZE_THRESHOLD) + reservedSize = TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE; + else + reservedSize = TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH; // Ensure size of a hidden volume larger than TC_VOLUME_SMALL_SIZE_THRESHOLD is a multiple of the maximum supported sector size + } + else + { + reservedSize = TC_TOTAL_VOLUME_HEADERS_SIZE; + } + + if (volumeSize < reservedSize) + return 0; + + return volumeSize - reservedSize; +} + + +int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams) +{ + int nStatus; + PCRYPTO_INFO cryptoInfo = NULL; + HANDLE dev = INVALID_HANDLE_VALUE; + DWORD dwError; + char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE]; + unsigned __int64 num_sectors, startSector; + fatparams ft; + FILETIME ftCreationTime; + FILETIME ftLastWriteTime; + FILETIME ftLastAccessTime; + BOOL bTimeStampValid = FALSE; + BOOL bInstantRetryOtherFilesys = FALSE; + WCHAR dosDev[TC_MAX_PATH] = { 0 }; + WCHAR devName[MAX_PATH] = { 0 }; + int driveLetter = -1; + WCHAR deviceName[MAX_PATH]; + uint64 dataOffset, dataAreaSize; + LARGE_INTEGER offset; + BOOL bFailedRequiredDASD = FALSE; + HWND hwndDlg = volParams->hwndDlg; + + FormatSectorSize = volParams->sectorSize; + + if (FormatSectorSize < TC_MIN_VOLUME_SECTOR_SIZE + || FormatSectorSize > TC_MAX_VOLUME_SECTOR_SIZE + || FormatSectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) + { + Error ("SECTOR_SIZE_UNSUPPORTED", hwndDlg); + return ERR_DONT_REPORT; + } + + /* WARNING: Note that if Windows fails to format the volume as NTFS and the volume size is + less than the maximum FAT size, the user is asked within this function whether he wants to instantly + retry FAT format instead (to avoid having to re-create the whole container again). If the user + answers yes, some of the input parameters are modified, the code below 'begin_format' is re-executed + and some destructive operations that were performed during the first attempt must be (and are) skipped. + Therefore, whenever adding or modifying any potentially destructive operations below 'begin_format', + determine whether they (or their portions) need to be skipped during such a second attempt; if so, + use the 'bInstantRetryOtherFilesys' flag to skip them. */ + + if (volParams->hiddenVol) + { + dataOffset = volParams->hiddenVolHostSize - TC_VOLUME_HEADER_GROUP_SIZE - volParams->size; + } + else + { + if (volParams->size <= TC_TOTAL_VOLUME_HEADERS_SIZE) + return ERR_VOL_SIZE_WRONG; + + dataOffset = TC_VOLUME_DATA_OFFSET; + } + + dataAreaSize = GetVolumeDataAreaSize (volParams->hiddenVol, volParams->size); + + num_sectors = dataAreaSize / FormatSectorSize; + + if (volParams->bDevice) + { + StringCchCopyW (deviceName, ARRAYSIZE(deviceName), volParams->volumePath); + + driveLetter = GetDiskDeviceDriveLetter (deviceName); + } + + VirtualLock (header, sizeof (header)); + + nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE, + header, + volParams->ea, + FIRST_MODE_OF_OPERATION_ID, + volParams->password, + volParams->pkcs5, + volParams->pim, + NULL, + &cryptoInfo, + dataAreaSize, + volParams->hiddenVol ? dataAreaSize : 0, + dataOffset, + dataAreaSize, + 0, + volParams->headerFlags, + FormatSectorSize, + FALSE); + + if (nStatus != 0) + { + burn (header, sizeof (header)); + VirtualUnlock (header, sizeof (header)); + return nStatus; + } + +begin_format: + + if (volParams->bDevice) + { + /* Device-hosted volume */ + + 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) + { + // 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 + DeleteVolumeMountPoint (rootPath); + } + } + } + } + + // For extra safety, we will try to gain "raw" access to the partition. Note that this should actually be + // redundant because if the filesystem was mounted, we already tried to obtain DASD above. If we failed, + // bFailedRequiredDASD was set to TRUE and therefore we will perform pseudo "quick format" below. However, + // for extra safety, in case IsDeviceMounted() failed to detect a live filesystem, we will blindly + // send FSCTL_ALLOW_EXTENDED_DASD_IO (possibly for a second time) without checking the result. + + DeviceIoControl (dev, + FSCTL_ALLOW_EXTENDED_DASD_IO, + NULL, + 0, + NULL, + 0, + &dwResult, + NULL); + + + // If DASD is needed but we failed to obtain it, perform open - 'quick format' - close - open + // so that the filesystem driver does not prevent us from formatting hidden sectors. + for (nPass = (bFailedRequiredDASD ? 0 : 1); nPass < 2; nPass++) + { + int retryCount; + + retryCount = 0; + + // Try exclusive access mode first + // Note that when exclusive access is denied, it is worth retrying (usually succeeds after a few tries). + while (dev == INVALID_HANDLE_VALUE && retryCount++ < EXCL_ACCESS_MAX_AUTO_RETRIES) + { + dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (retryCount > 1) + Sleep (EXCL_ACCESS_AUTO_RETRY_DELAY); + } + + if (dev == INVALID_HANDLE_VALUE) + { + // Exclusive access denied -- retry in shared mode + dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (dev != INVALID_HANDLE_VALUE) + { + if (!volParams->bForceOperation && (Silent || (IDNO == MessageBoxW (volParams->hwndDlg, GetString ("DEVICE_IN_USE_FORMAT"), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2)))) + { + nStatus = ERR_DONT_REPORT; + goto error; + } + } + else + { + handleWin32Error (volParams->hwndDlg, SRC_POS); + Error ("CANT_ACCESS_VOL", hwndDlg); + nStatus = ERR_DONT_REPORT; + goto error; + } + } + + if (volParams->hiddenVol || bInstantRetryOtherFilesys) + break; // The following "quick format" operation would damage the outer volume + + if (nPass == 0) + { + 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 */ + + 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; + } + + 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) + || SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0) + { + nStatus = ERR_OS_ERROR; + goto error; + } + } + } + + if (volParams->hiddenVol && !volParams->bDevice && bPreserveTimestamp) + { + if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0) + bTimeStampValid = FALSE; + else + bTimeStampValid = TRUE; + } + + 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; + } + + // Seek to hidden volume header location + + headerOffset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET; + + if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN)) + { + 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]; + 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 + } + + /* Data area */ + startSector = dataOffset / FormatSectorSize; + + // Format filesystem + + switch (volParams->fileSystem) + { + case FILESYS_NONE: + case FILESYS_NTFS: + case FILESYS_EXFAT: + + if (volParams->bDevice && !StartFormatWriteThread()) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + nStatus = FormatNoFs (hwndDlg, startSector, num_sectors, dev, cryptoInfo, volParams->quickFormat); + + if (volParams->bDevice) + StopFormatWriteThread(); + + break; + + case FILESYS_FAT: + if (num_sectors > 0xFFFFffff) + { + nStatus = ERR_VOL_SIZE_WRONG; + goto error; + } + + // Calculate the fats, root dir etc + ft.num_sectors = (unsigned int) (num_sectors); + +#if TC_MAX_VOLUME_SECTOR_SIZE > 0xFFFF +#error TC_MAX_VOLUME_SECTOR_SIZE > 0xFFFF +#endif + + ft.sector_size = (uint16) FormatSectorSize; + ft.cluster_size = volParams->clusterSize; + memcpy (ft.volume_name, "NO NAME ", 11); + GetFatParams (&ft); + *(volParams->realClusterSize) = ft.cluster_size * FormatSectorSize; + + if (volParams->bDevice && !StartFormatWriteThread()) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + nStatus = FormatFat (hwndDlg, startSector, &ft, (void *) dev, cryptoInfo, volParams->quickFormat); + + if (volParams->bDevice) + StopFormatWriteThread(); + + break; + + default: + nStatus = ERR_PARAMETER_INCORRECT; + goto error; + } + + if (nStatus != ERR_SUCCESS) + goto error; + + // Write header backup + offset.QuadPart = volParams->hiddenVol ? volParams->hiddenVolHostSize - TC_HIDDEN_VOLUME_HEADER_OFFSET : dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE; + + if (!SetFilePointerEx ((HANDLE) dev, offset, NULL, FILE_BEGIN)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE, + header, + volParams->ea, + FIRST_MODE_OF_OPERATION_ID, + volParams->password, + volParams->pkcs5, + volParams->pim, + cryptoInfo->master_keydata, + &cryptoInfo, + dataAreaSize, + volParams->hiddenVol ? dataAreaSize : 0, + dataOffset, + dataAreaSize, + 0, + volParams->headerFlags, + FormatSectorSize, + FALSE); + + if (!WriteEffectiveVolumeHeader (volParams->bDevice, dev, header)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + // Fill reserved header sectors (including the backup header area) with random data + if (!volParams->hiddenVol) + { + nStatus = WriteRandomDataToReservedHeaderAreas (hwndDlg, dev, cryptoInfo, dataAreaSize, FALSE, FALSE); + + if (nStatus != ERR_SUCCESS) + goto error; + } + +#ifndef DEBUG + if (volParams->quickFormat && volParams->fileSystem != FILESYS_NTFS && volParams->fileSystem != FILESYS_EXFAT) + Sleep (500); // User-friendly GUI +#endif + +error: + dwError = GetLastError(); + + burn (header, sizeof (header)); + VirtualUnlock (header, sizeof (header)); + + if (dev != INVALID_HANDLE_VALUE) + { + if (!volParams->bDevice && !volParams->hiddenVol && nStatus != 0) + { + // Remove preallocated part before closing file handle if format failed + if (SetFilePointer (dev, 0, NULL, FILE_BEGIN) == 0) + SetEndOfFile (dev); + } + + FlushFileBuffers (dev); + + if (bTimeStampValid) + SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime); + + CloseHandle (dev); + dev = INVALID_HANDLE_VALUE; + } + + if (nStatus != 0) + { + SetLastError(dwError); + goto fv_end; + } + + if (volParams->fileSystem == FILESYS_NTFS || volParams->fileSystem == FILESYS_EXFAT) + { + // Quick-format volume as NTFS + int driveNo = GetLastAvailableDrive (); + MountOptions mountOptions; + int retCode; + int fsType = (volParams->fileSystem == FILESYS_EXFAT)? FILESYS_EXFAT: FILESYS_NTFS; + + ZeroMemory (&mountOptions, sizeof (mountOptions)); + + if (driveNo == -1) + { + if (!Silent) + { + MessageBoxW (volParams->hwndDlg, GetString ("NO_FREE_DRIVES"), lpszTitle, ICON_HAND); + MessageBoxW (volParams->hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND); + } + + nStatus = ERR_NO_FREE_DRIVES; + goto fv_end; + } + + mountOptions.ReadOnly = FALSE; + mountOptions.Removable = FALSE; + mountOptions.ProtectHiddenVolume = FALSE; + mountOptions.PreserveTimestamp = bPreserveTimestamp; + mountOptions.PartitionInInactiveSysEncScope = FALSE; + mountOptions.UseBackupHeader = FALSE; + + if (MountVolume (volParams->hwndDlg, driveNo, volParams->volumePath, volParams->password, volParams->pkcs5, volParams->pim, FALSE, FALSE, FALSE, TRUE, &mountOptions, FALSE, TRUE) < 1) + { + if (!Silent) + { + MessageBoxW (volParams->hwndDlg, GetString ("CANT_MOUNT_VOLUME"), lpszTitle, ICON_HAND); + MessageBoxW (volParams->hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND); + } + 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) + { + if (!UnmountVolumeAfterFormatExCall (volParams->hwndDlg, driveNo) && !Silent) + MessageBoxW (volParams->hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND); + + if (dataAreaSize <= TC_MAX_FAT_SECTOR_COUNT * FormatSectorSize) + { + if (AskErrYesNo ("FORMAT_NTFS_FAILED_ASK_FAT", hwndDlg) == IDYES) + { + // NTFS format failed and the user wants to try FAT format immediately + volParams->fileSystem = FILESYS_FAT; + bInstantRetryOtherFilesys = TRUE; + volParams->quickFormat = TRUE; // Volume has already been successfully TC-formatted + volParams->clusterSize = 0; // Default cluster size + goto begin_format; + } + } + else + Error ("FORMAT_NTFS_FAILED", hwndDlg); + + nStatus = ERR_DONT_REPORT; + goto fv_end; + } + + if (!UnmountVolumeAfterFormatExCall (volParams->hwndDlg, driveNo) && !Silent) + MessageBoxW (volParams->hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND); + } + +fv_end: + dwError = GetLastError(); + + if (dosDev[0]) + RemoveFakeDosName (volParams->volumePath, dosDev); + + crypto_close (cryptoInfo); + + SetLastError (dwError); + return nStatus; +} + + +int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, __int64 num_sectors, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat) +{ + int write_buf_cnt = 0; + char sector[TC_MAX_VOLUME_SECTOR_SIZE], *write_buf; + unsigned __int64 nSecNo = startSector; + int retVal = 0; + DWORD err; + char temporaryKey[MASTER_KEYDATA_SIZE]; + char originalK2[MASTER_KEYDATA_SIZE]; + + LARGE_INTEGER startOffset; + LARGE_INTEGER newOffset; + + // Seek to start sector + startOffset.QuadPart = startSector * FormatSectorSize; + if (!SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN) + || newOffset.QuadPart != startOffset.QuadPart) + { + return ERR_OS_ERROR; + } + + write_buf = (char *)TCalloc (FormatWriteBufferSize); + if (!write_buf) + return ERR_OUTOFMEMORY; + + VirtualLock (temporaryKey, sizeof (temporaryKey)); + VirtualLock (originalK2, sizeof (originalK2)); + + memset (sector, 0, sizeof (sector)); + + // Remember the original secondary key (XTS mode) before generating a temporary one + memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2)); + + /* Fill the rest of the data area with random data */ + + if(!quickFormat) + { + /* Generate a random temporary key set to be used for "dummy" encryption that will fill + the free disk space (data area) with random data. This is necessary for plausible + deniability of hidden volumes. */ + + // Temporary master key + if (!RandgetBytes (hwndDlg, temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE)) + goto fail; + + // Temporary secondary key (XTS mode) + if (!RandgetBytes (hwndDlg, cryptoInfo->k2, sizeof cryptoInfo->k2, FALSE)) + goto fail; + + retVal = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks); + if (retVal != ERR_SUCCESS) + goto fail; + + if (!EAInitMode (cryptoInfo)) + { + retVal = ERR_MODE_INIT_FAILED; + goto fail; + } + + while (num_sectors--) + { + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + cryptoInfo) == FALSE) + goto fail; + } + + if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo)) + goto fail; + } + else + nSecNo = num_sectors; + + UpdateProgressBar (nSecNo * FormatSectorSize); + + // Restore the original secondary key (XTS mode) in case NTFS format fails and the user wants to try FAT immediately + memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2)); + + // Reinitialize the encryption algorithm and mode in case NTFS format fails and the user wants to try FAT immediately + retVal = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks); + if (retVal != ERR_SUCCESS) + goto fail; + if (!EAInitMode (cryptoInfo)) + { + retVal = ERR_MODE_INIT_FAILED; + goto fail; + } + + burn (temporaryKey, sizeof(temporaryKey)); + burn (originalK2, sizeof(originalK2)); + VirtualUnlock (temporaryKey, sizeof (temporaryKey)); + VirtualUnlock (originalK2, sizeof (originalK2)); + TCfree (write_buf); + + return 0; + +fail: + err = GetLastError(); + + burn (temporaryKey, sizeof(temporaryKey)); + burn (originalK2, sizeof(originalK2)); + VirtualUnlock (temporaryKey, sizeof (temporaryKey)); + VirtualUnlock (originalK2, sizeof (originalK2)); + TCfree (write_buf); + + SetLastError (err); + return (retVal ? retVal : ERR_OS_ERROR); +} + + +volatile BOOLEAN FormatExError; + +BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID parameter) { if (FormatExError) return FALSE; @@ -859,250 +859,250 @@ BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID paramet FormatExError = TRUE; break; } - return (FormatExError? FALSE : TRUE);
-}
-
-BOOL FormatFs (int driveNo, int clusterSize, int fsType)
-{
- wchar_t dllPath[MAX_PATH] = {0};
- WCHAR dir[8] = { (WCHAR) driveNo + L'A', 0 };
- PFORMATEX FormatEx;
- HMODULE hModule;
- int i;
- WCHAR szFsFormat[16];
- WCHAR szLabel[2] = {0};
- switch (fsType)
- {
- case FILESYS_NTFS:
- StringCchCopyW (szFsFormat, ARRAYSIZE (szFsFormat),L"NTFS");
- break;
- case FILESYS_EXFAT:
- StringCchCopyW (szFsFormat, ARRAYSIZE (szFsFormat),L"EXFAT");
- break;
- default:
- return FALSE;
- }
-
-
- if (GetSystemDirectory (dllPath, MAX_PATH))
- {
- StringCchCatW(dllPath, ARRAYSIZE(dllPath), L"\\fmifs.dll");
- }
- else
- StringCchCopyW(dllPath, ARRAYSIZE(dllPath), L"C:\\Windows\\System32\\fmifs.dll");
-
- hModule = LoadLibrary (dllPath);
-
- if (hModule == NULL)
- return FALSE;
-
- if (!(FormatEx = (PFORMATEX) GetProcAddress (GetModuleHandle (L"fmifs.dll"), "FormatEx")))
- {
- FreeLibrary (hModule);
- return FALSE;
- }
-
- StringCchCatW (dir, ARRAYSIZE(dir), L":\\");
-
- FormatExError = TRUE;
-
- // 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);
- }
-
- // The device may be referenced for some time after FormatEx() returns
- Sleep (4000);
-
- FreeLibrary (hModule);
- return FormatExError? FALSE : TRUE;
-}
-
-BOOL FormatNtfs (int driveNo, int clusterSize)
-{
- return FormatFs (driveNo, clusterSize, FILESYS_NTFS);
-}
-
-BOOL WriteSector (void *dev, char *sector,
- char *write_buf, int *write_buf_cnt,
- __int64 *nSecNo, 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 * FormatSectorSize))
- return FALSE;
-
- updateTime = GetTickCount ();
- }
-
- return TRUE;
-
-}
-
-
-static volatile BOOL WriteThreadRunning;
-static volatile BOOL WriteThreadExitRequested;
-static HANDLE WriteThreadHandle;
-
-static byte *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;
-
- if (!SetEvent (WriteBufferEmptyEvent))
- {
- handleWin32Error (NULL, SRC_POS);
- break;
- }
- }
-
- WriteThreadRunning = FALSE;
- _endthread();
-}
-
-
-static BOOL StartFormatWriteThread ()
-{
- DWORD sysErr;
-
- WriteBufferEmptyEvent = NULL;
- WriteBufferFullEvent = NULL;
- WriteThreadBuffer = NULL;
-
- WriteBufferEmptyEvent = CreateEvent (NULL, FALSE, TRUE, NULL);
- if (!WriteBufferEmptyEvent)
- goto err;
-
- WriteBufferFullEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
- if (!WriteBufferFullEvent)
- goto err;
-
- WriteThreadBuffer = TCalloc (FormatWriteBufferSize);
- if (!WriteThreadBuffer)
- {
- SetLastError (ERROR_OUTOFMEMORY);
- goto err;
- }
-
- WriteThreadExitRequested = FALSE;
- WriteRequestResult = ERROR_SUCCESS;
-
- WriteThreadHandle = (HANDLE) _beginthread (FormatWriteThreadProc, 0, NULL);
- if ((uintptr_t) WriteThreadHandle == -1L)
- goto err;
-
- WriteThreadRunning = TRUE;
- return TRUE;
-
-err:
- sysErr = GetLastError();
-
- if (WriteBufferEmptyEvent)
- CloseHandle (WriteBufferEmptyEvent);
- if (WriteBufferFullEvent)
- CloseHandle (WriteBufferFullEvent);
- if (WriteThreadBuffer)
- TCfree (WriteThreadBuffer);
-
- SetLastError (sysErr);
- return FALSE;
-}
-
-
-static void StopFormatWriteThread ()
-{
- if (WriteThreadRunning)
- {
- WaitForSingleObject (WriteBufferEmptyEvent, INFINITE);
-
- WriteThreadExitRequested = TRUE;
- SetEvent (WriteBufferFullEvent);
-
- WaitForSingleObject (WriteThreadHandle, INFINITE);
- }
-
- CloseHandle (WriteBufferEmptyEvent);
- CloseHandle (WriteBufferFullEvent);
- TCfree (WriteThreadBuffer);
-}
-
-
-BOOL FlushFormatWriteBuffer (void *dev, char *write_buf, int *write_buf_cnt, __int64 *nSecNo, PCRYPTO_INFO cryptoInfo)
-{
- UINT64_STRUCT unitNo;
- DWORD bytesWritten;
-
- if (*write_buf_cnt == 0)
- return TRUE;
-
- unitNo.Value = (*nSecNo * FormatSectorSize - *write_buf_cnt) / ENCRYPTION_DATA_UNIT_SIZE;
-
- EncryptDataUnits (write_buf, &unitNo, *write_buf_cnt / ENCRYPTION_DATA_UNIT_SIZE, cryptoInfo);
-
- if (WriteThreadRunning)
- {
- if (WaitForSingleObject (WriteBufferEmptyEvent, INFINITE) == WAIT_FAILED)
- return FALSE;
-
- if (WriteRequestResult != ERROR_SUCCESS)
- {
- SetEvent (WriteBufferEmptyEvent);
- SetLastError (WriteRequestResult);
- return FALSE;
- }
-
- memcpy (WriteThreadBuffer, write_buf, *write_buf_cnt);
- WriteRequestHandle = dev;
- WriteRequestSize = *write_buf_cnt;
-
- if (!SetEvent (WriteBufferFullEvent))
- return FALSE;
- }
- else
- {
- if (!WriteFile ((HANDLE) dev, write_buf, *write_buf_cnt, &bytesWritten, NULL))
- return FALSE;
- }
-
- *write_buf_cnt = 0;
- return TRUE;
-}
+ return (FormatExError? FALSE : TRUE); +} + +BOOL FormatFs (int driveNo, int clusterSize, int fsType) +{ + wchar_t dllPath[MAX_PATH] = {0}; + WCHAR dir[8] = { (WCHAR) driveNo + L'A', 0 }; + PFORMATEX FormatEx; + HMODULE hModule; + int i; + WCHAR szFsFormat[16]; + WCHAR szLabel[2] = {0}; + switch (fsType) + { + case FILESYS_NTFS: + StringCchCopyW (szFsFormat, ARRAYSIZE (szFsFormat),L"NTFS"); + break; + case FILESYS_EXFAT: + StringCchCopyW (szFsFormat, ARRAYSIZE (szFsFormat),L"EXFAT"); + break; + default: + return FALSE; + } + + + if (GetSystemDirectory (dllPath, MAX_PATH)) + { + StringCchCatW(dllPath, ARRAYSIZE(dllPath), L"\\fmifs.dll"); + } + else + StringCchCopyW(dllPath, ARRAYSIZE(dllPath), L"C:\\Windows\\System32\\fmifs.dll"); + + hModule = LoadLibrary (dllPath); + + if (hModule == NULL) + return FALSE; + + if (!(FormatEx = (PFORMATEX) GetProcAddress (GetModuleHandle (L"fmifs.dll"), "FormatEx"))) + { + FreeLibrary (hModule); + return FALSE; + } + + StringCchCatW (dir, ARRAYSIZE(dir), L":\\"); + + FormatExError = TRUE; + + // 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); + } + + // The device may be referenced for some time after FormatEx() returns + Sleep (4000); + + FreeLibrary (hModule); + return FormatExError? FALSE : TRUE; +} + +BOOL FormatNtfs (int driveNo, int clusterSize) +{ + return FormatFs (driveNo, clusterSize, FILESYS_NTFS); +} + +BOOL WriteSector (void *dev, char *sector, + char *write_buf, int *write_buf_cnt, + __int64 *nSecNo, 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 * FormatSectorSize)) + return FALSE; + + updateTime = GetTickCount (); + } + + return TRUE; + +} + + +static volatile BOOL WriteThreadRunning; +static volatile BOOL WriteThreadExitRequested; +static HANDLE WriteThreadHandle; + +static byte *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; + + if (!SetEvent (WriteBufferEmptyEvent)) + { + handleWin32Error (NULL, SRC_POS); + break; + } + } + + WriteThreadRunning = FALSE; + _endthread(); +} + + +static BOOL StartFormatWriteThread () +{ + DWORD sysErr; + + WriteBufferEmptyEvent = NULL; + WriteBufferFullEvent = NULL; + WriteThreadBuffer = NULL; + + WriteBufferEmptyEvent = CreateEvent (NULL, FALSE, TRUE, NULL); + if (!WriteBufferEmptyEvent) + goto err; + + WriteBufferFullEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + if (!WriteBufferFullEvent) + goto err; + + WriteThreadBuffer = TCalloc (FormatWriteBufferSize); + if (!WriteThreadBuffer) + { + SetLastError (ERROR_OUTOFMEMORY); + goto err; + } + + WriteThreadExitRequested = FALSE; + WriteRequestResult = ERROR_SUCCESS; + + WriteThreadHandle = (HANDLE) _beginthread (FormatWriteThreadProc, 0, NULL); + if ((uintptr_t) WriteThreadHandle == -1L) + goto err; + + WriteThreadRunning = TRUE; + return TRUE; + +err: + sysErr = GetLastError(); + + if (WriteBufferEmptyEvent) + CloseHandle (WriteBufferEmptyEvent); + if (WriteBufferFullEvent) + CloseHandle (WriteBufferFullEvent); + if (WriteThreadBuffer) + TCfree (WriteThreadBuffer); + + SetLastError (sysErr); + return FALSE; +} + + +static void StopFormatWriteThread () +{ + if (WriteThreadRunning) + { + WaitForSingleObject (WriteBufferEmptyEvent, INFINITE); + + WriteThreadExitRequested = TRUE; + SetEvent (WriteBufferFullEvent); + + WaitForSingleObject (WriteThreadHandle, INFINITE); + } + + CloseHandle (WriteBufferEmptyEvent); + CloseHandle (WriteBufferFullEvent); + TCfree (WriteThreadBuffer); +} + + +BOOL FlushFormatWriteBuffer (void *dev, char *write_buf, int *write_buf_cnt, __int64 *nSecNo, PCRYPTO_INFO cryptoInfo) +{ + UINT64_STRUCT unitNo; + DWORD bytesWritten; + + if (*write_buf_cnt == 0) + return TRUE; + + unitNo.Value = (*nSecNo * FormatSectorSize - *write_buf_cnt) / ENCRYPTION_DATA_UNIT_SIZE; + + EncryptDataUnits (write_buf, &unitNo, *write_buf_cnt / ENCRYPTION_DATA_UNIT_SIZE, cryptoInfo); + + if (WriteThreadRunning) + { + if (WaitForSingleObject (WriteBufferEmptyEvent, INFINITE) == WAIT_FAILED) + return FALSE; + + if (WriteRequestResult != ERROR_SUCCESS) + { + SetEvent (WriteBufferEmptyEvent); + SetLastError (WriteRequestResult); + return FALSE; + } + + memcpy (WriteThreadBuffer, write_buf, *write_buf_cnt); + WriteRequestHandle = dev; + WriteRequestSize = *write_buf_cnt; + + if (!SetEvent (WriteBufferFullEvent)) + return FALSE; + } + else + { + if (!WriteFile ((HANDLE) dev, write_buf, *write_buf_cnt, &bytesWritten, NULL)) + return FALSE; + } + + *write_buf_cnt = 0; + return TRUE; +} |