|
|
1.1.1.10 root 1: /*
1.1.1.12 root 2: Legal Notice: Some portions of the source code contained in this file were
3: derived from the source code of Encryption for the Masses 2.02a, which is
4: Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
5: Agreement for Encryption for the Masses'. Modifications and additions to
1.1.1.20 root 6: the original source code (contained in this file) and all other portions
1.1.1.21! root 7: of this file are Copyright (c) 2003-2010 TrueCrypt Developers Association
! 8: and are governed by the TrueCrypt License 3.0 the full text of which is
1.1.1.20 root 9: contained in the file License.txt included in TrueCrypt binary and source
10: code distribution packages. */
1.1.1.10 root 11:
12: #include <stdlib.h>
13: #include <string.h>
1.1.1.6 root 14:
15: #include "Tcdefs.h"
16:
1.1.1.9 root 17: #include "Common.h"
1.1.1.6 root 18: #include "Crypto.h"
19: #include "Fat.h"
20: #include "Format.h"
1.1.1.9 root 21: #include "Random.h"
1.1.1.6 root 22: #include "Volumes.h"
1.1.1.8 root 23:
1.1.1.6 root 24: #include "Apidrvr.h"
25: #include "Dlgcode.h"
26: #include "Language.h"
1.1.1.8 root 27: #include "Progress.h"
1.1.1.6 root 28: #include "Resource.h"
1.1.1.16 root 29: #include "Format/FormatCom.h"
30: #include "Format/Tcformat.h"
1.1.1.3 root 31:
1.1.1.19 root 32: int FormatWriteBufferSize = 1024 * 1024;
1.1.1.21! root 33: static uint32 FormatSectorSize = 0;
1.1.1.19 root 34:
1.1.1.14 root 35:
36: uint64 GetVolumeDataAreaSize (BOOL hiddenVolume, uint64 volumeSize)
37: {
38: uint64 reservedSize;
39:
40: if (hiddenVolume)
41: {
1.1.1.21! root 42: // Reserve free space at the end of the host filesystem. FAT file system fills the last sector with
! 43: // zeroes (marked as free; observed when quick format was performed using the OS format tool).
! 44: // Therefore, when the outer volume is mounted with hidden volume protection, such write operations
! 45: // (e.g. quick formatting the outer volume filesystem as FAT) would needlessly trigger hidden volume
! 46: // protection.
! 47:
! 48: #if TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE > 4096
! 49: # error TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE too large for very small volumes. Revise the code.
! 50: #endif
! 51:
! 52: #if TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH < TC_MAX_VOLUME_SECTOR_SIZE
! 53: # error TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH too small.
! 54: #endif
! 55:
1.1.1.14 root 56: if (volumeSize < TC_VOLUME_SMALL_SIZE_THRESHOLD)
57: reservedSize = TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE;
58: else
59: 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
60: }
61: else
62: {
63: reservedSize = TC_TOTAL_VOLUME_HEADERS_SIZE;
64: }
65:
66: if (volumeSize < reservedSize)
67: return 0;
68:
69: return volumeSize - reservedSize;
70: }
71:
72:
1.1.1.16 root 73: int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams)
1.1 root 74: {
75: int nStatus;
1.1.1.12 root 76: PCRYPTO_INFO cryptoInfo = NULL;
1.1.1.4 root 77: HANDLE dev = INVALID_HANDLE_VALUE;
1.1.1.10 root 78: DWORD dwError;
1.1.1.14 root 79: char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
1.1.1.4 root 80: unsigned __int64 num_sectors, startSector;
1.1.1.3 root 81: fatparams ft;
1.1.1.4 root 82: FILETIME ftCreationTime;
83: FILETIME ftLastWriteTime;
84: FILETIME ftLastAccessTime;
85: BOOL bTimeStampValid = FALSE;
1.1.1.12 root 86: BOOL bInstantRetryOtherFilesys = FALSE;
1.1.1.10 root 87: char dosDev[TC_MAX_PATH] = { 0 };
88: char devName[MAX_PATH] = { 0 };
89: int driveLetter = -1;
90: WCHAR deviceName[MAX_PATH];
1.1.1.16 root 91: uint64 dataOffset, dataAreaSize;
1.1.1.14 root 92: LARGE_INTEGER offset;
1.1.1.16 root 93: BOOL bFailedRequiredDASD = FALSE;
94:
1.1.1.21! root 95: FormatSectorSize = volParams->sectorSize;
! 96:
! 97: if (FormatSectorSize < TC_MIN_VOLUME_SECTOR_SIZE
! 98: || FormatSectorSize > TC_MAX_VOLUME_SECTOR_SIZE
! 99: || FormatSectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0)
! 100: {
! 101: Error ("SECTOR_SIZE_UNSUPPORTED");
! 102: return ERR_DONT_REPORT;
! 103: }
1.1.1.10 root 104:
1.1.1.12 root 105: /* WARNING: Note that if Windows fails to format the volume as NTFS and the volume size is
1.1.1.21! root 106: less than the maximum FAT size, the user is asked within this function whether he wants to instantly
1.1.1.12 root 107: retry FAT format instead (to avoid having to re-create the whole container again). If the user
108: answers yes, some of the input parameters are modified, the code below 'begin_format' is re-executed
109: and some destructive operations that were performed during the first attempt must be (and are) skipped.
110: Therefore, whenever adding or modifying any potentially destructive operations below 'begin_format',
111: determine whether they (or their portions) need to be skipped during such a second attempt; if so,
112: use the 'bInstantRetryOtherFilesys' flag to skip them. */
113:
1.1.1.15 root 114: if (volParams->hiddenVol)
1.1.1.14 root 115: {
1.1.1.15 root 116: dataOffset = volParams->hiddenVolHostSize - TC_VOLUME_HEADER_GROUP_SIZE - volParams->size;
1.1.1.14 root 117: }
118: else
119: {
1.1.1.15 root 120: if (volParams->size <= TC_TOTAL_VOLUME_HEADERS_SIZE)
1.1.1.14 root 121: return ERR_VOL_SIZE_WRONG;
122:
123: dataOffset = TC_VOLUME_DATA_OFFSET;
124: }
125:
1.1.1.16 root 126: dataAreaSize = GetVolumeDataAreaSize (volParams->hiddenVol, volParams->size);
1.1 root 127:
1.1.1.21! root 128: num_sectors = dataAreaSize / FormatSectorSize;
1.1.1.10 root 129:
1.1.1.15 root 130: if (volParams->bDevice)
1.1.1.10 root 131: {
1.1.1.15 root 132: strcpy ((char *)deviceName, volParams->volumePath);
1.1.1.10 root 133: ToUNICODE ((char *)deviceName);
134:
135: driveLetter = GetDiskDeviceDriveLetter (deviceName);
136: }
137:
1.1.1.3 root 138: VirtualLock (header, sizeof (header));
1.1 root 139:
1.1.1.16 root 140: nStatus = CreateVolumeHeaderInMemory (FALSE,
1.1.1.12 root 141: header,
1.1.1.15 root 142: volParams->ea,
1.1.1.12 root 143: FIRST_MODE_OF_OPERATION_ID,
1.1.1.15 root 144: volParams->password,
145: volParams->pkcs5,
1.1.1.12 root 146: NULL,
1.1.1.4 root 147: &cryptoInfo,
1.1.1.16 root 148: dataAreaSize,
149: volParams->hiddenVol ? dataAreaSize : 0,
1.1.1.14 root 150: dataOffset,
1.1.1.16 root 151: dataAreaSize,
1.1.1.14 root 152: 0,
1.1.1.15 root 153: volParams->headerFlags,
1.1.1.21! root 154: FormatSectorSize,
1.1.1.6 root 155: FALSE);
1.1 root 156:
157: if (nStatus != 0)
1.1.1.3 root 158: {
159: burn (header, sizeof (header));
160: VirtualUnlock (header, sizeof (header));
1.1 root 161: return nStatus;
1.1.1.3 root 162: }
163:
1.1.1.12 root 164: begin_format:
165:
1.1.1.15 root 166: if (volParams->bDevice)
1.1.1.3 root 167: {
1.1.1.10 root 168: /* Device-hosted volume */
1.1.1.14 root 169:
1.1.1.11 root 170: DWORD dwResult;
1.1.1.10 root 171: int nPass;
172:
1.1.1.15 root 173: if (FakeDosNameForDevice (volParams->volumePath, dosDev, devName, FALSE) != 0)
1.1.1.14 root 174: return ERR_OS_ERROR;
1.1.1.10 root 175:
176: if (IsDeviceMounted (devName))
177: {
1.1.1.16 root 178: if ((dev = DismountDrive (devName, volParams->volumePath)) == INVALID_HANDLE_VALUE)
1.1.1.4 root 179: {
1.1.1.11 root 180: Error ("FORMAT_CANT_DISMOUNT_FILESYS");
181: nStatus = ERR_DONT_REPORT;
182: goto error;
1.1.1.10 root 183: }
1.1.1.16 root 184:
185: /* Gain "raw" access to the partition (it contains a live filesystem and the filesystem driver
186: would otherwise prevent us from writing to hidden sectors). */
187:
188: if (!DeviceIoControl (dev,
189: FSCTL_ALLOW_EXTENDED_DASD_IO,
190: NULL,
191: 0,
192: NULL,
193: 0,
194: &dwResult,
195: NULL))
196: {
197: bFailedRequiredDASD = TRUE;
198: }
1.1.1.10 root 199: }
1.1.1.17 root 200: else if (IsOSAtLeast (WIN_VISTA) && driveLetter == -1)
1.1.1.10 root 201: {
202: // Windows Vista doesn't allow overwriting sectors belonging to an unformatted partition
203: // to which no drive letter has been assigned under the system. This problem can be worked
204: // around by assigning a drive letter to the partition temporarily.
205:
206: char szDriveLetter[] = { 'A', ':', 0 };
207: char rootPath[] = { 'A', ':', '\\', 0 };
208: char uniqVolName[MAX_PATH+1] = { 0 };
209: int tmpDriveLetter = -1;
210: BOOL bResult = FALSE;
211:
212: tmpDriveLetter = GetFirstAvailableDrive ();
213:
214: if (tmpDriveLetter != -1)
215: {
1.1.1.19 root 216: rootPath[0] += (char) tmpDriveLetter;
217: szDriveLetter[0] += (char) tmpDriveLetter;
1.1.1.10 root 218:
1.1.1.15 root 219: if (DefineDosDevice (DDD_RAW_TARGET_PATH, szDriveLetter, volParams->volumePath))
1.1.1.10 root 220: {
221: bResult = GetVolumeNameForVolumeMountPoint (rootPath, uniqVolName, MAX_PATH);
222:
223: DefineDosDevice (DDD_RAW_TARGET_PATH|DDD_REMOVE_DEFINITION|DDD_EXACT_MATCH_ON_REMOVE,
224: szDriveLetter,
1.1.1.15 root 225: volParams->volumePath);
1.1.1.10 root 226:
227: if (bResult
228: && SetVolumeMountPoint (rootPath, uniqVolName))
229: {
1.1.1.14 root 230: // The drive letter can be removed now
1.1.1.10 root 231: DeleteVolumeMountPoint (rootPath);
232: }
233: }
234: }
235: }
236:
1.1.1.16 root 237: // For extra safety, we will try to gain "raw" access to the partition. Note that this should actually be
238: // redundant because if the filesystem was mounted, we already tried to obtain DASD above. If we failed,
239: // bFailedRequiredDASD was set to TRUE and therefore we will perform pseudo "quick format" below. However,
240: // for extra safety, in case IsDeviceMounted() failed to detect a live filesystem, we will blindly
241: // send FSCTL_ALLOW_EXTENDED_DASD_IO (possibly for a second time) without checking the result.
242:
243: DeviceIoControl (dev,
244: FSCTL_ALLOW_EXTENDED_DASD_IO,
245: NULL,
246: 0,
247: NULL,
248: 0,
249: &dwResult,
250: NULL);
251:
252:
253: // If DASD is needed but we failed to obtain it, perform open - 'quick format' - close - open
254: // so that the filesystem driver does not prevent us from formatting hidden sectors.
255: for (nPass = (bFailedRequiredDASD ? 0 : 1); nPass < 2; nPass++)
1.1.1.10 root 256: {
1.1.1.14 root 257: int retryCount;
258:
259: retryCount = 0;
260:
1.1.1.10 root 261: // Try exclusive access mode first
1.1.1.14 root 262: // Note that when exclusive access is denied, it is worth retrying (usually succeeds after a few tries).
263: while (dev == INVALID_HANDLE_VALUE && retryCount++ < EXCL_ACCESS_MAX_AUTO_RETRIES)
264: {
1.1.1.21! root 265: dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
1.1.1.10 root 266:
1.1.1.14 root 267: if (retryCount > 1)
268: Sleep (EXCL_ACCESS_AUTO_RETRY_DELAY);
269: }
270:
1.1.1.10 root 271: if (dev == INVALID_HANDLE_VALUE)
272: {
1.1.1.14 root 273: // Exclusive access denied -- retry in shared mode
1.1.1.21! root 274: dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1.1.1.10 root 275: if (dev != INVALID_HANDLE_VALUE)
276: {
1.1.1.15 root 277: if (IDNO == MessageBoxW (volParams->hwndDlg, GetString ("DEVICE_IN_USE_FORMAT"), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2))
1.1.1.10 root 278: {
279: nStatus = ERR_DONT_REPORT;
280: goto error;
281: }
282: }
283: else
284: {
1.1.1.16 root 285: handleWin32Error (volParams->hwndDlg);
286: Error ("CANT_ACCESS_VOL");
287: nStatus = ERR_DONT_REPORT;
1.1.1.10 root 288: goto error;
289: }
290: }
291:
1.1.1.15 root 292: if (volParams->hiddenVol || bInstantRetryOtherFilesys)
1.1.1.10 root 293: break; // The following "quick format" operation would damage the outer volume
294:
295: if (nPass == 0)
296: {
1.1.1.16 root 297: char buf [2 * TC_MAX_VOLUME_SECTOR_SIZE];
1.1.1.10 root 298: DWORD bw;
299:
1.1.1.16 root 300: // Perform pseudo "quick format" so that the filesystem driver does not prevent us from
301: // formatting hidden sectors
1.1.1.10 root 302: memset (buf, 0, sizeof (buf));
1.1.1.16 root 303:
304: if (!WriteFile (dev, buf, sizeof (buf), &bw, NULL))
305: {
306: nStatus = ERR_OS_ERROR;
307: goto error;
308: }
309:
1.1.1.10 root 310: FlushFileBuffers (dev);
311: CloseHandle (dev);
312: dev = INVALID_HANDLE_VALUE;
1.1.1.4 root 313: }
314: }
1.1.1.11 root 315:
316: if (DeviceIoControl (dev, FSCTL_IS_VOLUME_MOUNTED, NULL, 0, NULL, 0, &dwResult, NULL))
317: {
318: Error ("FORMAT_CANT_DISMOUNT_FILESYS");
319: nStatus = ERR_DONT_REPORT;
320: goto error;
321: }
1.1.1.3 root 322: }
323: else
324: {
1.1.1.10 root 325: /* File-hosted volume */
326:
1.1.1.19 root 327: dev = CreateFile (volParams->volumePath, GENERIC_READ | GENERIC_WRITE,
1.1.1.15 root 328: (volParams->hiddenVol || bInstantRetryOtherFilesys) ? (FILE_SHARE_READ | FILE_SHARE_WRITE) : 0,
329: NULL, (volParams->hiddenVol || bInstantRetryOtherFilesys) ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
1.1.1.6 root 330:
1.1.1.8 root 331: if (dev == INVALID_HANDLE_VALUE)
332: {
1.1.1.14 root 333: nStatus = ERR_OS_ERROR;
1.1.1.8 root 334: goto error;
335: }
336:
1.1.1.19 root 337: DisableFileCompression (dev);
338:
1.1.1.15 root 339: if (!volParams->hiddenVol && !bInstantRetryOtherFilesys)
1.1.1.6 root 340: {
341: LARGE_INTEGER volumeSize;
1.1.1.16 root 342: volumeSize.QuadPart = dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE;
1.1.1.6 root 343:
1.1.1.15 root 344: if (volParams->sparseFileSwitch && volParams->quickFormat)
1.1.1.8 root 345: {
346: // Create as sparse file container
347: DWORD tmp;
348: if (!DeviceIoControl (dev, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &tmp, NULL))
349: {
1.1.1.14 root 350: nStatus = ERR_OS_ERROR;
1.1.1.8 root 351: goto error;
352: }
353: }
354:
355: // Preallocate the file
1.1.1.6 root 356: if (!SetFilePointerEx (dev, volumeSize, NULL, FILE_BEGIN)
357: || !SetEndOfFile (dev)
358: || SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0)
359: {
1.1.1.14 root 360: nStatus = ERR_OS_ERROR;
1.1.1.7 root 361: goto error;
1.1.1.6 root 362: }
363: }
1.1.1.3 root 364: }
365:
1.1.1.15 root 366: if (volParams->hiddenVol && !volParams->bDevice && bPreserveTimestamp)
1.1.1.4 root 367: {
368: if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
369: bTimeStampValid = FALSE;
370: else
371: bTimeStampValid = TRUE;
1.1.1.3 root 372: }
1.1 root 373:
1.1.1.16 root 374: KillTimer (volParams->hwndDlg, TIMER_ID_RANDVIEW);
1.1 root 375:
1.1.1.6 root 376: /* Volume header */
1.1.1.4 root 377:
378: // Hidden volume setup
1.1.1.15 root 379: if (volParams->hiddenVol)
1.1.1.4 root 380: {
1.1.1.14 root 381: LARGE_INTEGER headerOffset;
382:
1.1.1.16 root 383: // Check hidden volume size
1.1.1.15 root 384: if (volParams->hiddenVolHostSize < TC_MIN_HIDDEN_VOLUME_HOST_SIZE || volParams->hiddenVolHostSize > TC_MAX_HIDDEN_VOLUME_HOST_SIZE)
1.1.1.4 root 385: {
1.1.1.7 root 386: nStatus = ERR_VOL_SIZE_WRONG;
387: goto error;
1.1.1.4 root 388: }
389:
390: // Seek to hidden volume header location
1.1.1.14 root 391:
392: headerOffset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET;
393:
394: if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
1.1.1.4 root 395: {
1.1.1.14 root 396: nStatus = ERR_OS_ERROR;
1.1.1.7 root 397: goto error;
1.1.1.4 root 398: }
399: }
1.1.1.12 root 400: else if (bInstantRetryOtherFilesys)
401: {
402: // The previous file system format failed and the user wants to try again with a different file system.
403: // The volume header had been written successfully so we need to seek to the byte after the header.
404:
1.1.1.14 root 405: LARGE_INTEGER offset;
406: offset.QuadPart = TC_VOLUME_DATA_OFFSET;
407: if (!SetFilePointerEx ((HANDLE) dev, offset, NULL, FILE_BEGIN))
1.1.1.12 root 408: {
1.1.1.14 root 409: nStatus = ERR_OS_ERROR;
1.1.1.12 root 410: goto error;
411: }
412: }
1.1.1.4 root 413:
1.1.1.12 root 414: if (!bInstantRetryOtherFilesys)
1.1.1.10 root 415: {
1.1.1.12 root 416: // Write the volume header
1.1.1.21! root 417: if (!WriteEffectiveVolumeHeader (volParams->bDevice, dev, header))
1.1.1.12 root 418: {
1.1.1.14 root 419: nStatus = ERR_OS_ERROR;
1.1.1.12 root 420: goto error;
421: }
1.1.1.4 root 422:
1.1.1.14 root 423: // To prevent fragmentation, write zeroes to reserved header sectors which are going to be filled with random data
1.1.1.21! root 424: if (!volParams->bDevice && !volParams->hiddenVol)
1.1.1.14 root 425: {
426: byte buf[TC_VOLUME_HEADER_GROUP_SIZE - TC_VOLUME_HEADER_EFFECTIVE_SIZE];
1.1.1.21! root 427: DWORD bytesWritten;
1.1.1.14 root 428: ZeroMemory (buf, sizeof (buf));
1.1.1.21! root 429:
! 430: if (!WriteFile (dev, buf, sizeof (buf), &bytesWritten, NULL))
1.1.1.14 root 431: {
432: nStatus = ERR_OS_ERROR;
433: goto error;
434: }
1.1.1.21! root 435:
! 436: if (bytesWritten != sizeof (buf))
! 437: {
! 438: nStatus = ERR_PARAMETER_INCORRECT;
! 439: goto error;
! 440: }
1.1.1.14 root 441: }
442: }
1.1.1.4 root 443:
1.1.1.15 root 444: if (volParams->hiddenVol)
1.1.1.4 root 445: {
446: // Calculate data area position of hidden volume
1.1.1.14 root 447: cryptoInfo->hiddenVolumeOffset = dataOffset;
1.1.1.4 root 448:
449: // Validate the offset
1.1.1.21! root 450: if (dataOffset % FormatSectorSize != 0)
1.1.1.4 root 451: {
1.1.1.6 root 452: nStatus = ERR_VOL_SIZE_WRONG;
453: goto error;
1.1.1.4 root 454: }
455:
1.1.1.15 root 456: volParams->quickFormat = TRUE; // To entirely format a hidden volume would be redundant
1.1.1.4 root 457: }
458:
1.1.1.14 root 459: /* Data area */
1.1.1.21! root 460: startSector = dataOffset / FormatSectorSize;
1.1.1.14 root 461:
1.1.1.4 root 462: // Format filesystem
463:
1.1.1.15 root 464: switch (volParams->fileSystem)
1.1.1.3 root 465: {
466: case FILESYS_NONE:
1.1.1.10 root 467: case FILESYS_NTFS:
1.1.1.16 root 468:
469: if (volParams->bDevice && !StartFormatWriteThread())
470: {
471: nStatus = ERR_OS_ERROR;
472: goto error;
473: }
474:
1.1.1.15 root 475: nStatus = FormatNoFs (startSector, num_sectors, dev, cryptoInfo, volParams->quickFormat);
1.1.1.16 root 476:
477: if (volParams->bDevice)
478: StopFormatWriteThread();
479:
1.1.1.3 root 480: break;
1.1.1.10 root 481:
1.1.1.3 root 482: case FILESYS_FAT:
1.1.1.4 root 483: if (num_sectors > 0xFFFFffff)
484: {
1.1.1.6 root 485: nStatus = ERR_VOL_SIZE_WRONG;
486: goto error;
1.1.1.4 root 487: }
488:
489: // Calculate the fats, root dir etc
490: ft.num_sectors = (unsigned int) (num_sectors);
1.1.1.21! root 491:
! 492: #if TC_MAX_VOLUME_SECTOR_SIZE > 0xFFFF
! 493: #error TC_MAX_VOLUME_SECTOR_SIZE > 0xFFFF
! 494: #endif
! 495:
! 496: ft.sector_size = (uint16) FormatSectorSize;
1.1.1.15 root 497: ft.cluster_size = volParams->clusterSize;
1.1.1.6 root 498: memcpy (ft.volume_name, "NO NAME ", 11);
1.1.1.4 root 499: GetFatParams (&ft);
1.1.1.21! root 500: *(volParams->realClusterSize) = ft.cluster_size * FormatSectorSize;
1.1.1.4 root 501:
1.1.1.16 root 502: if (volParams->bDevice && !StartFormatWriteThread())
503: {
504: nStatus = ERR_OS_ERROR;
505: goto error;
506: }
507:
1.1.1.15 root 508: nStatus = FormatFat (startSector, &ft, (void *) dev, cryptoInfo, volParams->quickFormat);
1.1.1.16 root 509:
510: if (volParams->bDevice)
511: StopFormatWriteThread();
512:
1.1.1.3 root 513: break;
1.1.1.13 root 514:
515: default:
516: nStatus = ERR_PARAMETER_INCORRECT;
517: goto error;
1.1.1.3 root 518: }
1.1 root 519:
1.1.1.15 root 520: if (nStatus != ERR_SUCCESS)
521: goto error;
522:
1.1.1.14 root 523: // Write header backup
1.1.1.16 root 524: offset.QuadPart = volParams->hiddenVol ? volParams->hiddenVolHostSize - TC_HIDDEN_VOLUME_HEADER_OFFSET : dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE;
1.1.1.14 root 525:
526: if (!SetFilePointerEx ((HANDLE) dev, offset, NULL, FILE_BEGIN))
527: {
528: nStatus = ERR_OS_ERROR;
529: goto error;
530: }
531:
1.1.1.16 root 532: nStatus = CreateVolumeHeaderInMemory (FALSE,
1.1.1.14 root 533: header,
1.1.1.15 root 534: volParams->ea,
1.1.1.14 root 535: FIRST_MODE_OF_OPERATION_ID,
1.1.1.15 root 536: volParams->password,
537: volParams->pkcs5,
1.1.1.14 root 538: cryptoInfo->master_keydata,
539: &cryptoInfo,
1.1.1.16 root 540: dataAreaSize,
541: volParams->hiddenVol ? dataAreaSize : 0,
1.1.1.14 root 542: dataOffset,
1.1.1.16 root 543: dataAreaSize,
1.1.1.14 root 544: 0,
1.1.1.15 root 545: volParams->headerFlags,
1.1.1.21! root 546: FormatSectorSize,
1.1.1.14 root 547: FALSE);
548:
1.1.1.21! root 549: if (!WriteEffectiveVolumeHeader (volParams->bDevice, dev, header))
1.1.1.14 root 550: {
551: nStatus = ERR_OS_ERROR;
552: goto error;
553: }
554:
1.1.1.16 root 555: // Fill reserved header sectors (including the backup header area) with random data
1.1.1.15 root 556: if (!volParams->hiddenVol)
1.1.1.14 root 557: {
1.1.1.16 root 558: nStatus = WriteRandomDataToReservedHeaderAreas (dev, cryptoInfo, dataAreaSize, FALSE, FALSE);
1.1.1.14 root 559:
560: if (nStatus != ERR_SUCCESS)
561: goto error;
562: }
563:
1.1.1.19 root 564: #ifndef DEBUG
565: if (volParams->quickFormat && volParams->fileSystem != FILESYS_NTFS)
566: Sleep (500); // User-friendly GUI
567: #endif
568:
1.1.1.10 root 569: error:
570: dwError = GetLastError();
1.1.1.3 root 571:
572: burn (header, sizeof (header));
573: VirtualUnlock (header, sizeof (header));
1.1 root 574:
1.1.1.11 root 575: if (dev != INVALID_HANDLE_VALUE)
1.1.1.4 root 576: {
1.1.1.15 root 577: if (!volParams->bDevice && !volParams->hiddenVol && nStatus != 0)
1.1.1.11 root 578: {
579: // Remove preallocated part before closing file handle if format failed
580: if (SetFilePointer (dev, 0, NULL, FILE_BEGIN) == 0)
581: SetEndOfFile (dev);
582: }
1.1.1.6 root 583:
1.1.1.11 root 584: FlushFileBuffers (dev);
1.1.1.4 root 585:
1.1.1.11 root 586: if (bTimeStampValid)
1.1.1.20 root 587: SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime);
1.1.1.11 root 588:
589: CloseHandle (dev);
590: dev = INVALID_HANDLE_VALUE;
591: }
1.1 root 592:
1.1.1.6 root 593: if (nStatus != 0)
1.1.1.3 root 594: {
1.1.1.10 root 595: SetLastError(dwError);
1.1.1.12 root 596: goto fv_end;
1.1.1.10 root 597: }
1.1.1.6 root 598:
1.1.1.15 root 599: if (volParams->fileSystem == FILESYS_NTFS)
1.1.1.10 root 600: {
601: // Quick-format volume as NTFS
602: int driveNo = GetLastAvailableDrive ();
603: MountOptions mountOptions;
604: int retCode;
1.1.1.3 root 605:
1.1.1.10 root 606: ZeroMemory (&mountOptions, sizeof (mountOptions));
1.1.1.5 root 607:
1.1.1.10 root 608: if (driveNo == -1)
609: {
1.1.1.15 root 610: MessageBoxW (volParams->hwndDlg, GetString ("NO_FREE_DRIVES"), lpszTitle, ICON_HAND);
611: MessageBoxW (volParams->hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND);
1.1.1.3 root 612:
1.1.1.12 root 613: nStatus = ERR_NO_FREE_DRIVES;
614: goto fv_end;
1.1.1.10 root 615: }
1.1.1.4 root 616:
1.1.1.10 root 617: mountOptions.ReadOnly = FALSE;
618: mountOptions.Removable = FALSE;
619: mountOptions.ProtectHiddenVolume = FALSE;
620: mountOptions.PreserveTimestamp = bPreserveTimestamp;
1.1.1.13 root 621: mountOptions.PartitionInInactiveSysEncScope = FALSE;
1.1.1.14 root 622: mountOptions.UseBackupHeader = FALSE;
1.1.1.3 root 623:
1.1.1.15 root 624: if (MountVolume (volParams->hwndDlg, driveNo, volParams->volumePath, volParams->password, FALSE, TRUE, &mountOptions, FALSE, TRUE) < 1)
1.1.1.10 root 625: {
1.1.1.15 root 626: MessageBoxW (volParams->hwndDlg, GetString ("CANT_MOUNT_VOLUME"), lpszTitle, ICON_HAND);
627: MessageBoxW (volParams->hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND);
1.1.1.12 root 628: nStatus = ERR_VOL_MOUNT_FAILED;
629: goto fv_end;
1.1.1.10 root 630: }
1.1.1.3 root 631:
1.1.1.10 root 632: if (!IsAdmin () && IsUacSupported ())
1.1.1.15 root 633: retCode = UacFormatNtfs (volParams->hwndDlg, driveNo, volParams->clusterSize);
1.1.1.10 root 634: else
1.1.1.15 root 635: retCode = FormatNtfs (driveNo, volParams->clusterSize);
1.1.1.3 root 636:
1.1.1.10 root 637: if (retCode != TRUE)
638: {
1.1.1.15 root 639: if (!UnmountVolume (volParams->hwndDlg, driveNo, FALSE))
640: MessageBoxW (volParams->hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND);
1.1.1.3 root 641:
1.1.1.21! root 642: if (dataAreaSize <= TC_MAX_FAT_SECTOR_COUNT * FormatSectorSize)
1.1.1.12 root 643: {
644: if (AskErrYesNo ("FORMAT_NTFS_FAILED_ASK_FAT") == IDYES)
645: {
646: // NTFS format failed and the user wants to try FAT format immediately
1.1.1.15 root 647: volParams->fileSystem = FILESYS_FAT;
1.1.1.12 root 648: bInstantRetryOtherFilesys = TRUE;
1.1.1.15 root 649: volParams->quickFormat = TRUE; // Volume has already been successfully TC-formatted
650: volParams->clusterSize = 0; // Default cluster size
1.1.1.12 root 651: goto begin_format;
652: }
653: }
654: else
655: Error ("FORMAT_NTFS_FAILED");
656:
657: nStatus = ERR_DONT_REPORT;
658: goto fv_end;
1.1.1.3 root 659: }
1.1.1.10 root 660:
1.1.1.15 root 661: if (!UnmountVolume (volParams->hwndDlg, driveNo, FALSE))
662: MessageBoxW (volParams->hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND);
1.1.1.3 root 663: }
664:
1.1.1.12 root 665: fv_end:
1.1.1.17 root 666: dwError = GetLastError();
1.1.1.12 root 667:
668: if (dosDev[0])
1.1.1.15 root 669: RemoveFakeDosName (volParams->volumePath, dosDev);
1.1.1.12 root 670:
671: crypto_close (cryptoInfo);
672:
1.1.1.17 root 673: SetLastError (dwError);
1.1 root 674: return nStatus;
1.1.1.3 root 675: }
1.1 root 676:
1.1.1.3 root 677:
1.1.1.8 root 678: int FormatNoFs (unsigned __int64 startSector, __int64 num_sectors, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat)
1.1.1.3 root 679: {
680: int write_buf_cnt = 0;
1.1.1.21! root 681: char sector[TC_MAX_VOLUME_SECTOR_SIZE], *write_buf;
1.1.1.4 root 682: unsigned __int64 nSecNo = startSector;
1.1.1.12 root 683: int retVal = 0;
1.1.1.16 root 684: DWORD err;
1.1.1.12 root 685: char temporaryKey[MASTER_KEYDATA_SIZE];
686: char originalK2[MASTER_KEYDATA_SIZE];
1.1.1.4 root 687:
1.1.1.8 root 688: LARGE_INTEGER startOffset;
689: LARGE_INTEGER newOffset;
690:
1.1.1.4 root 691: // Seek to start sector
1.1.1.21! root 692: startOffset.QuadPart = startSector * FormatSectorSize;
1.1.1.6 root 693: if (!SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN)
694: || newOffset.QuadPart != startOffset.QuadPart)
1.1.1.4 root 695: {
1.1.1.14 root 696: return ERR_OS_ERROR;
1.1.1.4 root 697: }
1.1.1.12 root 698:
1.1.1.19 root 699: write_buf = (char *)TCalloc (FormatWriteBufferSize);
1.1.1.17 root 700: if (!write_buf)
701: return ERR_OUTOFMEMORY;
702:
1.1.1.12 root 703: VirtualLock (temporaryKey, sizeof (temporaryKey));
704: VirtualLock (originalK2, sizeof (originalK2));
1.1.1.3 root 705:
706: memset (sector, 0, sizeof (sector));
707:
1.1.1.12 root 708: // Remember the original secondary key (XTS mode) before generating a temporary one
709: memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2));
710:
1.1.1.7 root 711: /* Fill the rest of the data area with random data */
712:
1.1.1.3 root 713: if(!quickFormat)
714: {
1.1.1.7 root 715: /* Generate a random temporary key set to be used for "dummy" encryption that will fill
716: the free disk space (data area) with random data. This is necessary for plausible
1.1.1.12 root 717: deniability of hidden volumes. */
1.1.1.6 root 718:
1.1.1.9 root 719: // Temporary master key
720: if (!RandgetBytes (temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE))
721: goto fail;
1.1.1.12 root 722:
723: // Temporary secondary key (XTS mode)
724: if (!RandgetBytes (cryptoInfo->k2, sizeof cryptoInfo->k2, FALSE))
1.1.1.9 root 725: goto fail;
1.1.1.7 root 726:
727: retVal = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks);
1.1.1.12 root 728: if (retVal != ERR_SUCCESS)
729: goto fail;
730:
1.1.1.7 root 731: if (!EAInitMode (cryptoInfo))
732: {
1.1.1.12 root 733: retVal = ERR_MODE_INIT_FAILED;
734: goto fail;
1.1.1.7 root 735: }
1.1.1.4 root 736:
1.1.1.3 root 737: while (num_sectors--)
738: {
1.1.1.6 root 739: if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8 root 740: cryptoInfo) == FALSE)
1.1.1.3 root 741: goto fail;
742: }
1.1.1.14 root 743:
744: if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo))
1.1.1.3 root 745: goto fail;
746: }
747: else
748: nSecNo = num_sectors;
749:
1.1.1.21! root 750: UpdateProgressBar (nSecNo * FormatSectorSize);
1.1.1.3 root 751:
1.1.1.12 root 752: // Restore the original secondary key (XTS mode) in case NTFS format fails and the user wants to try FAT immediately
753: memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2));
754:
755: // Reinitialize the encryption algorithm and mode in case NTFS format fails and the user wants to try FAT immediately
756: retVal = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks);
757: if (retVal != ERR_SUCCESS)
758: goto fail;
759: if (!EAInitMode (cryptoInfo))
760: {
761: retVal = ERR_MODE_INIT_FAILED;
762: goto fail;
763: }
764:
1.1.1.7 root 765: burn (temporaryKey, sizeof(temporaryKey));
1.1.1.12 root 766: burn (originalK2, sizeof(originalK2));
767: VirtualUnlock (temporaryKey, sizeof (temporaryKey));
768: VirtualUnlock (originalK2, sizeof (originalK2));
1.1.1.17 root 769: TCfree (write_buf);
770:
1.1.1.3 root 771: return 0;
772:
773: fail:
1.1.1.16 root 774: err = GetLastError();
1.1.1.3 root 775:
1.1.1.7 root 776: burn (temporaryKey, sizeof(temporaryKey));
1.1.1.12 root 777: burn (originalK2, sizeof(originalK2));
778: VirtualUnlock (temporaryKey, sizeof (temporaryKey));
779: VirtualUnlock (originalK2, sizeof (originalK2));
1.1.1.17 root 780: TCfree (write_buf);
1.1.1.16 root 781:
782: SetLastError (err);
1.1.1.12 root 783: return (retVal ? retVal : ERR_OS_ERROR);
1.1 root 784: }
1.1.1.3 root 785:
786:
787: volatile BOOLEAN FormatExResult;
788:
789: BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID parameter)
790: {
791: if (command == FMIFS_DONE)
792: FormatExResult = *(BOOLEAN *) parameter;
793: return TRUE;
794: }
795:
796: BOOL FormatNtfs (int driveNo, int clusterSize)
797: {
1.1.1.19 root 798: WCHAR dir[8] = { (WCHAR) driveNo + 'A', 0 };
1.1.1.3 root 799: PFORMATEX FormatEx;
800: HMODULE hModule = LoadLibrary ("fmifs.dll");
1.1.1.10 root 801: int i;
1.1.1.3 root 802:
803: if (hModule == NULL)
804: return FALSE;
805:
1.1.1.19 root 806: if (!(FormatEx = (PFORMATEX) GetProcAddress (GetModuleHandle ("fmifs.dll"), "FormatEx")))
1.1.1.3 root 807: {
808: FreeLibrary (hModule);
809: return FALSE;
810: }
811:
812: wcscat (dir, L":\\");
813:
814: FormatExResult = FALSE;
815:
1.1.1.12 root 816: // Windows sometimes fails to format a volume (hosted on a removable medium) as NTFS.
1.1.1.10 root 817: // It often helps to retry several times.
1.1.1.19 root 818: for (i = 0; i < 50 && FormatExResult != TRUE; i++)
1.1.1.10 root 819: {
1.1.1.21! root 820: FormatEx (dir, FMIFS_HARDDISK, L"NTFS", L"", TRUE, clusterSize * FormatSectorSize, FormatExCallback);
1.1.1.10 root 821: }
1.1.1.3 root 822:
1.1.1.19 root 823: // The device may be referenced for some time after FormatEx() returns
824: Sleep (2000);
825:
1.1.1.3 root 826: FreeLibrary (hModule);
827: return FormatExResult;
828: }
829:
1.1.1.8 root 830:
1.1.1.12 root 831: BOOL WriteSector (void *dev, char *sector,
1.1.1.3 root 832: char *write_buf, int *write_buf_cnt,
1.1.1.8 root 833: __int64 *nSecNo, PCRYPTO_INFO cryptoInfo)
1.1.1.3 root 834: {
1.1.1.8 root 835: static __int32 updateTime = 0;
1.1.1.4 root 836:
1.1.1.12 root 837: (*nSecNo)++;
1.1.1.4 root 838:
1.1.1.21! root 839: memcpy (write_buf + *write_buf_cnt, sector, FormatSectorSize);
! 840: (*write_buf_cnt) += FormatSectorSize;
1.1.1.3 root 841:
1.1.1.19 root 842: if (*write_buf_cnt == FormatWriteBufferSize && !FlushFormatWriteBuffer (dev, write_buf, write_buf_cnt, nSecNo, cryptoInfo))
1.1.1.14 root 843: return FALSE;
1.1.1.6 root 844:
845: if (GetTickCount () - updateTime > 25)
1.1.1.3 root 846: {
1.1.1.21! root 847: if (UpdateProgressBar (*nSecNo * FormatSectorSize))
1.1.1.3 root 848: return FALSE;
1.1.1.6 root 849:
850: updateTime = GetTickCount ();
1.1.1.3 root 851: }
852:
853: return TRUE;
854:
855: }
1.1.1.14 root 856:
857:
1.1.1.16 root 858: static volatile BOOL WriteThreadRunning;
859: static volatile BOOL WriteThreadExitRequested;
860: static HANDLE WriteThreadHandle;
861:
862: static byte *WriteThreadBuffer;
863: static HANDLE WriteBufferEmptyEvent;
864: static HANDLE WriteBufferFullEvent;
865:
866: static volatile HANDLE WriteRequestHandle;
867: static volatile int WriteRequestSize;
868: static volatile DWORD WriteRequestResult;
869:
870:
871: static void __cdecl FormatWriteThreadProc (void *arg)
872: {
873: DWORD bytesWritten;
874:
875: SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
876:
877: while (!WriteThreadExitRequested)
878: {
879: if (WaitForSingleObject (WriteBufferFullEvent, INFINITE) == WAIT_FAILED)
880: {
881: handleWin32Error (NULL);
882: break;
883: }
884:
885: if (WriteThreadExitRequested)
886: break;
887:
888: if (!WriteFile (WriteRequestHandle, WriteThreadBuffer, WriteRequestSize, &bytesWritten, NULL))
889: WriteRequestResult = GetLastError();
890: else
891: WriteRequestResult = ERROR_SUCCESS;
892:
893: if (!SetEvent (WriteBufferEmptyEvent))
894: {
895: handleWin32Error (NULL);
896: break;
897: }
898: }
899:
900: WriteThreadRunning = FALSE;
901: _endthread();
902: }
903:
904:
905: static BOOL StartFormatWriteThread ()
906: {
907: DWORD sysErr;
908:
909: WriteBufferEmptyEvent = NULL;
910: WriteBufferFullEvent = NULL;
911: WriteThreadBuffer = NULL;
912:
913: WriteBufferEmptyEvent = CreateEvent (NULL, FALSE, TRUE, NULL);
914: if (!WriteBufferEmptyEvent)
915: goto err;
916:
917: WriteBufferFullEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
918: if (!WriteBufferFullEvent)
919: goto err;
920:
1.1.1.19 root 921: WriteThreadBuffer = TCalloc (FormatWriteBufferSize);
1.1.1.16 root 922: if (!WriteThreadBuffer)
923: {
924: SetLastError (ERROR_OUTOFMEMORY);
925: goto err;
926: }
927:
928: WriteThreadExitRequested = FALSE;
929: WriteRequestResult = ERROR_SUCCESS;
930:
931: WriteThreadHandle = (HANDLE) _beginthread (FormatWriteThreadProc, 0, NULL);
932: if ((uintptr_t) WriteThreadHandle == -1L)
933: goto err;
934:
935: WriteThreadRunning = TRUE;
936: return TRUE;
937:
938: err:
939: sysErr = GetLastError();
940:
941: if (WriteBufferEmptyEvent)
942: CloseHandle (WriteBufferEmptyEvent);
943: if (WriteBufferFullEvent)
944: CloseHandle (WriteBufferFullEvent);
945: if (WriteThreadBuffer)
946: TCfree (WriteThreadBuffer);
947:
948: SetLastError (sysErr);
949: return FALSE;
950: }
951:
952:
953: static void StopFormatWriteThread ()
954: {
955: if (WriteThreadRunning)
956: {
957: WaitForSingleObject (WriteBufferEmptyEvent, INFINITE);
958:
959: WriteThreadExitRequested = TRUE;
960: SetEvent (WriteBufferFullEvent);
961:
962: WaitForSingleObject (WriteThreadHandle, INFINITE);
963: }
964:
965: CloseHandle (WriteBufferEmptyEvent);
966: CloseHandle (WriteBufferFullEvent);
967: TCfree (WriteThreadBuffer);
968: }
969:
970:
1.1.1.14 root 971: BOOL FlushFormatWriteBuffer (void *dev, char *write_buf, int *write_buf_cnt, __int64 *nSecNo, PCRYPTO_INFO cryptoInfo)
972: {
973: UINT64_STRUCT unitNo;
974: DWORD bytesWritten;
975:
976: if (*write_buf_cnt == 0)
977: return TRUE;
978:
1.1.1.21! root 979: unitNo.Value = (*nSecNo * FormatSectorSize - *write_buf_cnt) / ENCRYPTION_DATA_UNIT_SIZE;
1.1.1.14 root 980:
981: EncryptDataUnits (write_buf, &unitNo, *write_buf_cnt / ENCRYPTION_DATA_UNIT_SIZE, cryptoInfo);
982:
1.1.1.16 root 983: if (WriteThreadRunning)
984: {
985: if (WaitForSingleObject (WriteBufferEmptyEvent, INFINITE) == WAIT_FAILED)
986: return FALSE;
987:
988: if (WriteRequestResult != ERROR_SUCCESS)
989: {
1.1.1.17 root 990: SetEvent (WriteBufferEmptyEvent);
1.1.1.16 root 991: SetLastError (WriteRequestResult);
992: return FALSE;
993: }
994:
995: memcpy (WriteThreadBuffer, write_buf, *write_buf_cnt);
996: WriteRequestHandle = dev;
997: WriteRequestSize = *write_buf_cnt;
998:
999: if (!SetEvent (WriteBufferFullEvent))
1000: return FALSE;
1001: }
1002: else
1003: {
1004: if (!WriteFile ((HANDLE) dev, write_buf, *write_buf_cnt, &bytesWritten, NULL))
1005: return FALSE;
1006: }
1.1.1.14 root 1007:
1008: *write_buf_cnt = 0;
1009: return TRUE;
1010: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.