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

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

unix.superglobalmegacorp.com

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