private static void MoveExtentLeft(DiskGroupDatabase database, DynamicVolume volume, MoveExtentOperationResumeRecord resumeRecord, ref long bytesCopied)
        {
            DynamicDiskExtent relocatedExtent = DynamicDiskExtentHelper.GetByExtentID(volume.DynamicExtents, resumeRecord.ExtentID);

            if (resumeRecord.OldStartSector == (ulong)relocatedExtent.FirstSector)
            {
                // the database update was not completed (this must be a resume operation)
                relocatedExtent = new DynamicDiskExtent(relocatedExtent.Disk, (long)resumeRecord.NewStartSector, relocatedExtent.Size, resumeRecord.ExtentID);
                VolumeManagerDatabaseHelper.UpdateExtentLocation(database, volume, relocatedExtent);
            }

            DiskExtent sourceExtent = new DiskExtent(relocatedExtent.Disk, (long)resumeRecord.OldStartSector, relocatedExtent.Size);

            MoveHelper.MoveExtentDataLeft(volume, sourceExtent, relocatedExtent, resumeRecord, ref bytesCopied);

            // if this is a resume, then volume is StripedVolume, otherwise it is a Raid5Volume
            if (resumeRecord.RestoreRAID5)
            {
                VolumeManagerDatabaseHelper.ConvertStripedVolumeToRaid(database, volume.VolumeGuid);
                // get the updated volume (we just reconverted to RAID-5)
                volume = DynamicVolumeHelper.GetVolumeByGuid(database.Disks, volume.VolumeGuid);
            }

            // restore the filesystem boot sector
            byte[] filesystemBootRecord = relocatedExtent.Disk.ReadSector((long)resumeRecord.BootRecordBackupSector);
            volume.WriteSectors(0, filesystemBootRecord);

            ClearBackupData(relocatedExtent.Disk, resumeRecord);
        }
        public const int BackupBufferSizeLBA = 128; // there are about 180 contiguous free sectors in a private region

        /// <summary>
        /// Move extent to another disk
        /// </summary>
        public static void MoveExtentToAnotherDisk(DiskGroupDatabase database, DynamicVolume volume, DynamicDiskExtent sourceExtent, DiskExtent relocatedExtent, ref long bytesCopied)
        {
            // copy the data
            long transferSizeLBA = Settings.MaximumTransferSizeLBA;

            for (long sectorIndex = 0; sectorIndex < relocatedExtent.TotalSectors; sectorIndex += transferSizeLBA)
            {
                long sectorsLeft   = relocatedExtent.TotalSectors - sectorIndex;
                int  sectorsToRead = (int)Math.Min(transferSizeLBA, sectorsLeft);

                byte[] data = sourceExtent.ReadSectors(sectorIndex, sectorsToRead);

                relocatedExtent.WriteSectors(sectorIndex, data);

                bytesCopied += sectorsToRead * sourceExtent.BytesPerSector;
            }

            // Update the database to point to the relocated extent
            DynamicDisk       targetDisk             = DynamicDisk.ReadFromDisk(relocatedExtent.Disk);
            DynamicDiskExtent dynamicRelocatedExtent = new DynamicDiskExtent(relocatedExtent, sourceExtent.ExtentID);

            dynamicRelocatedExtent.Name     = sourceExtent.Name;
            dynamicRelocatedExtent.DiskGuid = targetDisk.DiskGuid;
            VolumeManagerDatabaseHelper.UpdateExtentLocation(database, volume, dynamicRelocatedExtent);
        }
        private static void MoveExtentRight(DiskGroupDatabase database, DynamicVolume volume, MoveExtentOperationResumeRecord resumeRecord, ref long bytesCopied)
        {
            DynamicDiskExtent sourceExtent    = GetVolumeExtent(volume, resumeRecord.ExtentID);
            DiskExtent        relocatedExtent = new DiskExtent(sourceExtent.Disk, (long)resumeRecord.NewStartSector, sourceExtent.Size);

            MoveHelper.MoveExtentDataRight(volume, sourceExtent, relocatedExtent, resumeRecord, ref bytesCopied);

            // even if the database update won't complete, the resume record was copied

            // update the database
            DynamicDiskExtent dynamicRelocatedExtent = new DynamicDiskExtent(relocatedExtent, sourceExtent.ExtentID);

            dynamicRelocatedExtent.Name     = sourceExtent.Name;
            dynamicRelocatedExtent.DiskGuid = sourceExtent.DiskGuid;
            VolumeManagerDatabaseHelper.UpdateExtentLocation(database, volume, dynamicRelocatedExtent);

            // if this is a resume, then volume is StripedVolume, otherwise it is a Raid5Volume
            if (resumeRecord.RestoreRAID5)
            {
                VolumeManagerDatabaseHelper.ConvertStripedVolumeToRaid(database, volume.VolumeGuid);
            }
            // get the updated volume (we moved an extent and possibly reconverted to RAID-5)
            volume = DynamicVolumeHelper.GetVolumeByGuid(database.Disks, volume.VolumeGuid);

            // restore the filesystem boot sector
            byte[] filesystemBootRecord = relocatedExtent.Disk.ReadSector((long)resumeRecord.BootRecordBackupSector);
            volume.WriteSectors(0, filesystemBootRecord);

            ClearBackupData(relocatedExtent.Disk, resumeRecord);
        }
        private void resumeOperationMenuItem_Click(object sender, EventArgs e)
        {
            DynamicVolume     volume = (DynamicVolume)((KeyValuePair <Volume, DiskExtent>)extentContextMenu.Tag).Key;
            DynamicDiskExtent extent = (DynamicDiskExtent)((KeyValuePair <Volume, DiskExtent>)extentContextMenu.Tag).Value;

            List <DynamicDisk> dynamicDisks = GetDynamicDisks();
            List <DynamicDisk> diskGroup    = DynamicDiskHelper.FindDiskGroup(dynamicDisks, volume.DiskGroupGuid);

            ResumeForm   resumeForm = new ResumeForm(diskGroup, volume, extent);
            DialogResult result     = resumeForm.ShowDialog();

            if (result == DialogResult.OK)
            {
                UpdateView();
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    MessageBox.Show("Click OK to Continue", "Operation completed successfully");
                }
                else
                {
                    string message = OperatingSystemHelper.GetUpdateMessage();
                    MessageBox.Show(message, "Operation completed successfully");
                }
            }
        }
