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