|
|
1.1 ! root 1: /* ! 2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved. ! 3: ! 4: Governed by the TrueCrypt License 2.6 the full text of which is contained ! 5: in the file License.txt included in TrueCrypt binary and source code ! 6: distribution packages. ! 7: */ ! 8: ! 9: ! 10: /* In this file, _WIN32_WINNT is defined as 0x0600 to make file shrink available (Vista ! 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 ! 120: && sscanf (devicePath, "\\Device\\Harddisk%d\\Partition%d", &partitionNumber, &driveNumber) != 2) ! 121: { ! 122: if (!silent) ! 123: Error ("INPLACE_ENC_INVALID_PATH"); ! 124: ! 125: return FALSE; ! 126: } ! 127: ! 128: if (driveNumber == 0) ! 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) ! 160: szRootPath[0] = driveLetterNo + 'A'; ! 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) ! 290: ShowInPlaceEncErrMsgWAltSteps ("ERR_UNSUPPORTED_SECTOR_SIZE_GENERIC", TRUE); ! 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 ! 502: nStatus = CreateVolumeHeaderInMemory (FALSE, ! 503: header, ! 504: volParams->ea, ! 505: FIRST_MODE_OF_OPERATION_ID, ! 506: volParams->password, ! 507: volParams->pkcs5, ! 508: NULL, ! 509: &cryptoInfo, ! 510: dataAreaSize, ! 511: 0, ! 512: TC_VOLUME_DATA_OFFSET + dataAreaSize, // Start of the encrypted area = the first byte of the backup heeader (encrypting from the end) ! 513: 0, // No data is encrypted yet ! 514: 0, ! 515: volParams->headerFlags | TC_HEADER_FLAG_NONSYS_INPLACE_ENC, ! 516: FALSE); ! 517: ! 518: if (nStatus != 0) ! 519: goto closing_seq; ! 520: ! 521: offset.QuadPart = TC_VOLUME_DATA_OFFSET + dataAreaSize; ! 522: ! 523: if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) ! 524: { ! 525: nStatus = ERR_OS_ERROR; ! 526: goto closing_seq; ! 527: } ! 528: ! 529: // Write the backup header to the partition ! 530: if (_lwrite ((HFILE) dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE) == HFILE_ERROR) ! 531: { ! 532: nStatus = ERR_OS_ERROR; ! 533: goto closing_seq; ! 534: } ! 535: ! 536: // Fill the reserved sectors of the backup header area with random data ! 537: nStatus = WriteRandomDataToReservedHeaderAreas (dev, cryptoInfo, dataAreaSize, FALSE, TRUE); ! 538: ! 539: if (nStatus != ERR_SUCCESS) ! 540: goto closing_seq; ! 541: ! 542: ! 543: ! 544: /* Now we will try to decrypt the backup header to verify it has been correctly written. */ ! 545: ! 546: nStatus = OpenBackupHeader (dev, volParams->volumePath, volParams->password, &cryptoInfo2, NULL, deviceSize); ! 547: ! 548: if (nStatus != ERR_SUCCESS ! 549: || cryptoInfo->EncryptedAreaStart.Value != cryptoInfo2->EncryptedAreaStart.Value ! 550: || cryptoInfo2->EncryptedAreaStart.Value == 0) ! 551: { ! 552: if (nStatus == ERR_SUCCESS) ! 553: nStatus = ERR_PARAMETER_INCORRECT; ! 554: ! 555: goto closing_seq; ! 556: } ! 557: ! 558: // The backup header is valid so we know we should be able to safely resume in-place encryption ! 559: // of this partition even if the system/app crashes. ! 560: ! 561: ! 562: ! 563: /* Conceal the NTFS filesystem (by performing an easy-to-undo modification). This will prevent Windows ! 564: and apps from interfering with the volume until it has been fully encrypted. */ ! 565: ! 566: nStatus = ConcealNTFS (dev); ! 567: ! 568: if (nStatus != ERR_SUCCESS) ! 569: goto closing_seq; ! 570: ! 571: ! 572: ! 573: // /* If a drive letter is assigned to the device, remove it (so that users do not try to open it, which ! 574: //would cause Windows to ask them if they want to format the volume and other dangerous things). */ ! 575: ! 576: //if (driveLetter >= 0) ! 577: //{ ! 578: // char rootPath[] = { driveLetter + 'A', ':', '\\', 0 }; ! 579: ! 580: // // Try to remove the assigned drive letter ! 581: // if (DeleteVolumeMountPoint (rootPath)) ! 582: // driveLetter = -1; ! 583: //} ! 584: ! 585: ! 586: ! 587: /* Update config files and app data */ ! 588: ! 589: // In the config file, increase the number of partitions where in-place encryption is in progress ! 590: ! 591: SaveNonSysInPlaceEncSettings (1, wipeAlgorithm); ! 592: ! 593: ! 594: // Add the wizard to the system startup sequence if appropriate ! 595: ! 596: if (!IsNonInstallMode ()) ! 597: ManageStartupSeqWiz (FALSE, "/prinplace"); ! 598: ! 599: ! 600: nStatus = ERR_SUCCESS; ! 601: ! 602: ! 603: closing_seq: ! 604: ! 605: dwError = GetLastError(); ! 606: ! 607: if (cryptoInfo != NULL) ! 608: { ! 609: crypto_close (cryptoInfo); ! 610: cryptoInfo = NULL; ! 611: } ! 612: ! 613: if (cryptoInfo2 != NULL) ! 614: { ! 615: crypto_close (cryptoInfo2); ! 616: cryptoInfo2 = NULL; ! 617: } ! 618: ! 619: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 620: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 621: TCfree (header); ! 622: ! 623: if (dosDev[0]) ! 624: RemoveFakeDosName (volParams->volumePath, dosDev); ! 625: ! 626: *outHandle = dev; ! 627: ! 628: if (nStatus != ERR_SUCCESS) ! 629: SetLastError (dwError); ! 630: ! 631: return nStatus; ! 632: } ! 633: ! 634: ! 635: int EncryptPartitionInPlaceResume (HANDLE dev, ! 636: volatile FORMAT_VOL_PARAMETERS *volParams, ! 637: WipeAlgorithmId wipeAlgorithm, ! 638: volatile BOOL *bTryToCorrectReadErrors) ! 639: { ! 640: PCRYPTO_INFO masterCryptoInfo = NULL, headerCryptoInfo = NULL, tmpCryptoInfo = NULL; ! 641: UINT64_STRUCT unitNo; ! 642: char *buf = NULL, *header = NULL; ! 643: byte *wipeBuffer = NULL; ! 644: byte wipeRandChars [TC_WIPE_RAND_CHAR_COUNT]; ! 645: byte wipeRandCharsUpdate [TC_WIPE_RAND_CHAR_COUNT]; ! 646: char dosDev[TC_MAX_PATH] = {0}; ! 647: char devName[MAX_PATH] = {0}; ! 648: WCHAR deviceName[MAX_PATH]; ! 649: int nStatus = ERR_SUCCESS; ! 650: __int64 deviceSize; ! 651: uint64 remainingBytes, lastHeaderUpdateDistance = 0, zeroedSectorCount = 0; ! 652: uint32 workChunkSize; ! 653: DWORD dwError, dwResult; ! 654: BOOL bPause = FALSE, bEncryptedAreaSizeChanged = FALSE; ! 655: LARGE_INTEGER offset; ! 656: int sectorSize; ! 657: int i; ! 658: DWORD n; ! 659: char *devicePath = volParams->volumePath; ! 660: Password *password = volParams->password; ! 661: DISK_GEOMETRY driveGeometry; ! 662: ! 663: ! 664: bInPlaceEncNonSysResumed = TRUE; ! 665: ! 666: buf = (char *) TCalloc (TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE); ! 667: if (!buf) ! 668: { ! 669: nStatus = ERR_OUTOFMEMORY; ! 670: goto closing_seq; ! 671: } ! 672: ! 673: header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 674: if (!header) ! 675: { ! 676: nStatus = ERR_OUTOFMEMORY; ! 677: goto closing_seq; ! 678: } ! 679: ! 680: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 681: ! 682: if (wipeAlgorithm != TC_WIPE_NONE) ! 683: { ! 684: wipeBuffer = (byte *) TCalloc (TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE); ! 685: if (!wipeBuffer) ! 686: { ! 687: nStatus = ERR_OUTOFMEMORY; ! 688: goto closing_seq; ! 689: } ! 690: } ! 691: ! 692: headerCryptoInfo = crypto_open(); ! 693: ! 694: if (headerCryptoInfo == NULL) ! 695: { ! 696: nStatus = ERR_OUTOFMEMORY; ! 697: goto closing_seq; ! 698: } ! 699: ! 700: deviceSize = GetDeviceSize (devicePath); ! 701: if (deviceSize < 0) ! 702: { ! 703: // Cannot determine the size of the partition ! 704: nStatus = ERR_OS_ERROR; ! 705: goto closing_seq; ! 706: } ! 707: ! 708: if (dev == INVALID_HANDLE_VALUE) ! 709: { ! 710: strcpy ((char *)deviceName, devicePath); ! 711: ToUNICODE ((char *)deviceName); ! 712: ! 713: if (FakeDosNameForDevice (devicePath, dosDev, devName, FALSE) != 0) ! 714: { ! 715: nStatus = ERR_OS_ERROR; ! 716: goto closing_seq; ! 717: } ! 718: ! 719: dev = OpenPartitionVolume (devName, ! 720: FALSE, // Do not require exclusive access ! 721: FALSE, // Do not require shared access ! 722: TRUE, // Ask the user to confirm shared access (if exclusive fails) ! 723: FALSE, // Do not append alternative instructions how to encrypt the data (to applicable error messages) ! 724: FALSE); // Non-silent mode ! 725: ! 726: if (dev == INVALID_HANDLE_VALUE) ! 727: { ! 728: nStatus = ERR_DONT_REPORT; ! 729: goto closing_seq; ! 730: } ! 731: } ! 732: ! 733: // This should never be needed, but is still performed for extra safety (without checking the result) ! 734: DeviceIoControl (dev, ! 735: FSCTL_ALLOW_EXTENDED_DASD_IO, ! 736: NULL, ! 737: 0, ! 738: NULL, ! 739: 0, ! 740: &dwResult, ! 741: NULL); ! 742: ! 743: ! 744: if (!DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &driveGeometry, sizeof (driveGeometry), &dwResult, NULL)) ! 745: { ! 746: nStatus = ERR_OS_ERROR; ! 747: goto closing_seq; ! 748: } ! 749: ! 750: sectorSize = driveGeometry.BytesPerSector; ! 751: ! 752: ! 753: nStatus = OpenBackupHeader (dev, devicePath, password, &masterCryptoInfo, headerCryptoInfo, deviceSize); ! 754: ! 755: if (nStatus != ERR_SUCCESS) ! 756: goto closing_seq; ! 757: ! 758: ! 759: ! 760: remainingBytes = masterCryptoInfo->VolumeSize.Value - masterCryptoInfo->EncryptedAreaLength.Value; ! 761: ! 762: lastHeaderUpdateDistance = 0; ! 763: ! 764: ! 765: ExportProgressStats (masterCryptoInfo->EncryptedAreaLength.Value, masterCryptoInfo->VolumeSize.Value / SECTOR_SIZE); ! 766: ! 767: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_ENCRYPTING); ! 768: ! 769: bFirstNonSysInPlaceEncResumeDone = TRUE; ! 770: ! 771: ! 772: /* The in-place encryption core */ ! 773: ! 774: while (remainingBytes > 0) ! 775: { ! 776: workChunkSize = (uint32) min (remainingBytes, TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE); ! 777: ! 778: if (workChunkSize % ENCRYPTION_DATA_UNIT_SIZE != 0) ! 779: { ! 780: nStatus = ERR_PARAMETER_INCORRECT; ! 781: goto closing_seq; ! 782: } ! 783: ! 784: unitNo.Value = (remainingBytes - workChunkSize + TC_VOLUME_DATA_OFFSET) / ENCRYPTION_DATA_UNIT_SIZE; ! 785: ! 786: ! 787: // Read the plaintext into RAM ! 788: ! 789: inplace_enc_read: ! 790: ! 791: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize - TC_VOLUME_DATA_OFFSET; ! 792: ! 793: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) ! 794: { ! 795: nStatus = ERR_OS_ERROR; ! 796: goto closing_seq; ! 797: } ! 798: ! 799: if (ReadFile (dev, buf, workChunkSize, &n, NULL) == 0) ! 800: { ! 801: // Read error ! 802: ! 803: DWORD dwTmpErr = GetLastError (); ! 804: ! 805: if (dwTmpErr == ERROR_CRC || dwTmpErr == ERROR_IO_DEVICE) ! 806: { ! 807: // Physical defect or data corruption ! 808: ! 809: if (!*bTryToCorrectReadErrors) ! 810: { ! 811: *bTryToCorrectReadErrors = (AskWarnYesNo ("ENABLE_BAD_SECTOR_ZEROING") == IDYES); ! 812: } ! 813: ! 814: if (*bTryToCorrectReadErrors) ! 815: { ! 816: // Try to correct the read errors physically ! 817: ! 818: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize - TC_VOLUME_DATA_OFFSET; ! 819: ! 820: nStatus = ZeroUnreadableSectors (dev, offset, workChunkSize, sectorSize, &zeroedSectorCount); ! 821: ! 822: if (nStatus != ERR_SUCCESS) ! 823: { ! 824: // Due to write errors, we can't correct the read errors ! 825: nStatus = ERR_OS_ERROR; ! 826: goto closing_seq; ! 827: } ! 828: ! 829: goto inplace_enc_read; ! 830: } ! 831: } ! 832: ! 833: SetLastError (dwTmpErr); // Preserve the original error code ! 834: ! 835: nStatus = ERR_OS_ERROR; ! 836: goto closing_seq; ! 837: } ! 838: ! 839: if (remainingBytes - workChunkSize < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE) ! 840: { ! 841: // We reached the inital portion of the filesystem, which we had concealed (in order to prevent ! 842: // Windows from interfering with the volume). Now we need to undo that modification. ! 843: ! 844: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE - (remainingBytes - workChunkSize); i++) ! 845: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT; ! 846: } ! 847: ! 848: ! 849: // Encrypt the plaintext in RAM ! 850: ! 851: EncryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo); ! 852: ! 853: ! 854: // If enabled, wipe the area to which we will write the ciphertext ! 855: ! 856: if (wipeAlgorithm != TC_WIPE_NONE) ! 857: { ! 858: byte wipePass; ! 859: ! 860: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize; ! 861: ! 862: for (wipePass = 1; wipePass <= GetWipePassCount (wipeAlgorithm); ++wipePass) ! 863: { ! 864: if (!WipeBuffer (wipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, workChunkSize)) ! 865: { ! 866: ULONG i; ! 867: for (i = 0; i < workChunkSize; ++i) ! 868: { ! 869: wipeBuffer[i] = buf[i] + wipePass; ! 870: } ! 871: ! 872: EncryptDataUnits (wipeBuffer, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo); ! 873: memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate)); ! 874: } ! 875: ! 876: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 ! 877: || WriteFile (dev, wipeBuffer, workChunkSize, &n, NULL) == 0) ! 878: { ! 879: // Write error ! 880: dwError = GetLastError(); ! 881: ! 882: // Undo failed write operation ! 883: if (workChunkSize > TC_VOLUME_DATA_OFFSET && SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) ! 884: { ! 885: DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo); ! 886: WriteFile (dev, buf + TC_VOLUME_DATA_OFFSET, workChunkSize - TC_VOLUME_DATA_OFFSET, &n, NULL); ! 887: } ! 888: ! 889: SetLastError (dwError); ! 890: nStatus = ERR_OS_ERROR; ! 891: goto closing_seq; ! 892: } ! 893: } ! 894: ! 895: memcpy (wipeRandChars, wipeRandCharsUpdate, sizeof (wipeRandCharsUpdate)); ! 896: } ! 897: ! 898: ! 899: // Write the ciphertext ! 900: ! 901: offset.QuadPart = masterCryptoInfo->EncryptedAreaStart.Value - workChunkSize; ! 902: ! 903: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) ! 904: { ! 905: nStatus = ERR_OS_ERROR; ! 906: goto closing_seq; ! 907: } ! 908: ! 909: if (WriteFile (dev, buf, workChunkSize, &n, NULL) == 0) ! 910: { ! 911: // Write error ! 912: dwError = GetLastError(); ! 913: ! 914: // Undo failed write operation ! 915: if (workChunkSize > TC_VOLUME_DATA_OFFSET && SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) ! 916: { ! 917: DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo); ! 918: WriteFile (dev, buf + TC_VOLUME_DATA_OFFSET, workChunkSize - TC_VOLUME_DATA_OFFSET, &n, NULL); ! 919: } ! 920: ! 921: SetLastError (dwError); ! 922: nStatus = ERR_OS_ERROR; ! 923: goto closing_seq; ! 924: } ! 925: ! 926: ! 927: masterCryptoInfo->EncryptedAreaStart.Value -= workChunkSize; ! 928: masterCryptoInfo->EncryptedAreaLength.Value += workChunkSize; ! 929: ! 930: remainingBytes -= workChunkSize; ! 931: lastHeaderUpdateDistance += workChunkSize; ! 932: ! 933: bEncryptedAreaSizeChanged = TRUE; ! 934: ! 935: if (lastHeaderUpdateDistance >= TC_NONSYS_INPLACE_ENC_HEADER_UPDATE_INTERVAL) ! 936: { ! 937: nStatus = FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize); ! 938: ! 939: if (nStatus != ERR_SUCCESS) ! 940: goto closing_seq; ! 941: ! 942: lastHeaderUpdateDistance = 0; ! 943: } ! 944: ! 945: ExportProgressStats (masterCryptoInfo->EncryptedAreaLength.Value, masterCryptoInfo->VolumeSize.Value / SECTOR_SIZE); ! 946: ! 947: if (bVolTransformThreadCancel) ! 948: { ! 949: bPause = TRUE; ! 950: break; ! 951: } ! 952: } ! 953: ! 954: nStatus = FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize); ! 955: ! 956: ! 957: if (nStatus != ERR_SUCCESS) ! 958: goto closing_seq; ! 959: ! 960: ! 961: if (!bPause) ! 962: { ! 963: /* The data area has been fully encrypted; create and write the primary volume header */ ! 964: ! 965: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_FINALIZING); ! 966: ! 967: nStatus = CreateVolumeHeaderInMemory (FALSE, ! 968: header, ! 969: headerCryptoInfo->ea, ! 970: headerCryptoInfo->mode, ! 971: password, ! 972: masterCryptoInfo->pkcs5, ! 973: (char *) masterCryptoInfo->master_keydata, ! 974: &tmpCryptoInfo, ! 975: masterCryptoInfo->VolumeSize.Value, ! 976: 0, ! 977: masterCryptoInfo->EncryptedAreaStart.Value, ! 978: masterCryptoInfo->EncryptedAreaLength.Value, ! 979: masterCryptoInfo->RequiredProgramVersion, ! 980: masterCryptoInfo->HeaderFlags | TC_HEADER_FLAG_NONSYS_INPLACE_ENC, ! 981: FALSE); ! 982: ! 983: if (nStatus != ERR_SUCCESS) ! 984: goto closing_seq; ! 985: ! 986: ! 987: offset.QuadPart = TC_VOLUME_HEADER_OFFSET; ! 988: ! 989: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 ! 990: || WriteFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0) ! 991: { ! 992: nStatus = ERR_OS_ERROR; ! 993: goto closing_seq; ! 994: } ! 995: ! 996: // Fill the reserved sectors of the header area with random data ! 997: nStatus = WriteRandomDataToReservedHeaderAreas (dev, headerCryptoInfo, masterCryptoInfo->VolumeSize.Value, TRUE, FALSE); ! 998: ! 999: if (nStatus != ERR_SUCCESS) ! 1000: goto closing_seq; ! 1001: ! 1002: ! 1003: // Update the configuration files ! 1004: ! 1005: SaveNonSysInPlaceEncSettings (-1, wipeAlgorithm); ! 1006: ! 1007: ! 1008: ! 1009: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_FINISHED); ! 1010: ! 1011: nStatus = ERR_SUCCESS; ! 1012: } ! 1013: else ! 1014: { ! 1015: // The process has been paused by the user or aborted by the wizard (e.g. on app exit) ! 1016: ! 1017: nStatus = ERR_USER_ABORT; ! 1018: ! 1019: SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_PAUSED); ! 1020: } ! 1021: ! 1022: ! 1023: closing_seq: ! 1024: ! 1025: dwError = GetLastError(); ! 1026: ! 1027: if (bEncryptedAreaSizeChanged ! 1028: && dev != INVALID_HANDLE_VALUE ! 1029: && masterCryptoInfo != NULL ! 1030: && headerCryptoInfo != NULL ! 1031: && deviceSize > 0) ! 1032: { ! 1033: // Execution of the core loop may have been interrupted due to an error or user action without updating the header ! 1034: FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize); ! 1035: } ! 1036: ! 1037: if (masterCryptoInfo != NULL) ! 1038: { ! 1039: crypto_close (masterCryptoInfo); ! 1040: masterCryptoInfo = NULL; ! 1041: } ! 1042: ! 1043: if (headerCryptoInfo != NULL) ! 1044: { ! 1045: crypto_close (headerCryptoInfo); ! 1046: headerCryptoInfo = NULL; ! 1047: } ! 1048: ! 1049: if (tmpCryptoInfo != NULL) ! 1050: { ! 1051: crypto_close (tmpCryptoInfo); ! 1052: tmpCryptoInfo = NULL; ! 1053: } ! 1054: ! 1055: if (dosDev[0]) ! 1056: RemoveFakeDosName (devicePath, dosDev); ! 1057: ! 1058: if (dev != INVALID_HANDLE_VALUE) ! 1059: { ! 1060: CloseHandle (dev); ! 1061: dev = INVALID_HANDLE_VALUE; ! 1062: } ! 1063: ! 1064: if (buf != NULL) ! 1065: TCfree (buf); ! 1066: ! 1067: if (header != NULL) ! 1068: { ! 1069: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 1070: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 1071: TCfree (header); ! 1072: } ! 1073: ! 1074: if (wipeBuffer != NULL) ! 1075: TCfree (wipeBuffer); ! 1076: ! 1077: if (zeroedSectorCount > 0) ! 1078: { ! 1079: wchar_t msg[30000] = {0}; ! 1080: wchar_t sizeStr[500] = {0}; ! 1081: ! 1082: GetSizeString (zeroedSectorCount * sectorSize, sizeStr); ! 1083: ! 1084: wsprintfW (msg, ! 1085: GetString ("ZEROED_BAD_SECTOR_COUNT"), ! 1086: zeroedSectorCount, ! 1087: sizeStr); ! 1088: ! 1089: WarningDirect (msg); ! 1090: } ! 1091: ! 1092: if (nStatus != ERR_SUCCESS && nStatus != ERR_USER_ABORT) ! 1093: SetLastError (dwError); ! 1094: ! 1095: return nStatus; ! 1096: } ! 1097: ! 1098: ! 1099: int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_INFO *masterCryptoInfo, __int64 deviceSize) ! 1100: { ! 1101: LARGE_INTEGER offset; ! 1102: DWORD n; ! 1103: int nStatus = ERR_SUCCESS; ! 1104: byte *header; ! 1105: DWORD dwError; ! 1106: uint32 headerCrc32; ! 1107: byte *fieldPos; ! 1108: ! 1109: header = (byte *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 1110: ! 1111: if (!header) ! 1112: return ERR_OUTOFMEMORY; ! 1113: ! 1114: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 1115: ! 1116: ! 1117: fieldPos = (byte *) header + TC_HEADER_OFFSET_ENCRYPTED_AREA_START; ! 1118: ! 1119: offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE; ! 1120: ! 1121: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 ! 1122: || ReadFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0) ! 1123: { ! 1124: nStatus = ERR_OS_ERROR; ! 1125: goto closing_seq; ! 1126: } ! 1127: ! 1128: ! 1129: DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo); ! 1130: ! 1131: if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545) ! 1132: { ! 1133: nStatus = ERR_PARAMETER_INCORRECT; ! 1134: goto closing_seq; ! 1135: } ! 1136: ! 1137: mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaStart.Value)); ! 1138: mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaLength.Value)); ! 1139: ! 1140: ! 1141: headerCrc32 = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC); ! 1142: fieldPos = (byte *) header + TC_HEADER_OFFSET_HEADER_CRC; ! 1143: mputLong (fieldPos, headerCrc32); ! 1144: ! 1145: EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo); ! 1146: ! 1147: ! 1148: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 ! 1149: || WriteFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0) ! 1150: { ! 1151: nStatus = ERR_OS_ERROR; ! 1152: goto closing_seq; ! 1153: } ! 1154: ! 1155: ! 1156: closing_seq: ! 1157: ! 1158: dwError = GetLastError(); ! 1159: ! 1160: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 1161: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 1162: TCfree (header); ! 1163: ! 1164: if (nStatus != ERR_SUCCESS) ! 1165: SetLastError (dwError); ! 1166: ! 1167: return nStatus; ! 1168: } ! 1169: ! 1170: ! 1171: static HANDLE OpenPartitionVolume (const char *devName, ! 1172: BOOL bExclusiveRequired, ! 1173: BOOL bSharedRequired, ! 1174: BOOL bSharedRequiresConfirmation, ! 1175: BOOL bShowAlternativeSteps, ! 1176: BOOL bSilent) ! 1177: { ! 1178: HANDLE dev = INVALID_HANDLE_VALUE; ! 1179: int retryCount = 0; ! 1180: ! 1181: if (bExclusiveRequired) ! 1182: bSharedRequired = FALSE; ! 1183: ! 1184: if (bExclusiveRequired || !bSharedRequired) ! 1185: { ! 1186: // Exclusive access ! 1187: // Note that when exclusive access is denied, it is worth retrying (usually succeeds after a few tries). ! 1188: while (dev == INVALID_HANDLE_VALUE && retryCount++ < EXCL_ACCESS_MAX_AUTO_RETRIES) ! 1189: { ! 1190: dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL); ! 1191: ! 1192: if (retryCount > 1) ! 1193: Sleep (EXCL_ACCESS_AUTO_RETRY_DELAY); ! 1194: } ! 1195: } ! 1196: ! 1197: if (dev == INVALID_HANDLE_VALUE) ! 1198: { ! 1199: if (bExclusiveRequired) ! 1200: { ! 1201: if (!bSilent) ! 1202: { ! 1203: handleWin32Error (MainDlg); ! 1204: ! 1205: if (bShowAlternativeSteps) ! 1206: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE); ! 1207: else ! 1208: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL"); ! 1209: } ! 1210: return INVALID_HANDLE_VALUE; ! 1211: } ! 1212: ! 1213: // Shared mode ! 1214: dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL); ! 1215: if (dev != INVALID_HANDLE_VALUE) ! 1216: { ! 1217: if (bSharedRequiresConfirmation ! 1218: && !bSilent ! 1219: && AskWarnNoYes ("DEVICE_IN_USE_INPLACE_ENC") == IDNO) ! 1220: { ! 1221: CloseHandle (dev); ! 1222: return INVALID_HANDLE_VALUE; ! 1223: } ! 1224: } ! 1225: else ! 1226: { ! 1227: if (!bSilent) ! 1228: { ! 1229: handleWin32Error (MainDlg); ! 1230: ! 1231: if (bShowAlternativeSteps) ! 1232: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT", TRUE); ! 1233: else ! 1234: Error ("INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL"); ! 1235: } ! 1236: return INVALID_HANDLE_VALUE; ! 1237: } ! 1238: } ! 1239: ! 1240: return dev; ! 1241: } ! 1242: ! 1243: ! 1244: static int DismountFileSystem (HANDLE dev, ! 1245: int driveLetter, ! 1246: BOOL bForcedAllowed, ! 1247: BOOL bForcedRequiresConfirmation, ! 1248: BOOL bSilent) ! 1249: { ! 1250: int attempt; ! 1251: BOOL bResult; ! 1252: DWORD dwResult; ! 1253: ! 1254: CloseVolumeExplorerWindows (MainDlg, driveLetter); ! 1255: ! 1256: attempt = UNMOUNT_MAX_AUTO_RETRIES * 10; ! 1257: ! 1258: while (!(bResult = DeviceIoControl (dev, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL)) ! 1259: && attempt > 0) ! 1260: { ! 1261: Sleep (UNMOUNT_AUTO_RETRY_DELAY); ! 1262: attempt--; ! 1263: } ! 1264: ! 1265: if (!bResult) ! 1266: { ! 1267: if (!bForcedAllowed) ! 1268: { ! 1269: if (!bSilent) ! 1270: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS", TRUE); ! 1271: ! 1272: return ERR_DONT_REPORT; ! 1273: } ! 1274: ! 1275: if (bForcedRequiresConfirmation ! 1276: && !bSilent ! 1277: && AskWarnYesNo ("VOL_LOCK_FAILED_OFFER_FORCED_DISMOUNT") == IDNO) ! 1278: { ! 1279: return ERR_DONT_REPORT; ! 1280: } ! 1281: } ! 1282: ! 1283: // Dismount the volume ! 1284: ! 1285: attempt = UNMOUNT_MAX_AUTO_RETRIES * 10; ! 1286: ! 1287: while (!(bResult = DeviceIoControl (dev, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL)) ! 1288: && attempt > 0) ! 1289: { ! 1290: Sleep (UNMOUNT_AUTO_RETRY_DELAY); ! 1291: attempt--; ! 1292: } ! 1293: ! 1294: if (!bResult) ! 1295: { ! 1296: if (!bSilent) ! 1297: ShowInPlaceEncErrMsgWAltSteps ("INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS", TRUE); ! 1298: ! 1299: return ERR_DONT_REPORT; ! 1300: } ! 1301: ! 1302: return ERR_SUCCESS; ! 1303: } ! 1304: ! 1305: ! 1306: // Easy-to-undo modification applied to conceal the NTFS filesystem (to prevent Windows and apps from ! 1307: // interfering with it until the volume has been fully encrypted). Note that this function will precisely ! 1308: // undo any modifications it made to the filesystem automatically if an error occurs when writing (including ! 1309: // physical drive defects). ! 1310: static int ConcealNTFS (HANDLE dev) ! 1311: { ! 1312: char buf [TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE]; ! 1313: DWORD nbrBytesProcessed, nbrBytesProcessed2; ! 1314: int i; ! 1315: LARGE_INTEGER offset; ! 1316: DWORD dwError; ! 1317: ! 1318: offset.QuadPart = 0; ! 1319: ! 1320: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) ! 1321: return ERR_OS_ERROR; ! 1322: ! 1323: if (ReadFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0) ! 1324: return ERR_OS_ERROR; ! 1325: ! 1326: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE; i++) ! 1327: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT; ! 1328: ! 1329: offset.QuadPart = 0; ! 1330: ! 1331: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) ! 1332: return ERR_OS_ERROR; ! 1333: ! 1334: if (WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed, NULL) == 0) ! 1335: { ! 1336: // One or more of the sectors is/are probably damaged and cause write errors. ! 1337: // We must undo the modifications we made. ! 1338: ! 1339: dwError = GetLastError(); ! 1340: ! 1341: for (i = 0; i < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE; i++) ! 1342: buf[i] ^= TC_NTFS_CONCEAL_CONSTANT; ! 1343: ! 1344: offset.QuadPart = 0; ! 1345: ! 1346: do ! 1347: { ! 1348: Sleep (1); ! 1349: } ! 1350: while (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 ! 1351: || WriteFile (dev, buf, TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, &nbrBytesProcessed2, NULL) == 0); ! 1352: ! 1353: SetLastError (dwError); ! 1354: ! 1355: return ERR_OS_ERROR; ! 1356: } ! 1357: ! 1358: return ERR_SUCCESS; ! 1359: } ! 1360: ! 1361: ! 1362: void ShowInPlaceEncErrMsgWAltSteps (char *iniStrId, BOOL bErr) ! 1363: { ! 1364: wchar_t msg[30000]; ! 1365: ! 1366: wcscpy (msg, GetString (iniStrId)); ! 1367: ! 1368: wcscat (msg, L"\n\n\n"); ! 1369: wcscat (msg, GetString ("INPLACE_ENC_ALTERNATIVE_STEPS")); ! 1370: ! 1371: if (bErr) ! 1372: ErrorDirect (msg); ! 1373: else ! 1374: WarningDirect (msg); ! 1375: } ! 1376: ! 1377: ! 1378: static void ExportProgressStats (__int64 bytesDone, __int64 totalSectors) ! 1379: { ! 1380: NonSysInplaceEncBytesDone = bytesDone; ! 1381: NonSysInplaceEncTotalSectors = totalSectors; ! 1382: } ! 1383: ! 1384: ! 1385: void SetNonSysInplaceEncUIStatus (int nonSysInplaceEncStatus) ! 1386: { ! 1387: NonSysInplaceEncStatus = nonSysInplaceEncStatus; ! 1388: } ! 1389: ! 1390: ! 1391: BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId newWipeAlgorithm) ! 1392: { ! 1393: int count; ! 1394: char str[32]; ! 1395: WipeAlgorithmId savedWipeAlgorithm = TC_WIPE_NONE; ! 1396: ! 1397: if (delta == 0) ! 1398: return TRUE; ! 1399: ! 1400: count = LoadNonSysInPlaceEncSettings (&savedWipeAlgorithm) + delta; ! 1401: ! 1402: if (count < 1) ! 1403: { ! 1404: if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC))) ! 1405: remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC)); ! 1406: ! 1407: if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE))) ! 1408: remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)); ! 1409: ! 1410: if (!IsNonInstallMode () && SystemEncryptionStatus == SYSENC_STATUS_NONE) ! 1411: ManageStartupSeqWiz (TRUE, ""); ! 1412: ! 1413: return TRUE; ! 1414: } ! 1415: else ! 1416: { ! 1417: if (newWipeAlgorithm != TC_WIPE_NONE) ! 1418: { ! 1419: sprintf (str, "%d", (int) newWipeAlgorithm); ! 1420: ! 1421: SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE), strlen(str), FALSE); ! 1422: } ! 1423: else if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE))) ! 1424: { ! 1425: remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)); ! 1426: } ! 1427: ! 1428: sprintf (str, "%d", count); ! 1429: ! 1430: return SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC), strlen(str), FALSE); ! 1431: } ! 1432: } ! 1433: ! 1434: ! 1435: // Repairs damaged sectors (i.e. those with read errors) by zeroing them. ! 1436: // Note that this operating fails if there are any write errors. ! 1437: int ZeroUnreadableSectors (HANDLE dev, LARGE_INTEGER startOffset, int64 size, int sectorSize, uint64 *zeroedSectorCount) ! 1438: { ! 1439: int nStatus; ! 1440: DWORD n; ! 1441: int64 sectorCount; ! 1442: LARGE_INTEGER workOffset; ! 1443: byte *sectorBuffer = NULL; ! 1444: DWORD dwError; ! 1445: ! 1446: workOffset.QuadPart = startOffset.QuadPart; ! 1447: ! 1448: sectorBuffer = (byte *) TCalloc (sectorSize); ! 1449: ! 1450: if (!sectorBuffer) ! 1451: return ERR_OUTOFMEMORY; ! 1452: ! 1453: if (SetFilePointerEx (dev, startOffset, NULL, FILE_BEGIN) == 0) ! 1454: { ! 1455: nStatus = ERR_OS_ERROR; ! 1456: goto closing_seq; ! 1457: } ! 1458: ! 1459: ! 1460: for (sectorCount = size / sectorSize; sectorCount > 0; --sectorCount) ! 1461: { ! 1462: if (ReadFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0) ! 1463: { ! 1464: memset (sectorBuffer, 0, sectorSize); ! 1465: ! 1466: if (SetFilePointerEx (dev, workOffset, NULL, FILE_BEGIN) == 0) ! 1467: { ! 1468: nStatus = ERR_OS_ERROR; ! 1469: goto closing_seq; ! 1470: } ! 1471: ! 1472: if (WriteFile (dev, sectorBuffer, sectorSize, &n, NULL) == 0) ! 1473: { ! 1474: nStatus = ERR_OS_ERROR; ! 1475: goto closing_seq; ! 1476: } ! 1477: ++(*zeroedSectorCount); ! 1478: } ! 1479: ! 1480: workOffset.QuadPart += n; ! 1481: } ! 1482: ! 1483: nStatus = ERR_SUCCESS; ! 1484: ! 1485: closing_seq: ! 1486: ! 1487: dwError = GetLastError(); ! 1488: ! 1489: if (sectorBuffer != NULL) ! 1490: TCfree (sectorBuffer); ! 1491: ! 1492: if (nStatus != ERR_SUCCESS) ! 1493: SetLastError (dwError); ! 1494: ! 1495: return nStatus; ! 1496: } ! 1497: ! 1498: ! 1499: static int OpenBackupHeader (HANDLE dev, const char *devicePath, Password *password, PCRYPTO_INFO *retMasterCryptoInfo, CRYPTO_INFO *headerCryptoInfo, __int64 deviceSize) ! 1500: { ! 1501: LARGE_INTEGER offset; ! 1502: DWORD n; ! 1503: int nStatus = ERR_SUCCESS; ! 1504: char *header; ! 1505: DWORD dwError; ! 1506: ! 1507: header = (char *) TCalloc (TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 1508: if (!header) ! 1509: return ERR_OUTOFMEMORY; ! 1510: ! 1511: VirtualLock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 1512: ! 1513: ! 1514: ! 1515: offset.QuadPart = deviceSize - TC_VOLUME_HEADER_GROUP_SIZE; ! 1516: ! 1517: if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0 ! 1518: || ReadFile (dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &n, NULL) == 0) ! 1519: { ! 1520: nStatus = ERR_OS_ERROR; ! 1521: goto closing_seq; ! 1522: } ! 1523: ! 1524: ! 1525: nStatus = ReadVolumeHeader (FALSE, header, password, retMasterCryptoInfo, headerCryptoInfo); ! 1526: if (nStatus != ERR_SUCCESS) ! 1527: goto closing_seq; ! 1528: ! 1529: ! 1530: closing_seq: ! 1531: ! 1532: dwError = GetLastError(); ! 1533: ! 1534: burn (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 1535: VirtualUnlock (header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); ! 1536: TCfree (header); ! 1537: ! 1538: dwError = GetLastError(); ! 1539: ! 1540: if (nStatus != ERR_SUCCESS) ! 1541: SetLastError (dwError); ! 1542: ! 1543: return nStatus; ! 1544: } ! 1545: ! 1546: ! 1547: static BOOL GetFreeClusterBeforeThreshold (HANDLE volumeHandle, int64 *freeCluster, int64 clusterThreshold) ! 1548: { ! 1549: const int bitmapSize = 65536; ! 1550: byte bitmapBuffer[bitmapSize + sizeof (VOLUME_BITMAP_BUFFER)]; ! 1551: VOLUME_BITMAP_BUFFER *bitmap = (VOLUME_BITMAP_BUFFER *) bitmapBuffer; ! 1552: STARTING_LCN_INPUT_BUFFER startLcn; ! 1553: startLcn.StartingLcn.QuadPart = 0; ! 1554: ! 1555: DWORD bytesReturned; ! 1556: while (DeviceIoControl (volumeHandle, FSCTL_GET_VOLUME_BITMAP, &startLcn, sizeof (startLcn), &bitmapBuffer, sizeof (bitmapBuffer), &bytesReturned, NULL) ! 1557: || GetLastError() == ERROR_MORE_DATA) ! 1558: { ! 1559: for (int64 bitmapIndex = 0; bitmapIndex < min (bitmapSize, (bitmap->BitmapSize.QuadPart / 8)); ++bitmapIndex) ! 1560: { ! 1561: if (bitmap->StartingLcn.QuadPart + bitmapIndex * 8 >= clusterThreshold) ! 1562: goto err; ! 1563: ! 1564: if (bitmap->Buffer[bitmapIndex] != 0xff) ! 1565: { ! 1566: for (int bit = 0; bit < 8; ++bit) ! 1567: { ! 1568: if ((bitmap->Buffer[bitmapIndex] & (1 << bit)) == 0) ! 1569: { ! 1570: *freeCluster = bitmap->StartingLcn.QuadPart + bitmapIndex * 8 + bit; ! 1571: ! 1572: if (*freeCluster >= clusterThreshold) ! 1573: goto err; ! 1574: ! 1575: return TRUE; ! 1576: } ! 1577: } ! 1578: } ! 1579: } ! 1580: ! 1581: startLcn.StartingLcn.QuadPart += min (bitmapSize * 8, bitmap->BitmapSize.QuadPart); ! 1582: } ! 1583: ! 1584: err: ! 1585: SetLastError (ERROR_DISK_FULL); ! 1586: return FALSE; ! 1587: } ! 1588: ! 1589: ! 1590: static BOOL MoveClustersBeforeThresholdInDir (HANDLE volumeHandle, const wstring &directory, int64 clusterThreshold) ! 1591: { ! 1592: WIN32_FIND_DATAW findData; ! 1593: ! 1594: HANDLE findHandle = FindFirstFileW (((directory.size() <= 3 ? L"" : L"\\\\?\\") + directory + L"\\*").c_str(), &findData); ! 1595: if (findHandle == INVALID_HANDLE_VALUE) ! 1596: return TRUE; // Error ignored ! 1597: ! 1598: finally_do_arg (HANDLE, findHandle, { FindClose (finally_arg); }); ! 1599: ! 1600: // Find all files and directories ! 1601: do ! 1602: { ! 1603: if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ! 1604: { ! 1605: wstring subDir = findData.cFileName; ! 1606: ! 1607: if (subDir == L"." || subDir == L"..") ! 1608: continue; ! 1609: ! 1610: if (!MoveClustersBeforeThresholdInDir (volumeHandle, directory + L"\\" + subDir, clusterThreshold)) ! 1611: return FALSE; ! 1612: } ! 1613: ! 1614: DWORD access = FILE_READ_ATTRIBUTES; ! 1615: ! 1616: if (findData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ! 1617: access = FILE_READ_DATA; ! 1618: ! 1619: 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); ! 1620: if (fsObject == INVALID_HANDLE_VALUE) ! 1621: continue; ! 1622: ! 1623: finally_do_arg (HANDLE, fsObject, { CloseHandle (finally_arg); }); ! 1624: ! 1625: STARTING_VCN_INPUT_BUFFER startVcn; ! 1626: startVcn.StartingVcn.QuadPart = 0; ! 1627: RETRIEVAL_POINTERS_BUFFER retPointers; ! 1628: DWORD bytesReturned; ! 1629: ! 1630: // Find clusters allocated beyond the threshold ! 1631: while (DeviceIoControl (fsObject, FSCTL_GET_RETRIEVAL_POINTERS, &startVcn, sizeof (startVcn), &retPointers, sizeof (retPointers), &bytesReturned, NULL) ! 1632: || GetLastError() == ERROR_MORE_DATA) ! 1633: { ! 1634: if (retPointers.ExtentCount == 0) ! 1635: break; ! 1636: ! 1637: if (retPointers.Extents[0].Lcn.QuadPart != -1) ! 1638: { ! 1639: int64 extentStartCluster = retPointers.Extents[0].Lcn.QuadPart; ! 1640: int64 extentLen = retPointers.Extents[0].NextVcn.QuadPart - retPointers.StartingVcn.QuadPart; ! 1641: int64 extentEndCluster = extentStartCluster + extentLen - 1; ! 1642: ! 1643: if (extentEndCluster >= clusterThreshold) ! 1644: { ! 1645: // Move clusters before the threshold ! 1646: for (int64 movedCluster = max (extentStartCluster, clusterThreshold); movedCluster <= extentEndCluster; ++movedCluster) ! 1647: { ! 1648: for (int retry = 0; ; ++retry) ! 1649: { ! 1650: MOVE_FILE_DATA moveData; ! 1651: ! 1652: if (GetFreeClusterBeforeThreshold (volumeHandle, &moveData.StartingLcn.QuadPart, clusterThreshold)) ! 1653: { ! 1654: moveData.FileHandle = fsObject; ! 1655: moveData.StartingVcn.QuadPart = movedCluster - extentStartCluster + retPointers.StartingVcn.QuadPart; ! 1656: moveData.ClusterCount = 1; ! 1657: ! 1658: if (DeviceIoControl (volumeHandle, FSCTL_MOVE_FILE, &moveData, sizeof (moveData), NULL, 0, &bytesReturned, NULL)) ! 1659: break; ! 1660: } ! 1661: ! 1662: if (retry > 200) ! 1663: return FALSE; ! 1664: ! 1665: // There are possible race conditions as we work on a live filesystem ! 1666: Sleep (100); ! 1667: } ! 1668: } ! 1669: } ! 1670: } ! 1671: ! 1672: startVcn.StartingVcn = retPointers.Extents[0].NextVcn; ! 1673: } ! 1674: ! 1675: } while (FindNextFileW (findHandle, &findData)); ! 1676: ! 1677: return TRUE; ! 1678: } ! 1679: ! 1680: ! 1681: BOOL MoveClustersBeforeThreshold (HANDLE volumeHandle, PWSTR volumeDevicePath, int64 clusterThreshold) ! 1682: { ! 1683: int drive = GetDiskDeviceDriveLetter (volumeDevicePath); ! 1684: if (drive == -1) ! 1685: { ! 1686: SetLastError (ERROR_INVALID_PARAMETER); ! 1687: return FALSE; ! 1688: } ! 1689: ! 1690: wstring volumeRoot = L"X:"; ! 1691: volumeRoot[0] = L'A' + drive; ! 1692: ! 1693: return MoveClustersBeforeThresholdInDir (volumeHandle, volumeRoot, clusterThreshold); ! 1694: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.