Пример #5
0
 public static long GetMaximumSizeToExtendDynamicVolume(DynamicVolume volume)
 {
     if (volume is SimpleVolume)
     {
         SimpleVolume simpleVolume = (SimpleVolume)volume;
         return(GetMaximumSizeToExtendDynamicDiskExtent(simpleVolume.DiskExtent));
     }
     else if (volume is StripedVolume)
     {
         StripedVolume stripedVolume = (StripedVolume)volume;
         long          max           = Int64.MaxValue;
         foreach (DynamicDiskExtent extent in stripedVolume.Extents)
         {
             long extentMax = GetMaximumSizeToExtendDynamicDiskExtent(extent);
             max = Math.Min(max, extentMax);
         }
         return(max);
     }
     else if (volume is Raid5Volume)
     {
         Raid5Volume raid5Volume = (Raid5Volume)volume;
         long        max         = Int64.MaxValue;
         foreach (DynamicDiskExtent extent in raid5Volume.Extents)
         {
             long extentMax = GetMaximumSizeToExtendDynamicDiskExtent(extent);
             max = Math.Min(max, extentMax);
         }
         return(max);
     }
     else
     {
         return(0);
     }
 }
Пример #6
0
        public static string GetExtentsInformation(DynamicVolume volume)
        {
            List <DynamicDiskExtent> extents = volume.DynamicExtents;
            StringBuilder            builder = new StringBuilder();

            for (int extentIndex = 0; extentIndex < extents.Count; extentIndex++)
            {
                DynamicDiskExtent extent = extents[extentIndex];
                string            extentOffsetString;
                string            diskIDString = String.Empty;
                if (extent.Disk != null)
                {
                    long extentOffset = extent.FirstSector * extent.Disk.BytesPerSector;
                    extentOffsetString = FormattingHelper.GetStandardSizeString(extentOffset);
                    VolumeManagerDatabase database = VolumeManagerDatabase.ReadFromDisk(extent.Disk);
                    if (database != null)
                    {
                        ExtentRecord extentRecord = database.FindExtentByExtentID(extent.ExtentID);
                        if (extentRecord != null)
                        {
                            diskIDString = extentRecord.DiskId.ToString();
                        }
                    }
                }
                else
                {
                    extentOffsetString = "N/A";
                }

                string extentSizeString = FormattingHelper.GetStandardSizeString(extent.Size);
                builder.AppendFormat("Extent {0}, ID: {1}, Name: {2}, Size: {3}, Disk ID: {4}, Offset: {5}, Start Sector: {6}\n",
                                     extentIndex, extent.ExtentID, extent.Name, extentSizeString, diskIDString, extentOffsetString, extent.FirstSector);
            }
            return(builder.ToString());
        }
