Exemple #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="OldVHD"></param>
        /// <param name="NewVHD"></param>
        /// <param name="Output">Filename to the output file.  Method will fail if this already exists unless Force is passed as 'true'.</param>
        /// <param name="OutputType">A <see cref="VMProvisioningAgent.DiffVHD.DiskType"/> which specifies the output file format.</param>
        /// <param name="Force">If true, will overwrite the Output file if it already exists.  Defaults to 'false'.</param>
        /// <param name="Partition">An int tuple which declares a specific pair of partitions to compare.  The first value in the tuple will be the 0-indexed partition number from OldVHD to compare against.  The second value of the tuple will be the 0-indexed parition from NewVHD to compare with.</param>
        /// <param name="Style"></param>
        /// <returns></returns>
        internal static void CreateDiff(string OldVHD, string NewVHD, string Output, DiskType OutputType = DiskType.VHD, bool Force = false, Tuple <int, int> Partition = null, ComparisonStyle Style = ComparisonStyle.DateTimeOnly)
        {
            if (File.Exists(Output) && !Force)
            {
                throw new ArgumentException("Output file already exists.", "Output");
            }
            if (!File.Exists(OldVHD))
            {
                throw new ArgumentException("Input file does not exist.", "OldVHD");
            }
            if (!File.Exists(NewVHD))
            {
                throw new ArgumentException("Input file does not exist.", "NewVHD");
            }

            // byte[] CopyBuffer = new byte[1024*1024];
            VirtualDisk Old, New, Out;

            Old = VirtualDisk.OpenDisk(OldVHD, FileAccess.Read);
            New = VirtualDisk.OpenDisk(NewVHD, FileAccess.Read);

            using (Old)
                using (New)
                    using (var OutFS = new FileStream(Output, Force ? FileMode.Create : FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None))
                    {
                        // Check type of filesystems being compared
                        if (!Old.IsPartitioned)
                        {
                            throw new ArgumentException("Input disk is not partitioned.", "OldVHD");
                        }
                        if (!New.IsPartitioned)
                        {
                            throw new ArgumentException("Input disk is not partitioned.", "NewVHD");
                        }

                        long   CapacityBuffer   = 64 * Math.Max(Old.Geometry.BytesPerSector, New.Geometry.BytesPerSector); // starting with 64 sectors as a buffer for partition information in the output file
                        long[] OutputCapacities = new long[Partition != null ? 1 : Old.Partitions.Count];

                        if (Partition != null)
                        {
                            var PartA = Old.Partitions[Partition.Item1];
                            var PartB = New.Partitions[Partition.Item2];
                            if (PartA.BiosType != PartB.BiosType)
                            {
                                throw new InvalidFileSystemException(
                                          String.Format(
                                              "Filesystem of partition {0} in '{1}' does not match filesystem type of partition {2} in '{3}'.",
                                              Partition.Item2, NewVHD, Partition.Item1, OldVHD));
                            }
                            OutputCapacities[0] += Math.Max(PartA.SectorCount * Old.Geometry.BytesPerSector, PartB.SectorCount * New.Geometry.BytesPerSector);
                        }
                        else
                        {
                            if (Old.Partitions.Count != New.Partitions.Count)
                            {
                                throw new ArgumentException(
                                          "Input disks do not have the same number of partitions.  To compare specific partitions on mismatched disks, provide the 'Partition' parameter.");
                            }
                            for (int i = 0; i < Old.Partitions.Count; i++)
                            {
                                if (Old.Partitions[i].BiosType != New.Partitions[i].BiosType)
                                {
                                    throw new InvalidFileSystemException(String.Format("Filesystem of partition {0} in '{1}' does not match filesystem type of partition {0} in '{2}'.", i, NewVHD, OldVHD));
                                }
                                else
                                {
                                    OutputCapacities[i] = Math.Max(Old.Partitions[i].SectorCount * Old.Geometry.BytesPerSector, New.Partitions[i].SectorCount * New.Geometry.BytesPerSector);
                                }
                            }
                        }

                        long OutputCapacity = CapacityBuffer + OutputCapacities.Sum();
                        switch (OutputType)
                        {
                        case DiskType.VHD:
                            Out = DiscUtils.Vhd.Disk.InitializeDynamic(OutFS, Ownership.None, OutputCapacity, Math.Max(New.BlockSize, 512 * 1024)); // the Max() is present only because there's currently a bug with blocksize < (8*sectorSize) in DiscUtils
                            break;

                        case DiskType.VHDX:
                            Out = DiscUtils.Vhdx.Disk.InitializeDynamic(OutFS, Ownership.None, OutputCapacity, Math.Max(New.BlockSize, 512 * 1024));
                            break;

                        default:
                            throw new NotSupportedException("The selected disk type is not supported at this time.",
                                                            new ArgumentException(
                                                                "Selected DiskType not currently supported.", "OutputType"));
                        }

                        using (Out)
                        {
                            // set up the output location
                            if (Out is DiscUtils.Vhd.Disk)
                            {
                                ((DiscUtils.Vhd.Disk)Out).AutoCommitFooter = false;
                            }
                            var OutParts = BiosPartitionTable.Initialize(Out);

                            if (Partition != null)
                            {
                                OutParts.Create(GetPartitionType(Old.Partitions[Partition.Item1]), false); // there is no need (ever) for a VHD diff to have bootable partitions
                                var OutFileSystem = Out.FormatPartition(0);
                                DiffPart(DetectFileSystem(Old.Partitions[Partition.Item1]),
                                         DetectFileSystem(New.Partitions[Partition.Item2]),
                                         OutFileSystem, // As we made the partition spen the entire drive, it should be the only partition
                                         Style);
                            }
                            else // Partition == null
                            {
                                for (int i = 0; i < Old.Partitions.Count; i++)
                                {
                                    var partIndex = OutParts.Create(Math.Max(Old.Partitions[i].SectorCount * Old.Parameters.BiosGeometry.BytesPerSector,
                                                                             New.Partitions[i].SectorCount * New.Parameters.BiosGeometry.BytesPerSector),
                                                                    GetPartitionType(Old.Partitions[i]), false);
                                    var OutFileSystem = Out.FormatPartition(partIndex);

                                    DiffPart(DetectFileSystem(Old.Partitions[i]),
                                             DetectFileSystem(New.Partitions[i]),
                                             OutFileSystem,
                                             Style);
                                }
                            }
                        } // using (Out)
                    }// using (Old, New, and OutFS)
        }