Annotation of truecrypt/format/inplace.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.