Пример #7
0
        public static DynamicVolume GetVolume(List <DynamicDisk> disks, VolumeManagerDatabase database, VolumeRecord volumeRecord)
        {
            List <ComponentRecord> componentRecords = database.FindComponentsByVolumeID(volumeRecord.VolumeId);

            if (volumeRecord.NumberOfComponents != (ulong)componentRecords.Count || componentRecords.Count == 0)
            {
                // database record is invalid
                throw new InvalidDataException("Number of components in volume record does not match actual number of component records");
            }

            if (componentRecords.Count == 1)
            {
                ComponentRecord componentRecord = componentRecords[0];
                return(GetVolume(disks, database, volumeRecord, componentRecord));
            }
            else // Mirrored volume
            {
                // Mirrored Simple Volume is the only kind of mirror suppored by Windows (only 2-way mirror is supported)
                // Veritas also supports Mirrored Stripe / Mirrored RAID-5 / Mirrored Spanned Volume (up to 32-way mirror is supported)
                List <DynamicVolume> volumes = new List <DynamicVolume>();
                foreach (ComponentRecord componentRecord in componentRecords)
                {
                    DynamicVolume volume = GetVolume(disks, database, volumeRecord, componentRecord);
                    volumes.Add(volume);
                }

                MirroredVolume mirroredVolume = new MirroredVolume(volumes, volumeRecord.VolumeGuid, database.DiskGroupGuid);
                mirroredVolume.VolumeID = volumeRecord.VolumeId;
                mirroredVolume.Name     = volumeRecord.Name;
                return(mirroredVolume);
            }
        }
Пример #8
0
        public static string GetVolumeInformation(Volume volume)
        {
            StringBuilder builder = new StringBuilder();

            builder.AppendFormat("Volume size: {0} bytes\n", volume.Size.ToString("###,###,###,###,##0"));
            builder.AppendFormat("Volume type: {0}\n", VolumeHelper.GetVolumeTypeString(volume));
            if (volume is GPTPartition)
            {
                builder.AppendFormat("Partition name: {0}\n", ((GPTPartition)volume).PartitionName);
            }
            else if (volume is DynamicVolume)
            {
                builder.AppendFormat("Volume name: {0}\n", ((DynamicVolume)volume).Name);
                builder.AppendFormat("Volume status: {0}\n", VolumeHelper.GetVolumeStatusString(volume));
            }

            Guid?windowsVolumeGuid = WindowsVolumeHelper.GetWindowsVolumeGuid(volume);

            if (windowsVolumeGuid.HasValue)
            {
                List <string> mountPoints = WindowsVolumeManager.GetMountPoints(windowsVolumeGuid.Value);
                foreach (string volumePath in mountPoints)
                {
                    builder.AppendFormat("Volume path: {0}\n", volumePath);
                }
                bool isMounted = WindowsVolumeManager.IsMounted(windowsVolumeGuid.Value);
                builder.AppendFormat("Mounted: {0}\n", isMounted);
            }
            builder.AppendLine();

            if (volume is MirroredVolume)
            {
                builder.AppendLine("Extents:");
                List <DynamicVolume> components = ((MirroredVolume)volume).Components;
                for (int componentIndex = 0; componentIndex < components.Count; componentIndex++)
                {
                    if (componentIndex != 0)
                    {
                        builder.AppendLine();
                    }
                    DynamicVolume component = components[componentIndex];
                    builder.AppendFormat("Component {0}:\n", componentIndex);
                    builder.Append(GetExtentsInformation(component));
                }
            }
            else if (volume is DynamicVolume)
            {
                builder.AppendLine("Extents:");
                builder.Append(GetExtentsInformation((DynamicVolume)volume));
            }
            else if (volume is Partition)
            {
                Partition partition             = (Partition)volume;
                long      partitionOffset       = partition.FirstSector * partition.BytesPerSector;
                string    partitionOffsetString = FormattingHelper.GetStandardSizeString(partitionOffset);
                builder.AppendFormat("Partiton Offset: {0}, Start Sector: {1}\n", partitionOffsetString, partition.FirstSector);
            }

            return(builder.ToString());
        }
