public static DiskGroupLockResult ExtendPartition(Partition volume, long numberOfAdditionalExtentSectors)
        {
            if (volume.Disk is PhysicalDisk)
            {
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    bool isReadOnly;
                    bool isOnline = ((PhysicalDisk)volume.Disk).GetOnlineStatus(out isReadOnly);
                    if (!isOnline || isReadOnly)
                    {
                        return(DiskGroupLockResult.OneOrMoreDisksAreOfflineOrReadonly);
                    }
                }

                LockStatus status = LockHelper.LockBasicDiskAndVolumesOrNone(((PhysicalDisk)volume.Disk));
                if (status == LockStatus.CannotLockDisk)
                {
                    return(DiskGroupLockResult.CannotLockDisk);
                }
                else if (status == LockStatus.CannotLockVolume)
                {
                    return(DiskGroupLockResult.CannotLockVolume);
                }

                if (Environment.OSVersion.Version.Major >= 6)
                {
                    bool success = ((PhysicalDisk)volume.Disk).SetOnlineStatus(false);
                    if (!success)
                    {
                        return(DiskGroupLockResult.CannotTakeDiskOffline);
                    }
                }
            }

            ExtendHelper.ExtendPartition(volume, numberOfAdditionalExtentSectors);

            if (volume.Disk is PhysicalDisk)
            {
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    bool success = ((PhysicalDisk)volume.Disk).SetOnlineStatus(true);
                }
                LockHelper.UnlockBasicDiskAndVolumes((PhysicalDisk)volume.Disk);
                ((PhysicalDisk)volume.Disk).UpdateProperties();
            }

            return(DiskGroupLockResult.Success);
        }
示例#2
0
        /// <summary>
        /// Extend the partition and TrueCrypt volume
        /// </summary>
        public static TrueCryptResizeStatus ExtendVolume(Disk disk, byte[] password, long additionalNumberOfSectors)
        {
            Partition       partition = VolumeSelectionHelper.GetLastPartition(disk);
            TrueCryptVolume volume;

            try
            {
                volume = new TrueCryptVolume(partition, password);
            }
            catch (InvalidDataException)
            {
                return(TrueCryptResizeStatus.InvalidDisk);
            }
            catch (NotSupportedException)
            {
                return(TrueCryptResizeStatus.UnsupportedFormatVersion);
            }

            if (volume.IsHiddenVolume)
            {
                return(TrueCryptResizeStatus.HiddenVolume);
            }

            long availableBytes;

            if (partition is MBRPartition || partition is GPTPartition)
            {
                availableBytes = ExtendHelper.GetMaximumSizeToExtendPartition(partition);
            }
            else // Removable volume
            {
                availableBytes = additionalNumberOfSectors * volume.BytesPerSector;
            }

            TrueCryptHeader header = volume.Header;
            long            oldBackupHeaderOffset = (long)(header.MasterKeyScopeOffset + header.MasterKeyEncryptedAreaSize);
            long            newBackupHeaderOffset = (long)(header.MasterKeyScopeOffset + header.MasterKeyEncryptedAreaSize + (ulong)availableBytes);

            header.MasterKeyEncryptedAreaSize += (ulong)availableBytes;
            header.VolumeSize += (ulong)availableBytes;
            byte[] headerBytes = header.GetBytes(password);
            // Read backup header group from old end of the partition
            byte[] backupHeaderGroupBytes = partition.ReadSectors(oldBackupHeaderOffset / disk.BytesPerSector, TrueCryptVolume.VolumeHeaderGroupLength / disk.BytesPerSector);
            // Updated the backup header (using the stored salt)
            header.Salt = ByteReader.ReadBytes(backupHeaderGroupBytes, 0, 64);
            byte[] backupHeaderBytes = header.GetBytes(password);
            Array.Copy(backupHeaderBytes, 0, backupHeaderGroupBytes, 0, backupHeaderBytes.Length);

            if (partition is MBRPartition || partition is GPTPartition)
            {
                long availableSectors = availableBytes / disk.BytesPerSector;
                ExtendHelper.ExtendPartition((Partition)partition, availableSectors);
                // Reinitialize the partition
                partition = VolumeSelectionHelper.GetLastPartition(disk);
            }

            // Write backup header to the new end of the partition
            partition.WriteSectors(newBackupHeaderOffset / disk.BytesPerSector, backupHeaderGroupBytes);

            // Destroy the old backup header (to prevent decryption of the volume after the password has changed)
            byte[] temp = new byte[TrueCryptVolume.VolumeHeaderGroupLength];
            new Random().NextBytes(temp);
            partition.WriteSectors(oldBackupHeaderOffset / disk.BytesPerSector, temp);

            // Write an updated header
            partition.WriteSectors(0, headerBytes);

            return(TrueCryptResizeStatus.Success);
        }