|
|
1.1 root 1: /* 1.1.1.6 ! root 2: Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved. 1.1 root 3: 1.1.1.6 ! root 4: Governed by the TrueCrypt License 3.0 the full text of which is contained in 1.1.1.5 root 5: the file License.txt included in TrueCrypt binary and source code distribution 6: packages. 1.1 root 7: */ 8: 9: 1.1.1.2 root 10: /* In this file, _WIN32_WINNT is defined as 0x0600 to make filesystem shrink available (Vista 1.1 root 11: or later). _WIN32_WINNT cannot be defined as 0x0600 for the entire user-space projects 12: because it breaks the main font app when the app is running on XP (likely an MS bug). 13: IMPORTANT: Due to this issue, functions in this file must not directly interact with GUI. */ 14: #define TC_LOCAL_WIN32_WINNT_OVERRIDE 1 15: #if (_WIN32_WINNT < 0x0600) 16: # undef _WIN32_WINNT 17: # define _WIN32_WINNT 0x0600 18: #endif 19: 20: 21: #include <stdlib.h> 22: #include <string.h> 23: #include <string> 24: 25: #include "Tcdefs.h" 26: #include "Platform/Finally.h" 27: 28: #include "Common.h" 29: #include "Crc.h" 30: #include "Dlgcode.h" 31: #include "Language.h" 32: #include "Tcformat.h" 33: #include "Volumes.h" 34: 35: #include "InPlace.h" 36: 37: using namespace std; 38: using namespace TrueCrypt; 39: 40: #define TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE (2048 * BYTES_PER_KB) 41: #define TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE (2 * TC_MAX_VOLUME_SECTOR_SIZE) 42: #define TC_NTFS_CONCEAL_CONSTANT 0xFF 43: #define TC_NONSYS_INPLACE_ENC_HEADER_UPDATE_INTERVAL (64 * BYTES_PER_MB) 44: #define TC_NONSYS_INPLACE_ENC_MIN_VOL_SIZE (TC_TOTAL_VOLUME_HEADERS_SIZE + TC_MIN_NTFS_FS_SIZE * 2) 45: 46: 47: // If the returned value is greater than 0, it is the desired volume size in NTFS sectors (not in bytes) 48: // after shrinking has been performed. If there's any error, returns -1. 49: static __int64 NewFileSysSizeAfterShrink (HANDLE dev, const char *devicePath, int64 *totalClusterCount, DWORD *bytesPerCluster, BOOL silent) 50: { 51: NTFS_VOLUME_DATA_BUFFER ntfsVolData; 52: DWORD nBytesReturned; 53: __int64 fileSysSize, desiredNbrSectors; 54: 55: // Filesystem size and sector size 56: 57: if (!DeviceIoControl (dev, 58: FSCTL_GET_NTFS_VOLUME_DATA, 59: NULL, 60: 0, 61: (LPVOID) &ntfsVolData, 62: sizeof (ntfsVolData), 63: &nBytesReturned, 64: NULL)) 65: { 66: if (!silent) 67: handleWin32Error (MainDlg); 68: 69: return -1; 70: } 71: 72: fileSysSize = ntfsVolData.NumberSectors.QuadPart * ntfsVolData.BytesPerSector; 73: 74: desiredNbrSectors = (fileSysSize - TC_TOTAL_VOLUME_HEADERS_SIZE) / ntfsVolData.BytesPerSector; 75: 76: if (desiredNbrSectors <= 0) 77: return -1; 78: 79: if (totalClusterCount) 80: *totalClusterCount = ntfsVolData.TotalClusters.QuadPart; 81: if (bytesPerCluster) 82: *bytesPerCluster = ntfsVolData.BytesPerCluster; 83: 84: return desiredNbrSectors; 85: } 86: 87: 88: BOOL CheckRequirementsForNonSysInPlaceEnc (const char *devicePath, BOOL silent) 89: { 90: NTFS_VOLUME_DATA_BUFFER ntfsVolData; 91: DWORD nBytesReturned; 92: HANDLE dev; 93: char szFileSysName [256]; 94: WCHAR devPath [MAX_PATH]; 95: char dosDev [TC_MAX_PATH] = {0}; 96: char devName [MAX_PATH] = {0}; 97: int driveLetterNo = -1; 98: char szRootPath[4] = {0, ':', '\\', 0}; 99: __int64 deviceSize; 100: int partitionNumber = -1, driveNumber = -1; 101: 102: 103: /* ---------- Checks that do not require admin rights ----------- */ 104: 105: 106: /* Operating system */ 107: 108: if (CurrentOSMajor < 6) 109: { 110: if (!silent) 111: ShowInPlaceEncErrMsgWAltSteps ("OS_NOT_SUPPORTED_FOR_NONSYS_INPLACE_ENC", FALSE); 112: 113: return FALSE; 114: } 115: 116: 117: /* Volume type (must be a partition or a dynamic volume) */ 118: 119: if (sscanf (devicePath, "\\Device\\HarddiskVolume%d", &partitionNumber) != 1 1.1.1.2 root 120: && sscanf (devicePath, "\\Device\\Harddisk%d\\Partition%d", &driveNumber, &partitionNumber) != 2) 1.1 root 121: { 122: if (!silent) 123: Error ("INPLACE_ENC_INVALID_PATH"); 124: 125: return FALSE; 126: } 127: 1.1.1.2 root 128: if (partitionNumber == 0) 1.1 root 129: { 130: if (!silent) 131: Warning ("RAW_DEV_NOT_SUPPORTED_FOR_INPLACE_ENC"); 132: 133: return FALSE; 134: } 135: 136: 137: /* Admin rights */ 138: 139: if (!IsAdmin()) 140: { 141: // We rely on the wizard process to call us only when the whole wizard process has been elevated (so UAC 142: // status can be ignored). In case the IsAdmin() detection somehow fails, we allow the user to continue. 143: 144: if (!silent) 145: Warning ("ADMIN_PRIVILEGES_WARN_DEVICES"); 146: } 147: 148: 149: /* ---------- Checks that may require admin rights ----------- */ 150: 151: 152: /* Access to the partition */ 153: 154: strcpy ((char *) devPath, devicePath); 155: ToUNICODE ((char *) devPath); 156: 157: driveLetterNo = GetDiskDeviceDriveLetter (devPath); 158: 159: if (driveLetterNo >= 0) 1.1.1.4 root 160: szRootPath[0] = (char) driveLetterNo + 'A'; 1.1 root 161: 162: if (FakeDosNameForDevice (devicePath, dosDev, devName, FALSE) != 0) 163: { 164: if (!silent) 165: { 166: handleWin32Error (MainDlg); 167: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL"); 168: } 169: return FALSE; 170: } 171: 172: dev = OpenPartitionVolume (devName, 173: FALSE, // Do not require exclusive access 174: TRUE, // Require shared access (must be TRUE; otherwise, volume properties will not be possible to obtain) 175: FALSE, // Do not ask the user to confirm shared access (if exclusive fails) 176: FALSE, // Do not append alternative instructions how to encrypt the data (to applicable error messages) 177: silent); // Silent mode 178: 179: if (dev == INVALID_HANDLE_VALUE) 180: return FALSE; 181: 182: 183: /* File system type */ 184: 185: GetVolumeInformation (szRootPath, NULL, 0, NULL, NULL, NULL, szFileSysName, sizeof(szFileSysName)); 186: 187: if (strncmp (szFileSysName, "NTFS", 4)) 188: { 189: // The previous filesystem type detection method failed (or it's not NTFS) -- try an alternative method 190: 191: if (!DeviceIoControl (dev, 192: FSCTL_GET_NTFS_VOLUME_DATA, 193: NULL, 194: 0, 195: (LPVOID) &ntfsVolData, 196: sizeof (ntfsVolData), 197: &nBytesReturned, 198: NULL)) 199: { 200: if (!silent) 201: { 202: // The filesystem is not NTFS or the filesystem type could not be determined (or the NTFS filesystem 203: // is dismounted). 204: 205: if (IsDeviceMounted (devName)) 206: ShowInPlaceEncErrMsgWAltSteps ("ONLY_NTFS_SUPPORTED_FOR_NONSYS_INPLACE_ENC", FALSE); 207: else 208: Warning ("ONLY_MOUNTED_VOL_SUPPORTED_FOR_NONSYS_INPLACE_ENC"); 209: } 210: 211: CloseHandle (dev); 212: return FALSE; 213: } 214: } 215: 216: 217: /* Attempt to determine whether the filesystem can be safely shrunk */ 218: 219: if (NewFileSysSizeAfterShrink (dev, devicePath, NULL, NULL, silent) == -1) 220: { 221: // Cannot determine whether shrinking is required 222: if (!silent) 223: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE); 224: 225: CloseHandle (dev); 226: return FALSE; 227: } 228: 229: 230: /* Partition size */ 231: 232: deviceSize = GetDeviceSize (devicePath); 233: if (deviceSize < 0) 234: { 235: // Cannot determine the size of the partition 236: if (!silent) 237: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL"); 238: 239: CloseHandle (dev); 240: return FALSE; 241: } 242: 243: if (deviceSize < TC_NONSYS_INPLACE_ENC_MIN_VOL_SIZE) 244: { 245: // The partition is too small 246: if (!silent) 247: { 248: ShowInPlaceEncErrMsgWAltSteps ("PARTITION_TOO_SMALL_FOR_NONSYS_INPLACE_ENC", FALSE); 249: } 250: 251: CloseHandle (dev); 252: return FALSE; 253: } 254: 255: 256: /* Free space on the filesystem */ 257: 258: if (!DeviceIoControl (dev, 259: FSCTL_GET_NTFS_VOLUME_DATA, 260: NULL, 261: 0, 262: (LPVOID) &ntfsVolData, 263: sizeof (ntfsVolData), 264: &nBytesReturned, 265: NULL)) 266: { 267: if (!silent) 268: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL", TRUE); 269: 270: CloseHandle (dev); 271: return FALSE; 272: } 273: 274: if (ntfsVolData.FreeClusters.QuadPart * ntfsVolData.BytesPerCluster < TC_TOTAL_VOLUME_HEADERS_SIZE) 275: { 276: if (!silent) 277: ShowInPlaceEncErrMsgWAltSteps ("NOT_ENOUGH_FREE_FILESYS_SPACE_FOR_SHRINK", TRUE); 278: 279: CloseHandle (dev); 280: return FALSE; 281: } 282: 283: 284: /* Filesystem sector size */ 285: 286: if (ntfsVolData.BytesPerSector > TC_MAX_VOLUME_SECTOR_SIZE 287: || ntfsVolData.BytesPerSector % ENCRYPTION_DATA_UNIT_SIZE != 0) 288: { 289: if (!silent) 1.1.1.6 ! root 290: ShowInPlaceEncErrMsgWAltSteps ("SECTOR_SIZE_UNSUPPORTED", TRUE); 1.1 root 291: 292: CloseHandle (dev); 293: return FALSE; 294: } 295: 296: 297: CloseHandle (dev); 298: return TRUE; 299: } 300: 301: 302: int EncryptPartitionInPlaceBegin (volatile FORMAT_VOL_PARAMETERS *volParams, volatile HANDLE *outHandle, WipeAlgorithmId wipeAlgorithm) 303: { 304: SHRINK_VOLUME_INFORMATION shrinkVolInfo; 305: signed __int64 sizeToShrinkTo; 306: int nStatus = ERR_SUCCESS; 307: PCRYPTO_INFO cryptoInfo = NULL; 308: PCRYPTO_INFO cryptoInfo2 = NULL; 309: HANDLE dev = INVALID_HANDLE_VALUE; 310: DWORD dwError; 311: char *header; 312: char dosDev[TC_MAX_PATH] = {0}; 313: char devName[MAX_PATH] = {0}; 314: int driveLetter = -1; 315: WCHAR deviceName[MAX_PATH]; 316: uint64 dataAreaSize; 317: __int64 deviceSize; 318: LARGE_INTEGER offset; 319: DWORD dwResult; 320: 321: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_PREPARING); 322: 323: 324: if (!CheckRequirementsForNonSysInPlaceEnc (volParams->volumePath, FALSE)) 325: return ERR_DONT_REPORT; 326: 327: 328: header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE); 329: if (!header) 330: return ERR_OUTOFMEMORY; 331: 332: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 333: 334: deviceSize = GetDeviceSize (volParams->volumePath); 335: if (deviceSize < 0) 336: { 337: // Cannot determine the size of the partition 338: nStatus = ERR_PARAMETER_INCORRECT; 339: goto closing_seq; 340: } 341: 342: if (deviceSize < TC_NONSYS_INPLACE_ENC_MIN_VOL_SIZE) 343: { 344: ShowInPlaceEncErrMsgWAltSteps ("PARTITION_TOO_SMALL_FOR_NONSYS_INPLACE_ENC", TRUE); 345: nStatus = ERR_DONT_REPORT; 346: goto closing_seq; 347: } 348: 349: dataAreaSize = GetVolumeDataAreaSize (volParams->hiddenVol, deviceSize); 350: 351: strcpy ((char *)deviceName, volParams->volumePath); 352: ToUNICODE ((char *)deviceName); 353: 354: driveLetter = GetDiskDeviceDriveLetter (deviceName); 355: 356: 357: if (FakeDosNameForDevice (volParams->volumePath, dosDev, devName, FALSE) != 0) 358: { 359: nStatus = ERR_OS_ERROR; 360: goto closing_seq; 361: } 362: 363: if (IsDeviceMounted (devName)) 364: { 365: dev = OpenPartitionVolume (devName, 366: FALSE, // Do not require exclusive access (must be FALSE; otherwise, it will not be possible to dismount the volume or obtain its properties and FSCTL_ALLOW_EXTENDED_DASD_IO will fail too) 367: TRUE, // Require shared access (must be TRUE; otherwise, it will not be possible to dismount the volume or obtain its properties and FSCTL_ALLOW_EXTENDED_DASD_IO will fail too) 368: FALSE, // Do not ask the user to confirm shared access (if exclusive fails) 369: FALSE, // Do not append alternative instructions how to encrypt the data (to applicable error messages) 370: FALSE); // Non-silent mode 371: 372: if (dev == INVALID_HANDLE_VALUE) 373: { 374: nStatus = ERR_DONT_REPORT; 375: goto closing_seq; 376: } 377: } 378: else 379: { 380: // The volume is not mounted so we can't work with the filesystem. 381: Error ("ONLY_MOUNTED_VOL_SUPPORTED_FOR_NONSYS_INPLACE_ENC"); 382: nStatus = ERR_DONT_REPORT; 383: goto closing_seq; 384: } 385: 386: 387: /* Gain "raw" access to the partition (the NTFS driver guards hidden sectors). */ 388: 389: if (!DeviceIoControl (dev, 390: FSCTL_ALLOW_EXTENDED_DASD_IO, 391: NULL, 392: 0, 393: NULL, 394: 0, 395: &dwResult, 396: NULL)) 397: { 398: handleWin32Error (MainDlg); 399: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE); 400: nStatus = ERR_DONT_REPORT; 401: goto closing_seq; 402: } 403: 404: 405: 406: /* Shrink the filesystem */ 407: 408: int64 totalClusterCount; 409: DWORD bytesPerCluster; 410: 411: sizeToShrinkTo = NewFileSysSizeAfterShrink (dev, volParams->volumePath, &totalClusterCount, &bytesPerCluster, FALSE); 412: 413: if (sizeToShrinkTo == -1) 414: { 415: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE); 416: nStatus = ERR_DONT_REPORT; 417: goto closing_seq; 418: } 419: 420: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_RESIZING); 421: 422: memset (&shrinkVolInfo, 0, sizeof (shrinkVolInfo)); 423: 424: shrinkVolInfo.ShrinkRequestType = ShrinkPrepare; 425: shrinkVolInfo.NewNumberOfSectors = sizeToShrinkTo; 426: 427: if (!DeviceIoControl (dev, 428: FSCTL_SHRINK_VOLUME, 429: (LPVOID) &shrinkVolInfo, 430: sizeof (shrinkVolInfo), 431: NULL, 432: 0, 433: &dwResult, 434: NULL)) 435: { 436: handleWin32Error (MainDlg); 437: ShowInPlaceEncErrMsgWAltSteps ("CANNOT_RESIZE_FILESYS", TRUE); 438: nStatus = ERR_DONT_REPORT; 439: goto closing_seq; 440: } 441: 442: BOOL clustersMovedBeforeVolumeEnd = FALSE; 443: 444: while (true) 445: { 446: shrinkVolInfo.ShrinkRequestType = ShrinkCommit; 447: shrinkVolInfo.NewNumberOfSectors = 0; 448: 449: if (!DeviceIoControl (dev, FSCTL_SHRINK_VOLUME, &shrinkVolInfo, sizeof (shrinkVolInfo), NULL, 0, &dwResult, NULL)) 450: { 451: // If there are any occupied clusters beyond the new desired end of the volume, the call fails with 452: // ERROR_ACCESS_DENIED (STATUS_ALREADY_COMMITTED). 453: if (GetLastError () == ERROR_ACCESS_DENIED) 454: { 455: if (!clustersMovedBeforeVolumeEnd) 456: { 457: if (MoveClustersBeforeThreshold (dev, deviceName, totalClusterCount - (bytesPerCluster > TC_TOTAL_VOLUME_HEADERS_SIZE ? 1 : TC_TOTAL_VOLUME_HEADERS_SIZE / bytesPerCluster))) 458: { 459: clustersMovedBeforeVolumeEnd = TRUE; 460: continue; 461: } 462: 463: handleWin32Error (MainDlg); 464: } 465: } 466: else 467: handleWin32Error (MainDlg); 468: 469: ShowInPlaceEncErrMsgWAltSteps ("CANNOT_RESIZE_FILESYS", TRUE); 470: nStatus = ERR_DONT_REPORT; 471: goto closing_seq; 472: } 473: 474: break; 475: } 476: 477: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_PREPARING); 478: 479: 480: /* Gain exclusive access to the volume */ 481: 482: nStatus = DismountFileSystem (dev, 483: driveLetter, 484: TRUE, 485: TRUE, 486: FALSE); 487: 488: if (nStatus != ERR_SUCCESS) 489: { 490: nStatus = ERR_DONT_REPORT; 491: goto closing_seq; 492: } 493: 494: 495: 496: /* Create header backup on the partition. Until the volume is fully encrypted, the backup header will provide 497: us with the master key, encrypted range, and other data for pause/resume operations. We cannot create the 498: primary header until the entire partition is encrypted (because we encrypt backwards and the primary header 499: area is occuppied by data until the very end of the process). */ 500: 501: // Prepare the backup header 1.1.1.2 root 502: for (int wipePass = 0; wipePass < (wipeAlgorithm == TC_WIPE_NONE ? 1 : PRAND_DISK_WIPE_PASSES); wipePass++) 503: { 504: nStatus = CreateVolumeHeaderInMemory (FALSE, 505: header, 506: volParams->ea, 507: FIRST_MODE_OF_OPERATION_ID, 508: volParams->password, 509: volParams->pkcs5, 510: wipePass == 0 ? NULL : (char *) cryptoInfo->master_keydata, 511: &cryptoInfo, 512: dataAreaSize, 513: 0, 514: TC_VOLUME_DATA_OFFSET + dataAreaSize, // Start of the encrypted area = the first byte of the backup heeader (encrypting from the end) 515: 0, // No data is encrypted yet 516: 0, 517: volParams->headerFlags | TC_HEADER_FLAG_NONSYS_INPLACE_ENC, 1.1.1.6 ! root 518: volParams->sectorSize, 1.1.1.2 root 519: wipeAlgorithm == TC_WIPE_NONE ? FALSE : (wipePass < PRAND_DISK_WIPE_PASSES - 1)); 1.1 root 520: 1.1.1.2 root 521: if (nStatus != 0) 522: goto closing_seq; 1.1 root 523: 1.1.1.2 root 524: offset.QuadPart = TC_VOLUME_DATA_OFFSET + dataAreaSize; 1.1 root 525: 1.1.1.2 root 526: if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) 527: { 528: nStatus = ERR_OS_ERROR; 529: goto closing_seq; 530: } 1.1 root 531: 1.1.1.2 root 532: // Write the backup header to the partition 1.1.1.6 ! root 533: if (!WriteEffectiveVolumeHeader (TRUE, dev, (byte *) header)) 1.1.1.2 root 534: { 535: nStatus = ERR_OS_ERROR; 536: goto closing_seq; 537: } 1.1 root 538: 1.1.1.2 root 539: // Fill the reserved sectors of the backup header area with random data 540: nStatus = WriteRandomDataToReservedHeaderAreas (dev, cryptoInfo, dataAreaSize, FALSE, TRUE); 1.1 root 541: 1.1.1.2 root 542: if (nStatus != ERR_SUCCESS) 543: goto closing_seq; 544: } 1.1 root 545: 546: 547: /* Now we will try to decrypt the backup header to verify it has been correctly written. */ 548: 549: nStatus = OpenBackupHeader (dev, volParams->volumePath, volParams->password, &cryptoInfo2, NULL, deviceSize); 550: 551: if (nStatus != ERR_SUCCESS 552: || cryptoInfo->EncryptedAreaStart.Value != cryptoInfo2->EncryptedAreaStart.Value 553: || cryptoInfo2->EncryptedAreaStart.Value == 0) 554: { 555: if (nStatus == ERR_SUCCESS) 556: nStatus = ERR_PARAMETER_INCORRECT; 557: 558: goto closing_seq; 559: } 560: 561: // The backup header is valid so we know we should be able to safely resume in-place encryption 562: // of this partition even if the system/app crashes. 563: 564: 565: 566: /* Conceal the NTFS filesystem (by performing an easy-to-undo modification). This will prevent Windows 567: and apps from interfering with the volume until it has been fully encrypted. */ 568: 569: nStatus = ConcealNTFS (dev); 570: 571: if (nStatus != ERR_SUCCESS) 572: goto closing_seq; 573: 574: 575: 576: // /* If a drive letter is assigned to the device, remove it (so that users do not try to open it, which 577: //would cause Windows to ask them if they want to format the volume and other dangerous things). */ 578: 579: //if (driveLetter >= 0) 580: //{ 581: // char rootPath[] = { driveLetter + 'A', ':', '\\', 0 }; 582: 583: // // Try to remove the assigned drive letter 584: // if (DeleteVolumeMountPoint (rootPath)) 585: // driveLetter = -1; 586: //} 587: 588: 589: 590: /* Update config files and app data */ 591: 592: // In the config file, increase the number of partitions where in-place encryption is in progress 593: 594: SaveNonSysInPlaceEncSettings (1, wipeAlgorithm); 595: 596: 597: // Add the wizard to the system startup sequence if appropriate 598: 599: if (!IsNonInstallMode ()) 600: ManageStartupSeqWiz (FALSE, "/prinplace"); 601: 602: 603: nStatus = ERR_SUCCESS; 604: 605: 606: closing_seq: 607: 608: dwError = GetLastError(); 609: 610: if (cryptoInfo != NULL) 611: { 612: crypto_close (cryptoInfo); 613: cryptoInfo = NULL; 614: } 615: 616: if (cryptoInfo2 != NULL) 617: { 618: crypto_close (cryptoInfo2); 619: cryptoInfo2 = NULL; 620: } 621: 622: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 623: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 624: TCfree (header); 625: 626: if (dosDev[0]) 627: RemoveFakeDosName (volParams->volumePath, dosDev); 628: 629: *outHandle = dev; 630: 631: if (nStatus != ERR_SUCCESS) 632: SetLastError (dwError); 633: 634: return nStatus; 635: } 636: 637: 638: int EncryptPartitionInPlaceResume (HANDLE dev, 639: volatile FORMAT_VOL_PARAMETERS *volParams, 640: WipeAlgorithmId wipeAlgorithm, 641: volatile BOOL *bTryToCorrectReadErrors) 642: { 643: PCRYPTO_INFO masterCryptoInfo = NULL, headerCryptoInfo = NULL, tmpCryptoInfo = NULL; 644: UINT64_STRUCT unitNo; 645: char *buf = NULL, *header = NULL; 646: byte *wipeBuffer = NULL; 647: byte wipeRandChars [TC_WIPE_RAND_CHAR_COUNT]; 648: byte wipeRandCharsUpdate [TC_WIPE_RAND_CHAR_COUNT]; 649: char dosDev[TC_MAX_PATH] = {0}; 650: char devName[MAX_PATH] = {0}; 651: WCHAR deviceName[MAX_PATH]; 652: int nStatus = ERR_SUCCESS; 653: __int64 deviceSize; 654: uint64 remainingBytes, lastHeaderUpdateDistance = 0, zeroedSectorCount = 0; 655: uint32 workChunkSize; 656: DWORD dwError, dwResult; 657: BOOL bPause = FALSE, bEncryptedAreaSizeChanged = FALSE; 658: LARGE_INTEGER offset; 659: int sectorSize; 660: int i; 661: DWORD n; 662: char *devicePath = volParams->volumePath; 663: Password *password = volParams->password; 664: DISK_GEOMETRY driveGeometry; 665: 666: 667: bInPlaceEncNonSysResumed = TRUE; 668: 669: buf = (char *) TCalloc (TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE); 670: if (!buf) 671: { 672: nStatus = ERR_OUTOFMEMORY; 673: goto closing_seq; 674: } 675: 676: header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE); 677: if (!header) 678: { 679: nStatus = ERR_OUTOFMEMORY; 680: goto closing_seq; 681: } 682: 683: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 684: 685: if (wipeAlgorithm != TC_WIPE_NONE) 686: { 687: wipeBuffer = (byte *) TCalloc (TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE); 688: if (!wipeBuffer) 689: { 690: nStatus = ERR_OUTOFMEMORY; 691: goto closing_seq; 692: } 693: } 694: 695: headerCryptoInfo = crypto_open(); 696: 697: if (headerCryptoInfo == NULL) 698: { 699: nStatus = ERR_OUTOFMEMORY; 700: goto closing_seq; 701: } 702: 703: deviceSize = GetDeviceSize (devicePath); 704: if (deviceSize < 0) 705: { 706: // Cannot determine the size of the partition 707: nStatus = ERR_OS_ERROR; 708: goto closing_seq; 709: } 710: 711: if (dev == INVALID_HANDLE_VALUE) 712: { 713: strcpy ((char *)deviceName, devicePath); 714: ToUNICODE ((char *)deviceName); 715: 716: if (FakeDosNameForDevice (devicePath, dosDev, devName, FALSE) != 0) 717: { 718: nStatus = ERR_OS_ERROR; 719: goto closing_seq; 720: } 721: 722: dev = OpenPartitionVolume (devName, 723: FALSE, // Do not require exclusive access 724: FALSE, // Do not require shared access 725: TRUE, // Ask the user to confirm shared access (if exclusive fails) 726: FALSE, // Do not append alternative instructions how to encrypt the data (to applicable error messages) 727: FALSE); // Non-silent mode 728: 729: if (dev == INVALID_HANDLE_VALUE) 730: { 731: nStatus = ERR_DONT_REPORT; 732: goto closing_seq; 733: } 734: } 735: 736: // This should never be needed, but is still performed for extra safety (without checking the result) 737: DeviceIoControl (dev, 738: FSCTL_ALLOW_EXTENDED_DASD_IO, 739: NULL, 740: 0, 741: NULL, 742: 0, 743: &dwResult, 744: NULL); 745: 746: 747: if (!DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &driveGeometry, sizeof (driveGeometry), &dwResult, NULL)) 748: { 749: nStatus = ERR_OS_ERROR; 750: goto closing_seq; 751: } 752: 753: sectorSize = driveGeometry.BytesPerSector; 754: 755: 756: nStatus = OpenBackupHeader (dev, devicePath, password, &masterCryptoInfo, headerCryptoInfo, deviceSize); 757: 758: if (nStatus != ERR_SUCCESS) 759: goto closing_seq; 760: 761: 762: 763: remainingBytes = masterCryptoInfo->VolumeSize.Value - masterCryptoInfo->EncryptedAreaLength.Value; 764: 765: lastHeaderUpdateDistance = 0; 766: 767: 1.1.1.6 ! root 768: ExportProgressStats (masterCryptoInfo->EncryptedAreaLength.Value, masterCryptoInfo->VolumeSize.Value); 1.1 root 769: 770: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_ENCRYPTING); 771: 772: bFirstNonSysInPlaceEncResumeDone = TRUE; 773: 774: 775: /* The in-place encryption core */ 776: 777: while (remainingBytes > 0) 778: { 779: workChunkSize = (uint32) min (remainingBytes, TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE); 780: 781: if (workChunkSize % ENCRYPTION_DATA_UNIT_SIZE != 0) 782: { 783: nStatus = ERR_PARAMETER_INCORRECT; 784: goto closing_seq; 785: } 786: 787: unitNo.Value = (remainingBytes - workChunkSize + TC_VOLUME_DATA_OFFSET) / ENCRYPTION_DATA_UNIT_SIZE; 788: 789: 790: // Read the plaintext into RAM 791: 792: inplace_enc_read: 793: 794: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize - TC_VOLUME_DATA_OFFSET; 795: 796: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) 797: { 798: nStatus = ERR_OS_ERROR; 799: goto closing_seq; 800: } 801: 802: if (ReadFile (dev, buf, workChunkSize, &n, NULL) == 0) 803: { 804: // Read error 805: 806: DWORD dwTmpErr = GetLastError (); 807: 1.1.1.2 root 808: if (IsDiskReadError (dwTmpErr) && !bVolTransformThreadCancel) 1.1 root 809: { 810: // Physical defect or data corruption 811: 812: if (!*bTryToCorrectReadErrors) 813: { 814: *bTryToCorrectReadErrors = (AskWarnYesNo ("ENABLE_BAD_SECTOR_ZEROING") == IDYES); 815: } 816: 817: if (*bTryToCorrectReadErrors) 818: { 819: // Try to correct the read errors physically 820: 821: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize - TC_VOLUME_DATA_OFFSET; 822: 823: nStatus = ZeroUnreadableSectors (dev, offset, workChunkSize, sectorSize, &zeroedSectorCount); 824: 825: if (nStatus != ERR_SUCCESS) 826: { 827: // Due to write errors, we can't correct the read errors 828: nStatus = ERR_OS_ERROR; 829: goto closing_seq; 830: } 831: 832: goto inplace_enc_read; 833: } 834: } 835: 836: SetLastError (dwTmpErr); // Preserve the original error code 837: 838: nStatus = ERR_OS_ERROR; 839: goto closing_seq; 840: } 841: 842: if (remainingBytes - workChunkSize < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE) 843: { 844: // We reached the inital portion of the filesystem, which we had concealed (in order to prevent 845: // Windows from interfering with the volume). Now we need to undo that modification. 846: 847: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE - (remainingBytes - workChunkSize); i++) 848: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT; 849: } 850: 851: 852: // Encrypt the plaintext in RAM 853: 854: EncryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo); 855: 856: 857: // If enabled, wipe the area to which we will write the ciphertext 858: 859: if (wipeAlgorithm != TC_WIPE_NONE) 860: { 861: byte wipePass; 862: 863: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize; 864: 865: for (wipePass = 1; wipePass <= GetWipePassCount (wipeAlgorithm); ++wipePass) 866: { 867: if (!WipeBuffer (wipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, workChunkSize)) 868: { 869: ULONG i; 870: for (i = 0; i < workChunkSize; ++i) 871: { 872: wipeBuffer[i] = buf[i] + wipePass; 873: } 874: 875: EncryptDataUnits (wipeBuffer, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo); 876: memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate)); 877: } 878: 879: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 880: || WriteFile (dev, wipeBuffer, workChunkSize, &n, NULL) == 0) 881: { 882: // Write error 883: dwError = GetLastError(); 884: 885: // Undo failed write operation 886: if (workChunkSize > TC_VOLUME_DATA_OFFSET && SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) 887: { 888: DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo); 889: WriteFile (dev, buf + TC_VOLUME_DATA_OFFSET, workChunkSize - TC_VOLUME_DATA_OFFSET, &n, NULL); 890: } 891: 892: SetLastError (dwError); 893: nStatus = ERR_OS_ERROR; 894: goto closing_seq; 895: } 896: } 897: 898: memcpy (wipeRandChars, wipeRandCharsUpdate, sizeof (wipeRandCharsUpdate)); 899: } 900: 901: 902: // Write the ciphertext 903: 904: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize; 905: 906: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) 907: { 908: nStatus = ERR_OS_ERROR; 909: goto closing_seq; 910: } 911: 912: if (WriteFile (dev, buf, workChunkSize, &n, NULL) == 0) 913: { 914: // Write error 915: dwError = GetLastError(); 916: 917: // Undo failed write operation 918: if (workChunkSize > TC_VOLUME_DATA_OFFSET && SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) 919: { 920: DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo); 921: WriteFile (dev, buf + TC_VOLUME_DATA_OFFSET, workChunkSize - TC_VOLUME_DATA_OFFSET, &n, NULL); 922: } 923: 924: SetLastError (dwError); 925: nStatus = ERR_OS_ERROR; 926: goto closing_seq; 927: } 928: 929: 930: masterCryptoInfo->EncryptedAreaStart.Value -= workChunkSize; 931: masterCryptoInfo->EncryptedAreaLength.Value += workChunkSize; 932: 933: remainingBytes -= workChunkSize; 934: lastHeaderUpdateDistance += workChunkSize; 935: 936: bEncryptedAreaSizeChanged = TRUE; 937: 938: if (lastHeaderUpdateDistance >= TC_NONSYS_INPLACE_ENC_HEADER_UPDATE_INTERVAL) 939: { 940: nStatus = FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize); 941: 942: if (nStatus != ERR_SUCCESS) 943: goto closing_seq; 944: 945: lastHeaderUpdateDistance = 0; 946: } 947: 1.1.1.6 ! root 948: ExportProgressStats (masterCryptoInfo->EncryptedAreaLength.Value, masterCryptoInfo->VolumeSize.Value); 1.1 root 949: 950: if (bVolTransformThreadCancel) 951: { 952: bPause = TRUE; 953: break; 954: } 955: } 956: 957: nStatus = FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize); 958: 959: 960: if (nStatus != ERR_SUCCESS) 961: goto closing_seq; 962: 963: 964: if (!bPause) 965: { 966: /* The data area has been fully encrypted; create and write the primary volume header */ 967: 968: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_FINALIZING); 969: 1.1.1.2 root 970: for (int wipePass = 0; wipePass < (wipeAlgorithm == TC_WIPE_NONE ? 1 : PRAND_DISK_WIPE_PASSES); wipePass++) 971: { 972: nStatus = CreateVolumeHeaderInMemory (FALSE, 973: header, 974: headerCryptoInfo->ea, 975: headerCryptoInfo->mode, 976: password, 977: masterCryptoInfo->pkcs5, 978: (char *) masterCryptoInfo->master_keydata, 979: &tmpCryptoInfo, 980: masterCryptoInfo->VolumeSize.Value, 981: 0, 982: masterCryptoInfo->EncryptedAreaStart.Value, 983: masterCryptoInfo->EncryptedAreaLength.Value, 984: masterCryptoInfo->RequiredProgramVersion, 985: masterCryptoInfo->HeaderFlags | TC_HEADER_FLAG_NONSYS_INPLACE_ENC, 1.1.1.6 ! root 986: masterCryptoInfo->SectorSize, 1.1.1.2 root 987: wipeAlgorithm == TC_WIPE_NONE ? FALSE : (wipePass < PRAND_DISK_WIPE_PASSES - 1)); 1.1 root 988: 1.1.1.2 root 989: if (nStatus != ERR_SUCCESS) 990: goto closing_seq; 1.1 root 991: 992: 1.1.1.2 root 993: offset.QuadPart = TC_VOLUME_HEADER_OFFSET; 1.1 root 994: 1.1.1.2 root 995: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 1.1.1.6 ! root 996: || !WriteEffectiveVolumeHeader (TRUE, dev, (byte *) header)) 1.1.1.2 root 997: { 998: nStatus = ERR_OS_ERROR; 999: goto closing_seq; 1000: } 1.1 root 1001: 1.1.1.2 root 1002: // Fill the reserved sectors of the header area with random data 1003: nStatus = WriteRandomDataToReservedHeaderAreas (dev, headerCryptoInfo, masterCryptoInfo->VolumeSize.Value, TRUE, FALSE); 1.1 root 1004: 1.1.1.2 root 1005: if (nStatus != ERR_SUCCESS) 1006: goto closing_seq; 1007: } 1.1 root 1008: 1009: // Update the configuration files 1010: 1011: SaveNonSysInPlaceEncSettings (-1, wipeAlgorithm); 1012: 1013: 1014: 1015: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_FINISHED); 1016: 1017: nStatus = ERR_SUCCESS; 1018: } 1019: else 1020: { 1021: // The process has been paused by the user or aborted by the wizard (e.g. on app exit) 1022: 1023: nStatus = ERR_USER_ABORT; 1024: 1025: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_PAUSED); 1026: } 1027: 1028: 1029: closing_seq: 1030: 1031: dwError = GetLastError(); 1032: 1033: if (bEncryptedAreaSizeChanged 1034: && dev != INVALID_HANDLE_VALUE 1035: && masterCryptoInfo != NULL 1036: && headerCryptoInfo != NULL 1037: && deviceSize > 0) 1038: { 1039: // Execution of the core loop may have been interrupted due to an error or user action without updating the header 1040: FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize); 1041: } 1042: 1043: if (masterCryptoInfo != NULL) 1044: { 1045: crypto_close (masterCryptoInfo); 1046: masterCryptoInfo = NULL; 1047: } 1048: 1049: if (headerCryptoInfo != NULL) 1050: { 1051: crypto_close (headerCryptoInfo); 1052: headerCryptoInfo = NULL; 1053: } 1054: 1055: if (tmpCryptoInfo != NULL) 1056: { 1057: crypto_close (tmpCryptoInfo); 1058: tmpCryptoInfo = NULL; 1059: } 1060: 1061: if (dosDev[0]) 1062: RemoveFakeDosName (devicePath, dosDev); 1063: 1064: if (dev != INVALID_HANDLE_VALUE) 1065: { 1066: CloseHandle (dev); 1067: dev = INVALID_HANDLE_VALUE; 1068: } 1069: 1070: if (buf != NULL) 1071: TCfree (buf); 1072: 1073: if (header != NULL) 1074: { 1075: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 1076: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 1077: TCfree (header); 1078: } 1079: 1080: if (wipeBuffer != NULL) 1081: TCfree (wipeBuffer); 1082: 1083: if (zeroedSectorCount > 0) 1084: { 1085: wchar_t msg[30000] = {0}; 1086: wchar_t sizeStr[500] = {0}; 1087: 1088: GetSizeString (zeroedSectorCount * sectorSize, sizeStr); 1089: 1090: wsprintfW (msg, 1091: GetString ("ZEROED_BAD_SECTOR_COUNT"), 1092: zeroedSectorCount, 1093: sizeStr); 1094: 1095: WarningDirect (msg); 1096: } 1097: 1098: if (nStatus != ERR_SUCCESS && nStatus != ERR_USER_ABORT) 1099: SetLastError (dwError); 1100: 1101: return nStatus; 1102: } 1103: 1104: 1105: int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_INFO *masterCryptoInfo, __int64 deviceSize) 1106: { 1107: LARGE_INTEGER offset; 1108: DWORD n; 1109: int nStatus = ERR_SUCCESS; 1110: byte *header; 1111: DWORD dwError; 1112: uint32 headerCrc32; 1113: byte *fieldPos; 1114: 1115: header = (byte *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE); 1116: 1117: if (!header) 1118: return ERR_OUTOFMEMORY; 1119: 1120: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 1121: 1122: 1123: fieldPos = (byte *) header + TC_HEADER_OFFSET_ENCRYPTED_AREA_START; 1124: 1125: offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE; 1126: 1127: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 1.1.1.6 ! root 1128: || !ReadEffectiveVolumeHeader (TRUE, dev, header, &n) || n < TC_VOLUME_HEADER_EFFECTIVE_SIZE) 1.1 root 1129: { 1130: nStatus = ERR_OS_ERROR; 1131: goto closing_seq; 1132: } 1133: 1134: 1135: DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo); 1136: 1137: if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545) 1138: { 1139: nStatus = ERR_PARAMETER_INCORRECT; 1140: goto closing_seq; 1141: } 1142: 1143: mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaStart.Value)); 1144: mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaLength.Value)); 1145: 1146: 1147: headerCrc32 = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC); 1148: fieldPos = (byte *) header + TC_HEADER_OFFSET_HEADER_CRC; 1149: mputLong (fieldPos, headerCrc32); 1150: 1151: EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo); 1152: 1153: 1154: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 1.1.1.6 ! root 1155: || !WriteEffectiveVolumeHeader (TRUE, dev, header)) 1.1 root 1156: { 1157: nStatus = ERR_OS_ERROR; 1158: goto closing_seq; 1159: } 1160: 1161: 1162: closing_seq: 1163: 1164: dwError = GetLastError(); 1165: 1166: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 1167: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 1168: TCfree (header); 1169: 1170: if (nStatus != ERR_SUCCESS) 1171: SetLastError (dwError); 1172: 1173: return nStatus; 1174: } 1175: 1176: 1177: static HANDLE OpenPartitionVolume (const char *devName, 1178: BOOL bExclusiveRequired, 1179: BOOL bSharedRequired, 1180: BOOL bSharedRequiresConfirmation, 1181: BOOL bShowAlternativeSteps, 1182: BOOL bSilent) 1183: { 1184: HANDLE dev = INVALID_HANDLE_VALUE; 1185: int retryCount = 0; 1186: 1187: if (bExclusiveRequired) 1188: bSharedRequired = FALSE; 1189: 1190: if (bExclusiveRequired || !bSharedRequired) 1191: { 1192: // Exclusive access 1193: // Note that when exclusive access is denied, it is worth retrying (usually succeeds after a few tries). 1194: while (dev == INVALID_HANDLE_VALUE && retryCount++ < EXCL_ACCESS_MAX_AUTO_RETRIES) 1195: { 1196: dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL); 1197: 1198: if (retryCount > 1) 1199: Sleep (EXCL_ACCESS_AUTO_RETRY_DELAY); 1200: } 1201: } 1202: 1203: if (dev == INVALID_HANDLE_VALUE) 1204: { 1205: if (bExclusiveRequired) 1206: { 1207: if (!bSilent) 1208: { 1209: handleWin32Error (MainDlg); 1210: 1211: if (bShowAlternativeSteps) 1212: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE); 1213: else 1214: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL"); 1215: } 1216: return INVALID_HANDLE_VALUE; 1217: } 1218: 1219: // Shared mode 1220: dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL); 1221: if (dev != INVALID_HANDLE_VALUE) 1222: { 1223: if (bSharedRequiresConfirmation 1224: && !bSilent 1225: && AskWarnNoYes ("DEVICE_IN_USE_INPLACE_ENC") == IDNO) 1226: { 1227: CloseHandle (dev); 1228: return INVALID_HANDLE_VALUE; 1229: } 1230: } 1231: else 1232: { 1233: if (!bSilent) 1234: { 1235: handleWin32Error (MainDlg); 1236: 1237: if (bShowAlternativeSteps) 1238: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE); 1239: else 1240: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL"); 1241: } 1242: return INVALID_HANDLE_VALUE; 1243: } 1244: } 1245: 1246: return dev; 1247: } 1248: 1249: 1250: static int DismountFileSystem (HANDLE dev, 1251: int driveLetter, 1252: BOOL bForcedAllowed, 1253: BOOL bForcedRequiresConfirmation, 1254: BOOL bSilent) 1255: { 1256: int attempt; 1257: BOOL bResult; 1258: DWORD dwResult; 1259: 1260: CloseVolumeExplorerWindows (MainDlg, driveLetter); 1261: 1262: attempt = UNMOUNT_MAX_AUTO_RETRIES * 10; 1263: 1264: while (!(bResult = DeviceIoControl (dev, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL)) 1265: && attempt > 0) 1266: { 1267: Sleep (UNMOUNT_AUTO_RETRY_DELAY); 1268: attempt--; 1269: } 1270: 1271: if (!bResult) 1272: { 1273: if (!bForcedAllowed) 1274: { 1275: if (!bSilent) 1276: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS", TRUE); 1277: 1278: return ERR_DONT_REPORT; 1279: } 1280: 1281: if (bForcedRequiresConfirmation 1282: && !bSilent 1283: && AskWarnYesNo ("VOL_LOCK_FAILED_OFFER_FORCED_DISMOUNT") == IDNO) 1284: { 1285: return ERR_DONT_REPORT; 1286: } 1287: } 1288: 1289: // Dismount the volume 1290: 1291: attempt = UNMOUNT_MAX_AUTO_RETRIES * 10; 1292: 1293: while (!(bResult = DeviceIoControl (dev, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL)) 1294: && attempt > 0) 1295: { 1296: Sleep (UNMOUNT_AUTO_RETRY_DELAY); 1297: attempt--; 1298: } 1299: 1300: if (!bResult) 1301: { 1302: if (!bSilent) 1303: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS", TRUE); 1304: 1305: return ERR_DONT_REPORT; 1306: } 1307: 1308: return ERR_SUCCESS; 1309: } 1310: 1311: 1312: // Easy-to-undo modification applied to conceal the NTFS filesystem (to prevent Windows and apps from 1313: // interfering with it until the volume has been fully encrypted). Note that this function will precisely 1314: // undo any modifications it made to the filesystem automatically if an error occurs when writing (including 1315: // physical drive defects). 1316: static int ConcealNTFS (HANDLE dev) 1317: { 1318: char buf [TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE]; 1319: DWORD nbrBytesProcessed, nbrBytesProcessed2; 1320: int i; 1321: LARGE_INTEGER offset; 1322: DWORD dwError; 1323: 1324: offset.QuadPart = 0; 1325: 1326: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) 1327: return ERR_OS_ERROR; 1328: 1329: if (ReadFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0) 1330: return ERR_OS_ERROR; 1331: 1332: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE; i++) 1333: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT; 1334: 1335: offset.QuadPart = 0; 1336: 1337: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) 1338: return ERR_OS_ERROR; 1339: 1340: if (WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0) 1341: { 1342: // One or more of the sectors is/are probably damaged and cause write errors. 1343: // We must undo the modifications we made. 1344: 1345: dwError = GetLastError(); 1346: 1347: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE; i++) 1348: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT; 1349: 1350: offset.QuadPart = 0; 1351: 1352: do 1353: { 1354: Sleep (1); 1355: } 1356: while (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 1357: || WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed2, NULL) == 0); 1358: 1359: SetLastError (dwError); 1360: 1361: return ERR_OS_ERROR; 1362: } 1363: 1364: return ERR_SUCCESS; 1365: } 1366: 1367: 1368: void ShowInPlaceEncErrMsgWAltSteps (char *iniStrId, BOOL bErr) 1369: { 1370: wchar_t msg[30000]; 1371: 1372: wcscpy (msg, GetString (iniStrId)); 1373: 1374: wcscat (msg, L"\n\n\n"); 1375: wcscat (msg, GetString ("INPLACE_ENC_ALTERNATIVE_STEPS")); 1376: 1377: if (bErr) 1378: ErrorDirect (msg); 1379: else 1380: WarningDirect (msg); 1381: } 1382: 1383: 1.1.1.6 ! root 1384: static void ExportProgressStats (__int64 bytesDone, __int64 totalSize) 1.1 root 1385: { 1386: NonSysInplaceEncBytesDone = bytesDone; 1.1.1.6 ! root 1387: NonSysInplaceEncTotalSize = totalSize; 1.1 root 1388: } 1389: 1390: 1391: void SetNonSysInplaceEncUIStatus (int nonSysInplaceEncStatus) 1392: { 1393: NonSysInplaceEncStatus = nonSysInplaceEncStatus; 1394: } 1395: 1396: 1397: BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId newWipeAlgorithm) 1398: { 1399: int count; 1400: char str[32]; 1401: WipeAlgorithmId savedWipeAlgorithm = TC_WIPE_NONE; 1402: 1403: if (delta == 0) 1404: return TRUE; 1405: 1406: count = LoadNonSysInPlaceEncSettings (&savedWipeAlgorithm) + delta; 1407: 1408: if (count < 1) 1409: { 1.1.1.2 root 1410: RemoveNonSysInPlaceEncNotifications(); 1.1 root 1411: return TRUE; 1412: } 1413: else 1414: { 1415: if (newWipeAlgorithm != TC_WIPE_NONE) 1416: { 1417: sprintf (str, "%d", (int) newWipeAlgorithm); 1418: 1419: SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE), strlen(str), FALSE); 1420: } 1421: else if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE))) 1422: { 1423: remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)); 1424: } 1425: 1426: sprintf (str, "%d", count); 1427: 1428: return SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC), strlen(str), FALSE); 1429: } 1430: } 1431: 1432: 1433: // Repairs damaged sectors (i.e. those with read errors) by zeroing them. 1434: // Note that this operating fails if there are any write errors. 1435: int ZeroUnreadableSectors (HANDLE dev, LARGE_INTEGER startOffset, int64 size, int sectorSize, uint64 *zeroedSectorCount) 1436: { 1437: int nStatus; 1438: DWORD n; 1439: int64 sectorCount; 1440: LARGE_INTEGER workOffset; 1441: byte *sectorBuffer = NULL; 1442: DWORD dwError; 1443: 1444: workOffset.QuadPart = startOffset.QuadPart; 1445: 1446: sectorBuffer = (byte *) TCalloc (sectorSize); 1447: 1448: if (!sectorBuffer) 1449: return ERR_OUTOFMEMORY; 1450: 1451: if (SetFilePointerEx (dev, startOffset, NULL, FILE_BEGIN) == 0) 1452: { 1453: nStatus = ERR_OS_ERROR; 1454: goto closing_seq; 1455: } 1456: 1457: 1458: for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount) 1459: { 1460: if (ReadFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0) 1461: { 1462: memset (sectorBuffer, 0, sectorSize); 1463: 1464: if (SetFilePointerEx (dev, workOffset, NULL, FILE_BEGIN) == 0) 1465: { 1466: nStatus = ERR_OS_ERROR; 1467: goto closing_seq; 1468: } 1469: 1470: if (WriteFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0) 1471: { 1472: nStatus = ERR_OS_ERROR; 1473: goto closing_seq; 1474: } 1475: ++(*zeroedSectorCount); 1476: } 1477: 1478: workOffset.QuadPart += n; 1479: } 1480: 1481: nStatus = ERR_SUCCESS; 1482: 1483: closing_seq: 1484: 1485: dwError = GetLastError(); 1486: 1487: if (sectorBuffer != NULL) 1488: TCfree (sectorBuffer); 1489: 1490: if (nStatus != ERR_SUCCESS) 1491: SetLastError (dwError); 1492: 1493: return nStatus; 1494: } 1495: 1496: 1497: static int OpenBackupHeader (HANDLE dev, const char *devicePath, Password *password, PCRYPTO_INFO *retMasterCryptoInfo, CRYPTO_INFO *headerCryptoInfo, __int64 deviceSize) 1498: { 1499: LARGE_INTEGER offset; 1500: DWORD n; 1501: int nStatus = ERR_SUCCESS; 1502: char *header; 1503: DWORD dwError; 1504: 1505: header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE); 1506: if (!header) 1507: return ERR_OUTOFMEMORY; 1508: 1509: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 1510: 1511: 1512: 1513: offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE; 1514: 1515: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 1.1.1.6 ! root 1516: || !ReadEffectiveVolumeHeader (TRUE, dev, (byte *) header, &n) || n < TC_VOLUME_HEADER_EFFECTIVE_SIZE) 1.1 root 1517: { 1518: nStatus = ERR_OS_ERROR; 1519: goto closing_seq; 1520: } 1521: 1522: 1523: nStatus = ReadVolumeHeader (FALSE, header, password, retMasterCryptoInfo, headerCryptoInfo); 1524: if (nStatus != ERR_SUCCESS) 1525: goto closing_seq; 1526: 1527: 1528: closing_seq: 1529: 1530: dwError = GetLastError(); 1531: 1532: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 1533: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); 1534: TCfree (header); 1535: 1536: dwError = GetLastError(); 1537: 1538: if (nStatus != ERR_SUCCESS) 1539: SetLastError (dwError); 1540: 1541: return nStatus; 1542: } 1543: 1544: 1545: static BOOL GetFreeClusterBeforeThreshold (HANDLE volumeHandle, int64 *freeCluster, int64 clusterThreshold) 1546: { 1547: const int bitmapSize = 65536; 1548: byte bitmapBuffer[bitmapSize + sizeof (VOLUME_BITMAP_BUFFER)]; 1549: VOLUME_BITMAP_BUFFER *bitmap = (VOLUME_BITMAP_BUFFER *) bitmapBuffer; 1550: STARTING_LCN_INPUT_BUFFER startLcn; 1551: startLcn.StartingLcn.QuadPart = 0; 1552: 1553: DWORD bytesReturned; 1554: while (DeviceIoControl (volumeHandle, FSCTL_GET_VOLUME_BITMAP, &startLcn, sizeof (startLcn), &bitmapBuffer, sizeof (bitmapBuffer), &bytesReturned, NULL) 1555: || GetLastError() == ERROR_MORE_DATA) 1556: { 1557: for (int64 bitmapIndex = 0; bitmapIndex < min (bitmapSize, (bitmap->BitmapSize.QuadPart / 8)); ++bitmapIndex) 1558: { 1559: if (bitmap->StartingLcn.QuadPart + bitmapIndex * 8 >= clusterThreshold) 1560: goto err; 1561: 1562: if (bitmap->Buffer[bitmapIndex] != 0xff) 1563: { 1564: for (int bit = 0; bit < 8; ++bit) 1565: { 1566: if ((bitmap->Buffer[bitmapIndex] & (1 << bit)) == 0) 1567: { 1568: *freeCluster = bitmap->StartingLcn.QuadPart + bitmapIndex * 8 + bit; 1569: 1570: if (*freeCluster >= clusterThreshold) 1571: goto err; 1572: 1573: return TRUE; 1574: } 1575: } 1576: } 1577: } 1578: 1579: startLcn.StartingLcn.QuadPart += min (bitmapSize * 8, bitmap->BitmapSize.QuadPart); 1580: } 1581: 1582: err: 1583: SetLastError (ERROR_DISK_FULL); 1584: return FALSE; 1585: } 1586: 1587: 1588: static BOOL MoveClustersBeforeThresholdInDir (HANDLE volumeHandle, const wstring &directory, int64 clusterThreshold) 1589: { 1590: WIN32_FIND_DATAW findData; 1591: 1592: HANDLE findHandle = FindFirstFileW (((directory.size() <= 3 ? L"" : L"\\\\?\\") + directory + L"\\*").c_str(), &findData); 1593: if (findHandle == INVALID_HANDLE_VALUE) 1594: return TRUE; // Error ignored 1595: 1596: finally_do_arg (HANDLE, findHandle, { FindClose (finally_arg); }); 1597: 1598: // Find all files and directories 1599: do 1600: { 1601: if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 1602: { 1603: wstring subDir = findData.cFileName; 1604: 1605: if (subDir == L"." || subDir == L"..") 1606: continue; 1607: 1608: if (!MoveClustersBeforeThresholdInDir (volumeHandle, directory + L"\\" + subDir, clusterThreshold)) 1609: return FALSE; 1610: } 1611: 1612: DWORD access = FILE_READ_ATTRIBUTES; 1613: 1614: if (findData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) 1615: access = FILE_READ_DATA; 1616: 1617: HANDLE fsObject = CreateFileW ((directory + L"\\" + findData.cFileName).c_str(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); 1618: if (fsObject == INVALID_HANDLE_VALUE) 1619: continue; 1620: 1621: finally_do_arg (HANDLE, fsObject, { CloseHandle (finally_arg); }); 1622: 1623: STARTING_VCN_INPUT_BUFFER startVcn; 1624: startVcn.StartingVcn.QuadPart = 0; 1625: RETRIEVAL_POINTERS_BUFFER retPointers; 1626: DWORD bytesReturned; 1627: 1628: // Find clusters allocated beyond the threshold 1629: while (DeviceIoControl (fsObject, FSCTL_GET_RETRIEVAL_POINTERS, &startVcn, sizeof (startVcn), &retPointers, sizeof (retPointers), &bytesReturned, NULL) 1630: || GetLastError() == ERROR_MORE_DATA) 1631: { 1632: if (retPointers.ExtentCount == 0) 1633: break; 1634: 1635: if (retPointers.Extents[0].Lcn.QuadPart != -1) 1636: { 1637: int64 extentStartCluster = retPointers.Extents[0].Lcn.QuadPart; 1638: int64 extentLen = retPointers.Extents[0].NextVcn.QuadPart - retPointers.StartingVcn.QuadPart; 1639: int64 extentEndCluster = extentStartCluster + extentLen - 1; 1640: 1641: if (extentEndCluster >= clusterThreshold) 1642: { 1643: // Move clusters before the threshold 1644: for (int64 movedCluster = max (extentStartCluster, clusterThreshold); movedCluster <= extentEndCluster; ++movedCluster) 1645: { 1646: for (int retry = 0; ; ++retry) 1647: { 1648: MOVE_FILE_DATA moveData; 1649: 1650: if (GetFreeClusterBeforeThreshold (volumeHandle, &moveData.StartingLcn.QuadPart, clusterThreshold)) 1651: { 1652: moveData.FileHandle = fsObject; 1653: moveData.StartingVcn.QuadPart = movedCluster - extentStartCluster + retPointers.StartingVcn.QuadPart; 1654: moveData.ClusterCount = 1; 1655: 1656: if (DeviceIoControl (volumeHandle, FSCTL_MOVE_FILE, &moveData, sizeof (moveData), NULL, 0, &bytesReturned, NULL)) 1657: break; 1658: } 1659: 1.1.1.2 root 1660: if (retry > 600) 1.1 root 1661: return FALSE; 1662: 1663: // There are possible race conditions as we work on a live filesystem 1664: Sleep (100); 1665: } 1666: } 1667: } 1668: } 1669: 1670: startVcn.StartingVcn = retPointers.Extents[0].NextVcn; 1671: } 1672: 1673: } while (FindNextFileW (findHandle, &findData)); 1674: 1675: return TRUE; 1676: } 1677: 1678: 1679: BOOL MoveClustersBeforeThreshold (HANDLE volumeHandle, PWSTR volumeDevicePath, int64 clusterThreshold) 1680: { 1681: int drive = GetDiskDeviceDriveLetter (volumeDevicePath); 1682: if (drive == -1) 1683: { 1684: SetLastError (ERROR_INVALID_PARAMETER); 1685: return FALSE; 1686: } 1687: 1688: wstring volumeRoot = L"X:"; 1.1.1.4 root 1689: volumeRoot[0] = L'A' + (wchar_t) drive; 1.1 root 1690: 1691: return MoveClustersBeforeThresholdInDir (volumeHandle, volumeRoot, clusterThreshold); 1692: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.