Пример #9
0
 public ResumeForm(List <DynamicDisk> diskGroup, DynamicVolume volume, DynamicDiskExtent extent)
 {
     InitializeComponent();
     m_diskGroup = diskGroup;
     m_volume    = volume;
     m_extent    = extent;
 }
Пример #10
0
        public static List <DynamicVolume> GetDynamicDiskVolumes(DynamicDisk disk)
        {
            VolumeManagerDatabase database = VolumeManagerDatabase.ReadFromDisk(disk);
            List <DynamicDisk>    disks    = new List <DynamicDisk>();

            disks.Add(disk);

            List <DynamicVolume> result = new List <DynamicVolume>();

            if (database != null)
            {
                foreach (VolumeRecord volumeRecord in database.VolumeRecords)
                {
                    DynamicVolume volume = GetVolume(disks, database, volumeRecord);
                    if (volume != null)
                    {
                        foreach (DynamicDiskExtent extent in volume.Extents)
                        {
                            if (extent.DiskGuid == disk.DiskGuid)
                            {
                                result.Add(volume);
                                break;
                            }
                        }
                    }
                }
            }
            return(result);
        }
        private void addDiskToVolumeMenuItem_Click(object sender, EventArgs e)
        {
            DynamicVolume     volume = (DynamicVolume)((KeyValuePair <Volume, DiskExtent>)extentContextMenu.Tag).Key;
            DynamicDiskExtent extent = (DynamicDiskExtent)((KeyValuePair <Volume, DiskExtent>)extentContextMenu.Tag).Value;

            List <DynamicDisk> dynamicDisks = GetDynamicDisks();
            List <DynamicDisk> diskGroup    = DynamicDiskHelper.FindDiskGroup(dynamicDisks, volume.DiskGroupGuid);

            AddDiskForm  addDisk = new AddDiskForm(diskGroup, volume);
            DialogResult result  = addDisk.ShowDialog();

            if (result == DialogResult.OK)
            {
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    // Windows 7 / 2008 will likely make changes to the disk group, it will be marked as 'dirty' if we don't wait
                    Thread.Sleep(Windows6WaitTimeBeforeRefresh);
                }
                UpdateView();
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    //MessageBox.Show("Please go to Disk Management and reactivate the disk group", "Operation completed successfully");
                    MessageBox.Show("The volume has been extended successfully.\nyou can now proceed to extend the underlying file system.", "Operation completed successfully");
                }
                else
                {
                    string message = "The volume has been extended successfully.\nyou can now proceed to extend the underlying file system.";
                    message += "\n\n" + OperatingSystemHelper.GetUpdateMessage();
                    MessageBox.Show(message, "Operation completed successfully");
                }
            }
        }
        private void moveExtentMenuItem_Click(object sender, EventArgs e)
        {
            DynamicVolume     volume = (DynamicVolume)((KeyValuePair <Volume, DiskExtent>)extentContextMenu.Tag).Key;
            DynamicDiskExtent extent = (DynamicDiskExtent)((KeyValuePair <Volume, DiskExtent>)extentContextMenu.Tag).Value;

            List <DynamicDisk> dynamicDisks = GetDynamicDisks();
            List <DynamicDisk> diskGroup    = DynamicDiskHelper.FindDiskGroup(dynamicDisks, volume.DiskGroupGuid);

            bool isBootVolume;

            if (RetainHelper.IsVolumeRetained(volume, out isBootVolume))
            {
                StringBuilder builder = new StringBuilder();
                builder.AppendLine("You're trying to move a retained volume (volume that has a partition");
                builder.AppendLine("associated with it).");
                builder.AppendLine("If an operating system is present on this volume, a reconfiguration");
                builder.AppendLine("might be necessary before you could boot it successfully.");
                builder.AppendLine("This operation is currently not supported.");
                MessageBox.Show(builder.ToString(), "Warning");
                return;
            }

            if (DynamicDiskPartitionerResumeRecord.HasValidSignature(volume.ReadSector(0)))
            {
                StringBuilder builder = new StringBuilder();
                builder.AppendLine("There is already an operation in progress");
                builder.AppendLine("Use the RESUME command to resume the operation");
                MessageBox.Show(builder.ToString(), "Error");
                return;
            }

            MoveExtentForm moveExtent = new MoveExtentForm(diskGroup, volume, extent);
            DialogResult   result     = moveExtent.ShowDialog();

            if (result == DialogResult.OK)
            {
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    // Windows 7 / 2008 will likely make changes to the disk group, it will be marked as 'dirty' if we don't wait
                    Thread.Sleep(Windows6WaitTimeBeforeRefresh);
                }
                UpdateView();
                if (Environment.OSVersion.Version.Major >= 6)
                {
                    //MessageBox.Show("Please go to Disk Management and reactivate the disk group", "Operation completed successfully");
                    MessageBox.Show("Click OK to Continue", "Operation completed successfully");
                }
                else
                {
                    string message = OperatingSystemHelper.GetUpdateMessage();
                    MessageBox.Show(message, "Operation completed successfully");
                }
            }
        }
