/// <summary> /// Calculates the minimum block size required for a single partition, taking into account any children partitions. /// </summary> public PartitionHelper Partition(int hdNumberToGet, int partNumberToGet, long newHdSize) { var partition = _imageSchema.HardDrives[hdNumberToGet].Partitions[partNumberToGet]; var partitionHelper = new PartitionHelper { MinSizeBlk = 0 }; var extendedPartitionHelper = new ExtendedPartitionHelper(); if (partition.Type.ToLower() == "extended") extendedPartitionHelper = ExtendedPartition(hdNumberToGet, newHdSize); partitionHelper.VolumeGroupHelper = VolumeGroup(hdNumberToGet, partNumberToGet, newHdSize); var lbsByte = _imageSchema.HardDrives[hdNumberToGet].Lbs; var imagePath = Settings.PrimaryStoragePath + Path.DirectorySeparatorChar + "images" + Path.DirectorySeparatorChar + _imageProfile.Image.Name + Path.DirectorySeparatorChar + "hd" + hdNumberToGet; //Look if any volume groups are present for this partition. If so set the volumesize for the volume group to the minimum size //required for the volume group. Volume groups are always treated as resizable even if none of the individual //logical volumes are resizable if (partitionHelper.VolumeGroupHelper.Pv != null) { partitionHelper.PartitionHasVolumeGroup = true; partition.VolumeSize = (partitionHelper.VolumeGroupHelper.MinSizeBlk * lbsByte / 1024 / 1024); } if (partition.ForceFixedSize) { partitionHelper.MinSizeBlk = partition.Size; partitionHelper.IsDynamicSize = false; } //Use partition size that user has set for the partition, if it is set. else if (!string.IsNullOrEmpty(partition.CustomSize) && !string.IsNullOrEmpty(partition.CustomSizeUnit)) { long customSizeBytes = 0; switch (partition.CustomSizeUnit) { case "MB": customSizeBytes = Convert.ToInt64(partition.CustomSize) * 1024 * 1024; break; case "GB": customSizeBytes = Convert.ToInt64(partition.CustomSize) * 1024 * 1024 * 1024; break; case "%": double hdPercent = Convert.ToDouble(partition.CustomSize) / 100; customSizeBytes = Convert.ToInt64(hdPercent * newHdSize); break; } partitionHelper.MinSizeBlk = customSizeBytes / lbsByte; partitionHelper.IsDynamicSize = false; } //If partition is not resizable. Determine partition size. Also if the partition is less than 5 gigs assume it is that // size for a reason, do not resize it even if it is marked as a resizable partition else if ((partition.VolumeSize == 0 && partition.Type.ToLower() != "extended") || (partition.Type.ToLower() == "extended" && extendedPartitionHelper.IsOnlySwap) || partition.Size * lbsByte <= 5368709120 || partition.FsType == "swap") { partitionHelper.MinSizeBlk = partition.Size; partitionHelper.IsDynamicSize = false; } //If resizable determine what percent of drive partition was originally and match that to the new drive //while making sure the min size is still less than the resized size. else { partitionHelper.IsDynamicSize = true; if (partition.Type.ToLower() == "extended") partitionHelper.MinSizeBlk = extendedPartitionHelper.MinSizeBlk; else if (partitionHelper.VolumeGroupHelper.Pv != null) { partitionHelper.MinSizeBlk = partitionHelper.VolumeGroupHelper.MinSizeBlk; } else { string imageFile = null; foreach (var ext in new[] { "ntfs", "fat", "extfs", "hfsp", "imager", "xfs" }) { try { imageFile = Directory.GetFiles( imagePath + Path.DirectorySeparatorChar, "part" + partition.Number + "." + ext + ".*") .FirstOrDefault(); } catch (Exception ex) { Logger.Log(ex.Message); } if (imageFile != null) break; } if (Path.GetExtension(imageFile) == ".wim") partitionHelper.MinSizeBlk = (partition.UsedMb * 1024 * 1024) / lbsByte; else { //The resize value and used_mb value are calculated during upload by two different methods //Use the one that is bigger just in case. if (partition.VolumeSize > partition.UsedMb) partitionHelper.MinSizeBlk = partition.VolumeSize * 1024 * 1024 / lbsByte; else partitionHelper.MinSizeBlk = (partition.UsedMb * 1024 * 1024) / lbsByte; } } } return partitionHelper; }
/// <summary> /// Calculates the minimum block size for an extended partition by determining the minimum size of all logical /// partitions that fall under the extended. Does not assume that any extended partitions actually exist. /// </summary> public ExtendedPartitionHelper ExtendedPartition(int hdNumberToGet, long newHdSize) { var lbsByte = _imageSchema.HardDrives[hdNumberToGet].Lbs; var extendedPartitionHelper = new ExtendedPartitionHelper(); //Determine if any Extended or Logical Partitions are present. Needed ahead of time correctly calculate sizes. //And calculate minimum needed extended partition size bool schemaHasExtendedPartition = false; string logicalFsType = null; foreach (var part in _imageSchema.HardDrives[hdNumberToGet].Partitions.Where(part => part.Active)) { if (part.Type.ToLower() == "extended") { schemaHasExtendedPartition = true; } if (part.Type.ToLower() != "logical") continue; extendedPartitionHelper.LogicalCount++; logicalFsType = part.FsType; extendedPartitionHelper.HasLogical = true; } if (!schemaHasExtendedPartition) return extendedPartitionHelper; if (logicalFsType != null && (extendedPartitionHelper.LogicalCount == 1 && logicalFsType.ToLower() == "swap")) extendedPartitionHelper.IsOnlySwap = true; var partitionCounter = -1; foreach (var partition in _imageSchema.HardDrives[hdNumberToGet].Partitions) { partitionCounter++; if (!partition.Active && partition.Type.ToLower() != "extended" && partition.Type.ToLower() != "logical") continue; if (partition.Type.ToLower() == "extended") { if (partition.ForceFixedSize) { extendedPartitionHelper.MinSizeBlk = partition.Size; return extendedPartitionHelper; } if (!string.IsNullOrEmpty(partition.CustomSize) && !string.IsNullOrEmpty(partition.CustomSizeUnit)) { long customSizeBytes = 0; switch (partition.CustomSizeUnit) { case "MB": customSizeBytes = Convert.ToInt64(partition.CustomSize) * 1024 * 1024; break; case "GB": customSizeBytes = Convert.ToInt64(partition.CustomSize) * 1024 * 1024 * 1024; break; case "%": double hdPercent = Convert.ToDouble(partition.CustomSize) / 100; customSizeBytes = Convert.ToInt64(hdPercent * newHdSize); break; } extendedPartitionHelper.MinSizeBlk = customSizeBytes / lbsByte; return extendedPartitionHelper; } //If Hd has extended but no logical, use the extended to calc size if (!extendedPartitionHelper.HasLogical) { //In this case someone has defined an extended partition but has not created any logical //This could just be for preperation of leaving room for more logical partition later //This should be highly unlikely but should account for it anyway. There is no way of knowing a minimum size required //while still having the partition be resizable. So will set minimum sized required to unless user overrides //set arbitary minimum to 100MB extendedPartitionHelper.MinSizeBlk = 100 * 1024 * 1024 / lbsByte; return extendedPartitionHelper; } } else if (partition.Type.ToLower() == "logical") { //Check if the logical partition is a physical volume for a volume group if (partition.FsId.ToLower() == "8e" || partition.FsId.ToLower() == "8e00") { //Add to the minimum extended size the minimum size of the volume group var volumeGroupHelper = VolumeGroup(hdNumberToGet, partitionCounter, newHdSize); extendedPartitionHelper.MinSizeBlk += volumeGroupHelper.MinSizeBlk; if (volumeGroupHelper.MinSizeBlk == 0) extendedPartitionHelper.MinSizeBlk += partition.Size; } else { var partitionHelper = Partition(hdNumberToGet, partitionCounter, newHdSize); extendedPartitionHelper.MinSizeBlk += partitionHelper.MinSizeBlk; } } } //Logical paritions default to 1MB more than the previous block using fdisk. This needs to be added to extended size so logical parts will fit inside long epPadding = (((1048576/lbsByte)*extendedPartitionHelper.LogicalCount) + (1048576/lbsByte)); extendedPartitionHelper.MinSizeBlk += epPadding; return extendedPartitionHelper; }