/// <summary> /// Performs the actual comparison. /// </summary> /// <param name="Style">Comparison style to be used</param> /// <param name="Force">If True, will clear any existing results and perform a fresh comparison. If False, will not compare again if a comparison has already been performed. Defaults to False.</param> public void DoCompare(ComparisonStyle Style, bool Force = false) { if (!HaveCompared || Force) { Files.Clear(); Files = Compare(String.Empty, SourceA, SourceB, Recursive, Style); } HaveCompared = true; }
/// <summary> /// Construct an EntryComparer to compare entries using the provided /// <b>IComparer</b> object according to the specified comparison /// style. /// </summary> /// <remarks> /// If the style is <b>ComparisonStyle.Auto</b> then the comparator /// type is checked: if the comparer is an instance of the /// <see cref="KeyExtractor"/>, <b>ComparisonStyle.Key</b> style will /// be assumed; otherwise, the <b>ComparisonStyle.Value</b> style is used. /// </remarks> /// <param name="comparer"> /// The comparer to use; if not specified the "natural" comparison is /// used. /// </param> /// <param name="style"> /// The comparison style to use; valid values are any of the /// <see cref="ComparisonStyle"/> values. /// </param> public EntryComparer(IComparer comparer, ComparisonStyle style) : base(comparer) { switch (style) { case ComparisonStyle.Auto: style = (comparer != null && IsKeyComparer(comparer)) ? ComparisonStyle.Key : ComparisonStyle.Value; break; case ComparisonStyle.Value: case ComparisonStyle.Key: case ComparisonStyle.Entry: break; default: throw new ArgumentException("Invalid comparison style: " + style); } m_style = style; }
// private static WellKnownPartitionType GetPartitionType(PartitionInfo Partition) // { // switch (Partition.BiosType) // { // case BiosPartitionTypes.Fat16: // case BiosPartitionTypes.Fat32: // case BiosPartitionTypes.Fat32Lba: // return WellKnownPartitionType.WindowsFat; // case BiosPartitionTypes.Ntfs: // return WellKnownPartitionType.WindowsNtfs; // case BiosPartitionTypes.LinuxNative: // return WellKnownPartitionType.Linux; // case BiosPartitionTypes.LinuxSwap: // return WellKnownPartitionType.LinuxSwap; // case BiosPartitionTypes.LinuxLvm: // return WellKnownPartitionType.LinuxLvm; // default: // throw new ArgumentException( // String.Format("Unsupported partition type: '{0}'", BiosPartitionTypes.ToString(Partition.BiosType)), "Partition"); // } // } // // private static DiscFileSystem DetectFileSystem(PartitionInfo Partition) // { // using (var stream = Partition.Open()) // { // if (NtfsFileSystem.Detect(stream)) // return new NtfsFileSystem(Partition.Open()); // stream.Seek(0, SeekOrigin.Begin); // if (FatFileSystem.Detect(stream)) // return new FatFileSystem(Partition.Open()); // // /* Ext2/3/4 file system - when Ext becomes fully writable // // stream.Seek(0, SeekOrigin.Begin); // if (ExtFileSystem.Detect(stream)) // return new ExtFileSystem(Partition.Open()); // */ // // return null; // } // } private static void DiffPart(DiscFileSystem PartA, DiscFileSystem PartB, DiscFileSystem Output, ComparisonStyle Style = ComparisonStyle.DateTimeOnly, CopyQueue WriteQueue = null) { if (PartA == null) throw new ArgumentNullException("PartA"); if (PartB == null) throw new ArgumentNullException("PartB"); if (Output == null) throw new ArgumentNullException("Output"); if (PartA is NtfsFileSystem) { ((NtfsFileSystem) PartA).NtfsOptions.HideHiddenFiles = false; ((NtfsFileSystem) PartA).NtfsOptions.HideSystemFiles = false; } if (PartB is NtfsFileSystem) { ((NtfsFileSystem) PartB).NtfsOptions.HideHiddenFiles = false; ((NtfsFileSystem) PartB).NtfsOptions.HideSystemFiles = false; } if (Output is NtfsFileSystem) { ((NtfsFileSystem) Output).NtfsOptions.HideHiddenFiles = false; ((NtfsFileSystem) Output).NtfsOptions.HideSystemFiles = false; } if (WriteQueue == null) WriteQueue = new CopyQueue(); var RootA = PartA.Root; var RootB = PartB.Root; var OutRoot = Output.Root; var OutFileRoot = Output.GetDirectoryInfo(RootFiles); if (!OutFileRoot.Exists) OutFileRoot.Create(); CompareTree(RootA, RootB, OutFileRoot, WriteQueue, Style); WriteQueue.Go(); // Now handle registry files (if any) ParallelQuery<DiscFileInfo> Ofiles; lock(OutFileRoot.FileSystem) Ofiles = OutFileRoot.GetFiles("*.*", SearchOption.AllDirectories).AsParallel(); Ofiles = Ofiles.Where(dfi => SystemRegistryFiles.Contains(dfi.FullName, StringComparer.CurrentCultureIgnoreCase)); foreach (var file in Ofiles) { var A = PartA.GetFileInfo(file.FullName.Substring(RootFiles.Length + 1)); if (!A.Exists) { file.FileSystem.MoveFile(file.FullName, String.Concat(RootSystemRegistry, A.FullName)); continue; } //else MemoryStream SideA = new MemoryStream(); using (var tmp = A.OpenRead()) tmp.CopyTo(SideA); MemoryStream SideB = new MemoryStream(); using (var tmp = file.OpenRead()) tmp.CopyTo(SideB); var comp = new RegistryComparison(SideA, SideB, RegistryComparison.Side.B); comp.DoCompare(); var diff = new RegDiff(comp, RegistryComparison.Side.B); var outFile = Output.GetFileInfo(Path.Combine(RootSystemRegistry, file.FullName)); if (!outFile.Directory.Exists) { outFile.Directory.Create(); } using (var OUT = outFile.Open(outFile.Exists ? FileMode.Truncate : FileMode.CreateNew, FileAccess.ReadWrite)) diff.WriteToStream(OUT); file.Delete(); // remove this file from the set of file to copy and overwrite } lock (OutFileRoot.FileSystem) Ofiles = OutFileRoot.GetFiles("*.*", SearchOption.AllDirectories).AsParallel(); Ofiles = Ofiles.Where(dfi => UserRegisrtyFiles.IsMatch(dfi.FullName)); foreach (var file in Ofiles) { var match = UserRegisrtyFiles.Match(file.FullName); var A = PartA.GetFileInfo(file.FullName.Substring(RootFiles.Length + 1)); if (!A.Exists) { file.FileSystem.MoveFile(file.FullName, Path.Combine(RootUserRegistry, match.Groups["user"].Value, A.Name)); continue; } //else MemoryStream SideA = new MemoryStream(); using (var tmp = A.OpenRead()) tmp.CopyTo(SideA); MemoryStream SideB = new MemoryStream(); using (var tmp = file.OpenRead()) tmp.CopyTo(SideB); var comp = new RegistryComparison(SideA, SideB, RegistryComparison.Side.B); comp.DoCompare(); var diff = new RegDiff(comp, RegistryComparison.Side.B); var outFile = Output.GetFileInfo(Path.Combine(RootUserRegistry, match.Groups["user"].Value, file.FullName)); if (!outFile.Directory.Exists) { outFile.Directory.Create(); } using (var OUT = outFile.Open(outFile.Exists ? FileMode.Truncate : FileMode.CreateNew, FileAccess.ReadWrite)) diff.WriteToStream(OUT); file.Delete(); // remove this file from the set of file to copy and overwrite } }
private static Task CompTree(DiscDirectoryInfo A, DiscDirectoryInfo B, DiscDirectoryInfo Out, CopyQueue WriteQueue, ComparisonStyle Style = ComparisonStyle.DateTimeOnly) { if (WriteQueue == null) throw new ArgumentNullException("WriteQueue"); List<Task> tasks = new List<Task>(); DiscFileSystem Alock = A.FileSystem; DiscFileSystem Block = B.FileSystem; DiscFileSystem Olock = Out.FileSystem; ParallelQuery<DiscFileInfo> BFiles; lock(Block) BFiles = B.GetFiles("*.*", SearchOption.AllDirectories).ToArray().AsParallel(); BFiles = BFiles.Where(file => !ExcludeFiles.Contains(file.FullName.ToUpperInvariant()) ).AsParallel(); BFiles = ExclusionRules.Aggregate(BFiles, (current, rule) => current.Where(file => !rule.IsMatch(file.FullName))); BFiles = BFiles.Where(file => { DiscFileInfo Atmp; lock (Alock) Atmp = Alock.GetFileInfo(file.FullName); return !CompareFile(Atmp, file, Style); }).ToArray().AsParallel(); foreach (var file in BFiles) { DiscFileInfo outFile; lock (Olock) outFile = Out.FileSystem.GetFileInfo(Path.Combine(Out.FullName, file.FullName)); lock (Alock) WriteQueue.Add(file, outFile, Alock.GetFileInfo(file.FullName)); } return Task.Factory.StartNew(() => Task.WaitAll(tasks.ToArray()), TaskCreationOptions.AttachedToParent); }
private static void CompareTree(DiscDirectoryInfo A, DiscDirectoryInfo B, DiscDirectoryInfo Out, CopyQueue WriteQueue, ComparisonStyle Style = ComparisonStyle.DateTimeOnly) { CompTree(A, B, Out, WriteQueue, Style).Wait(); }
/// <summary> /// /// </summary> /// <param name="A"></param> /// <param name="B"></param> /// <param name="Style"></param> /// <returns>True if A and B are equivalent.</returns> private static bool CompareFile(DiscFileInfo A, DiscFileInfo B, ComparisonStyle Style = ComparisonStyle.DateTimeOnly) { if (A == null || B == null) return A == B; lock (A.FileSystem) lock (B.FileSystem) if (!A.Exists || !B.Exists) return false; if (Style == ComparisonStyle.Journaled) if (A.FileSystem is NtfsFileSystem) { lock(A.FileSystem) lock (B.FileSystem) { var An = A.FileSystem as NtfsFileSystem; var Bn = (NtfsFileSystem) (B.FileSystem); long Aid = (long) (An.GetFileId(A.FullName) & 0x0000ffffffffffff); long Bid = (long) (Bn.GetFileId(B.FullName) & 0x0000ffffffffffff); return An.GetMasterFileTable()[Aid].LogFileSequenceNumber == Bn.GetMasterFileTable()[Bid].LogFileSequenceNumber; } } else throw new ArgumentException("Journal comparison only functions on NTFS partitions.", "Style"); bool LenCheck, WriteCheck; lock (A.FileSystem) lock (B.FileSystem) { LenCheck = A.Length == B.Length; WriteCheck = A.LastWriteTimeUtc == B.LastWriteTimeUtc; } return LenCheck && (Style == ComparisonStyle.NameOnly || (Style == ComparisonStyle.BinaryOnly ? FilesMatch(A, B) : (WriteCheck && (Style == ComparisonStyle.DateTimeOnly || FilesMatch(A, B))))); }
/// <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="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">The <see cref="DiffVHD.ComparisonStyle"/> to be used when comparing individual files.</param> /// <param name="AsBinary">If true, the resultant diff will contain the complete binary file from the child for each file found to be different. Default is to only do this for non-text files and record a textual diff instead whenever possible.</param> /// <returns></returns> public 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, bool AsBinary = false) { 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(); using (Out = VHDBuilder.CreateDisk(OutputType, OutFS, OutputCapacity, New.BlockSize)) { var OutParts = Out.Partitions; if (Partition != null) { OutParts.Create(VHDBuilder.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(VHDBuilder.DetectFileSystem(Old.Partitions[Partition.Item1]), VHDBuilder.DetectFileSystem(New.Partitions[Partition.Item2]), OutFileSystem, // As we made the partition spen the entire drive, it should be the only partition Style, new CopyQueue(AsBinary)); } 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), VHDBuilder.GetPartitionType(Old.Partitions[i]), false); var OutFileSystem = Out.FormatPartition(partIndex); DiffPart(VHDBuilder.DetectFileSystem(Old.Partitions[i]), VHDBuilder.DetectFileSystem(New.Partitions[i]), OutFileSystem, Style, new CopyQueue(AsBinary)); } } } // using (Out) } // using (Old, New, and OutFS) }
/// <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="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">The 0-indexed partition number to compare from each disk file.</param> /// <param name="Style">The <see cref="DiffVHD.ComparisonStyle"/> to be used when comparing individual files.</param> /// <param name="AsBinary">If true, the resultant diff will contain the complete binary file from the child for each file found to be different. Default is to only do this for non-text files and record a textual diff instead whenever possible.</param> /// <returns></returns> public static void CreateDiff(string OldVHD, string NewVHD, string Output, int? Partition, DiskType OutputType = DiskType.VHD, bool Force = false, ComparisonStyle Style = ComparisonStyle.DateTimeOnly, bool AsBinary = false) { CreateDiff(OldVHD, NewVHD, Output, OutputType, Force, Partition.HasValue ? new Tuple<int, int>(Partition.Value, Partition.Value) : null, Style: Style, AsBinary: AsBinary); }
/// <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) }
private static Dictionary<string, FileCondition> Compare(string root, string sideA, string sideB, bool recurse, ComparisonStyle style) { Dictionary<string, file> Working = new Dictionary<string, file>(); // A-Side var AsideRoot = new DirectoryInfo(Path.Combine(sideA, root)); var Afiles = AsideRoot.GetFiles("*", recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); foreach (FileInfo A in Afiles) { var tmp = A.FullName.Substring(sideA.Length); if (tmp.IndexOf(Path.PathSeparator) == 0) tmp = tmp.Substring(1); Working.Add(tmp, new file{sideA = A}); } // B-Side var BsideRoot = new DirectoryInfo(Path.Combine(sideB, root)); var Bfiles = BsideRoot.GetFiles("*", recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); foreach (FileInfo B in Bfiles) { var tmp = B.FullName.Substring(sideB.Length); if (tmp.IndexOf(Path.PathSeparator) == 0) tmp = tmp.Substring(1); if (Working.ContainsKey(tmp)) { file F = Working[tmp]; F.sideB = B; Working[tmp] = F; } else { Working.Add(tmp, new file {sideB = B}); } } return Working.ToDictionary(item => item.Key, item => item.Value.sideB == null ? FileCondition.OnlyA : item.Value.sideA == null ? FileCondition.OnlyB // Check ComparisonStyle : style == ComparisonStyle.NameOnly ? (item.Value.sideA.Length != item.Value.sideB.Length ? FileCondition.Diff : FileCondition.Same) : style == ComparisonStyle.BinaryOnly ? (item.Value.sideA.Length != item.Value.sideB.Length ? FileCondition.Diff : FilesMatch(item.Value.sideA, item.Value.sideB) ? FileCondition.Same : FileCondition.Diff) : item.Value.sideA.LastWriteTimeUtc > item.Value.sideB.LastWriteTimeUtc ? FileCondition.NewerA : item.Value.sideA.LastWriteTimeUtc < item.Value.sideB.LastWriteTimeUtc ? FileCondition.NewerB : item.Value.sideA.Length != item.Value.sideB.Length ? FileCondition.Diff : style == ComparisonStyle.DateTimeOnly ? FileCondition.Same : FilesMatch(item.Value.sideA, item.Value.sideB) ? FileCondition.Same : FileCondition.Diff); }
/// <summary> /// Performs the actual comparison. /// </summary> /// <param name="Style">Comparison style to be used</param> /// <param name="Force">If True, will clear any existing results and perform a fresh comparison. If False, will not compare again if a comparison has already been performed. Defaults to False.</param> public void DoCompare(ComparisonStyle Style, bool Force = false) { if (!HaveCompared || Force) { Files.Clear(); Files = Compare(String.Empty, SourceA, SourceB, Recursive, Style); } HaveCompared = true; }
public TableHelper(ComparisonStyle style) { this.style = style; }
private static Dictionary <string, FileCondition> Compare(string root, string sideA, string sideB, bool recurse, ComparisonStyle style) { Dictionary <string, file> Working = new Dictionary <string, file>(); // A-Side var AsideRoot = new DirectoryInfo(Path.Combine(sideA, root)); var Afiles = AsideRoot.GetFiles("*", recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); foreach (FileInfo A in Afiles) { var tmp = A.FullName.Substring(sideA.Length); if (tmp.IndexOf(Path.PathSeparator) == 0) { tmp = tmp.Substring(1); } Working.Add(tmp, new file { sideA = A }); } // B-Side var BsideRoot = new DirectoryInfo(Path.Combine(sideB, root)); var Bfiles = BsideRoot.GetFiles("*", recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); foreach (FileInfo B in Bfiles) { var tmp = B.FullName.Substring(sideB.Length); if (tmp.IndexOf(Path.PathSeparator) == 0) { tmp = tmp.Substring(1); } if (Working.ContainsKey(tmp)) { file F = Working[tmp]; F.sideB = B; Working[tmp] = F; } else { Working.Add(tmp, new file { sideB = B }); } } return(Working.ToDictionary(item => item.Key, item => item.Value.sideB == null ? FileCondition.OnlyA : item.Value.sideA == null ? FileCondition.OnlyB // Check ComparisonStyle : style == ComparisonStyle.NameOnly ? (item.Value.sideA.Length != item.Value.sideB.Length ? FileCondition.Diff : FileCondition.Same) : style == ComparisonStyle.BinaryOnly ? (item.Value.sideA.Length != item.Value.sideB.Length ? FileCondition.Diff : FilesMatch(item.Value.sideA, item.Value.sideB) ? FileCondition.Same : FileCondition.Diff) : item.Value.sideA.LastWriteTimeUtc > item.Value.sideB.LastWriteTimeUtc ? FileCondition.NewerA : item.Value.sideA.LastWriteTimeUtc < item.Value.sideB.LastWriteTimeUtc ? FileCondition.NewerB : item.Value.sideA.Length != item.Value.sideB.Length ? FileCondition.Diff : style == ComparisonStyle.DateTimeOnly ? FileCondition.Same : FilesMatch(item.Value.sideA, item.Value.sideB) ? FileCondition.Same : FileCondition.Diff)); }