Пример #13
0
 public static bool ContainsVolumeGuid(List <Volume> volumes, Guid volumeGuid)
 {
     foreach (Volume volume in volumes)
     {
         if (volume is DynamicVolume)
         {
             DynamicVolume dynamicVolume = (DynamicVolume)volume;
             if (dynamicVolume.VolumeGuid == volumeGuid)
             {
                 return(true);
             }
         }
     }
     return(false);
 }
Пример #14
0
        public static List <DynamicVolume> GetDynamicVolumes(List <DynamicDisk> disks)
        {
            List <DynamicVolume> result = new List <DynamicVolume>();

            List <DiskGroupDatabase> diskGroupDatabases = DiskGroupDatabase.ReadFromDisks(disks);

            foreach (DiskGroupDatabase database in diskGroupDatabases)
            {
                foreach (VolumeRecord volumeRecord in database.VolumeRecords)
                {
                    DynamicVolume volume = GetVolume(disks, database, volumeRecord);
                    result.Add(volume);
                }
            }

            return(result);
        }
Пример #15
0
 public static void ExtendDynamicVolume(DynamicVolume volume, long numberOfAdditionalExtentSectors, DiskGroupDatabase database)
 {
     if (volume is SimpleVolume)
     {
         SimpleVolume simpleVolume = (SimpleVolume)volume;
         VolumeManagerDatabaseHelper.ExtendSimpleVolume(database, simpleVolume, numberOfAdditionalExtentSectors);
     }
     else if (volume is StripedVolume)
     {
         StripedVolume stripedVolume = (StripedVolume)volume;
         VolumeManagerDatabaseHelper.ExtendStripedVolume(database, stripedVolume, numberOfAdditionalExtentSectors);
     }
     else if (volume is Raid5Volume)
     {
         Raid5Volume raid5Volume = (Raid5Volume)volume;
         VolumeManagerDatabaseHelper.ExtendRAID5Volume(database, raid5Volume, numberOfAdditionalExtentSectors);
     }
 }
        public static void ResumeMoveExtent(DiskGroupDatabase database, DynamicVolume volume, MoveExtentOperationResumeRecord resumeRecord, ref long bytesCopied)
        {
            if (resumeRecord.OldStartSector == resumeRecord.NewStartSector)
            {
                throw new InvalidDataException("Invalid move record");
            }

            if (resumeRecord.RestoreFromBuffer)
            {
                // we need to use the backup buffer to restore the data that may have been overwritten
                DynamicDiskExtent sourceExtent = GetVolumeExtent(volume, resumeRecord.ExtentID);
                byte[]            backupBuffer = sourceExtent.Disk.ReadSectors((long)resumeRecord.BackupBufferStartSector, BackupBufferSizeLBA);
                if (resumeRecord.OldStartSector < resumeRecord.NewStartSector)
                {
                    // move right
                    long readCount     = (long)resumeRecord.NumberOfCommittedSectors;
                    int  sectorsToRead = BackupBufferSizeLBA;
                    long sectorIndex   = sourceExtent.TotalSectors - readCount - sectorsToRead;
                    sourceExtent.WriteSectors(sectorIndex, backupBuffer);

                    System.Diagnostics.Debug.WriteLine("Restored to " + sectorIndex);
                }
                else
                {
                    // move left
                    long sectorIndex = (long)resumeRecord.NumberOfCommittedSectors;
                    sourceExtent.WriteSectors(sectorIndex, backupBuffer);

                    System.Diagnostics.Debug.WriteLine("Restored to " + sectorIndex);
                }
            }

            if (resumeRecord.OldStartSector < resumeRecord.NewStartSector)
            {
                MoveExtentRight(database, volume, resumeRecord, ref bytesCopied);
            }
            else
            {
                MoveExtentLeft(database, volume, resumeRecord, ref bytesCopied);
            }
        }
 private static DynamicDiskExtent GetVolumeExtent(DynamicVolume volume, ulong extentID)
 {
     if (volume is MirroredVolume)
     {
         foreach (DynamicVolume component in ((MirroredVolume)volume).Components)
         {
             int extentIndex = DynamicDiskExtentHelper.GetIndexOfExtentID(component.DynamicExtents, extentID);
             if (extentIndex >= 0)
             {
                 return(volume.DynamicExtents[extentIndex]);
             }
         }
     }
     else
     {
         int extentIndex = DynamicDiskExtentHelper.GetIndexOfExtentID(volume.DynamicExtents, extentID);
         if (extentIndex >= 0)
         {
             return(volume.DynamicExtents[extentIndex]);
         }
     }
     throw new ArgumentException("Volume does not have an extent with given ExtentID");
 }
        public static DiskGroupLockResult ExtendDynamicVolume(List <DynamicDisk> diskGroup, DynamicVolume volume, long numberOfAdditionalExtentSectors)
        {
            if (volume is StripedVolume)
            {
                numberOfAdditionalExtentSectors -= numberOfAdditionalExtentSectors % ((StripedVolume)volume).SectorsPerStripe;
            }
            if (volume is Raid5Volume)
            {
                numberOfAdditionalExtentSectors -= numberOfAdditionalExtentSectors % ((Raid5Volume)volume).SectorsPerStripe;
            }

            DiskGroupLockResult result = DiskGroupHelper.LockDiskGroup(diskGroup);

            if (result != DiskGroupLockResult.Success)
            {
                return(result);
            }

            DiskGroupDatabase database = DiskGroupDatabase.ReadFromDisks(diskGroup, volume.DiskGroupGuid);

            ExtendHelper.ExtendDynamicVolume((DynamicVolume)volume, numberOfAdditionalExtentSectors, database);

            DiskGroupHelper.UnlockDiskGroup(diskGroup);

            return(DiskGroupLockResult.Success);
        }
        /// <summary>
        /// Move extent to a new location on the same disk
        /// </summary>
        public static void MoveExtentWithinSameDisk(DiskGroupDatabase database, DynamicVolume volume, DynamicDiskExtent sourceExtent, DiskExtent relocatedExtent, ref long bytesCopied)
        {
            MoveExtentOperationResumeRecord resumeRecord = new MoveExtentOperationResumeRecord();

            // If there will be a power failure during the move, a RAID volume will resync during boot,
            // To prevent destruction of the data, we temporarily convert the array to striped volume
            if (volume is Raid5Volume)
            {
                VolumeManagerDatabaseHelper.ConvertRaidToStripedVolume(database, volume.VolumeGuid);
                resumeRecord.RestoreRAID5 = true;
            }

            // We want to write our own volume boot sector for recovery purposes, so we must find where to backup the old boot sector.
            // We don't want to store the backup in the range of the existing or relocated extent, because then we would have to move
            // the backup around during the move operation, other options include:
            // 1. Store it between sectors 1-62 (cons: Could be in use, Windows occasionally start a volume from sector 1)
            // 2. Find an easily compressible sector (e.g. zero-filled) within the existing extent, overwrite it with the backup, and restore it when the operation is done.
            // 3. use the LDM private region to store the sector.

            DynamicDisk dynamicDisk = DynamicDisk.ReadFromDisk(relocatedExtent.Disk);
            // Note: backupSectorIndex will be from the beginning of the private region while backupBufferStartSector will be from the end
            // so there is no need to allocate them
            long backupSectorIndex = PrivateRegionHelper.FindUnusedSector(dynamicDisk.PrivateHeader, dynamicDisk.TOCBlock);

            resumeRecord.VolumeGuid = volume.VolumeGuid;
            resumeRecord.NumberOfCommittedSectors = 0;
            resumeRecord.ExtentID               = sourceExtent.ExtentID;
            resumeRecord.OldStartSector         = (ulong)sourceExtent.FirstSector;
            resumeRecord.NewStartSector         = (ulong)relocatedExtent.FirstSector;
            resumeRecord.BootRecordBackupSector = (ulong)backupSectorIndex;

            long distanceLBA = (long)Math.Abs((double)resumeRecord.NewStartSector - resumeRecord.OldStartSector);

            if (distanceLBA < MoveHelper.BufferedModeThresholdLBA)
            {
                long backupBufferStartSector = PrivateRegionHelper.FindUnusedRegion(dynamicDisk.PrivateHeader, dynamicDisk.TOCBlock, BackupBufferSizeLBA);
                if (backupBufferStartSector == -1)
                {
                    throw new Exception("Private region is full");
                }

                if (backupBufferStartSector <= backupSectorIndex)
                {
                    throw new Exception("Private region structure is unknown");
                }
                resumeRecord.BackupBufferStartSector = (ulong)backupBufferStartSector;
                resumeRecord.BackupBufferSizeLBA     = BackupBufferSizeLBA;
            }

            // Backup the first sector of the first extent
            // (We replace the filesystem boot record with our own sector for recovery purposes)
            byte[] filesystemBootRecord = volume.ReadSector(0);
            relocatedExtent.Disk.WriteSectors(backupSectorIndex, filesystemBootRecord);

            // we write the resume record instead of the boot record
            volume.WriteSectors(0, resumeRecord.GetBytes(volume.BytesPerSector));

            if (sourceExtent.FirstSector < relocatedExtent.FirstSector)
            {
                // move right
                MoveExtentRight(database, volume, resumeRecord, ref bytesCopied);
            }
            else
            {
                // move left

                // we write the resume record at the new location as well (to be able to resume if a power failure will occur immediately after updating the database)
                relocatedExtent.WriteSectors(0, resumeRecord.GetBytes(relocatedExtent.BytesPerSector));
                DynamicDiskExtent dynamicRelocatedExtent = new DynamicDiskExtent(relocatedExtent, sourceExtent.ExtentID);
                dynamicRelocatedExtent.Name     = sourceExtent.Name;
                dynamicRelocatedExtent.DiskGuid = sourceExtent.DiskGuid;
                VolumeManagerDatabaseHelper.UpdateExtentLocation(database, volume, dynamicRelocatedExtent);
                int extentIndex = DynamicDiskExtentHelper.GetIndexOfExtentID(volume.DynamicExtents, sourceExtent.ExtentID);
                // get the updated volume (we just moved an extent)
                volume = DynamicVolumeHelper.GetVolumeByGuid(database.Disks, volume.VolumeGuid);
                MoveExtentLeft(database, volume, resumeRecord, ref bytesCopied);
            }
        }
 public AddDiskForm(List <DynamicDisk> diskGroup, DynamicVolume volume)
 {
     InitializeComponent();
     m_diskGroup = diskGroup;
     m_volume    = volume;
 }
        private static ExtendFileSystemResult ExtendUnmountedFileSystem(List <DynamicDisk> diskGroup, DynamicVolume volume, long numberOfAdditionalSectors)
        {
            if (!volume.IsOperational)
            {
                return(ExtendFileSystemResult.NonOperationalVolume);
            }

            IExtendableFileSystem fileSystem = FileSystemHelper.ReadFileSystem(volume) as IExtendableFileSystem;

            // Windows Vista / 7 enforce various limitations on direct write operations to volumes and disks.
            // Basic disks are not needed to be taken offline for direct write operations within volume region. Only dynamic disks have to.
            if (Environment.OSVersion.Version.Major >= 6)
            {
                // Lock disks and volumes
                DiskGroupLockResult lockResult = DiskGroupHelper.LockDiskGroup(diskGroup);
                if (lockResult == DiskGroupLockResult.CannotLockDisk)
                {
                    return(ExtendFileSystemResult.CannotLockDisk);
                }
                else if (lockResult == DiskGroupLockResult.CannotLockVolume)
                {
                    return(ExtendFileSystemResult.CannotLockVolume);
                }
                else if (lockResult == DiskGroupLockResult.CannotTakeDiskOffline)
                {
                    return(ExtendFileSystemResult.CannotTakeDiskOffline);
                }
                else if (lockResult == DiskGroupLockResult.OneOrMoreDisksAreOfflineOrReadonly)
                {
                    return(ExtendFileSystemResult.OneOrMoreDisksAreOfflineOrReadonly);
                }
            }
            fileSystem.Extend(numberOfAdditionalSectors);

            if (Environment.OSVersion.Version.Major >= 6)
            {
                DiskGroupHelper.UnlockDiskGroup(diskGroup);
            }

            return(ExtendFileSystemResult.Success);
        }