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

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

unix.superglobalmegacorp.com

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