public void Go() { while (_queue.Any()) lock (this) { if (!_queue.Any()) continue; var current = _queue.First(); if (!current.Key.Directory.Exists) { CreateDirectoryTree(current.Value.Source.Directory, current.Key.Directory); } using (Stream src = current.Value.Source.OpenRead()) { if (src.Length <= 0) { // Diff/New file is empty, skip it. _queue.Remove(current.Key); continue; } if (current.Key.Exists) // trying to merge/apply data diff if (Diff.IsBinary(src) || _copyAsBinary) // binary blobs are copied whole using (Stream dest = current.Key.Open(FileMode.Truncate, FileAccess.ReadWrite)) src.CopyTo(dest); else using (Stream dest = current.Key.Open(FileMode.Open, FileAccess.ReadWrite)) { var srcBytes = src.toArray(); Patch P = new Patch(); if (P.ParseHunks(srcBytes) == 0) { // No diff hunks in the file. // Diff file not a diff, and not empty. Handle it as a binary file overwrite. dest.SetLength(0); src.CopyTo(dest); _queue.Remove(current.Key); continue; } var newBytes = P.SimpleApply(dest.toArray()); // Replace this call with a more sophisticated (read "intellegent") diff application method. dest.Position = 0; dest.Write(newBytes, 0, newBytes.Length); dest.SetLength(newBytes.Length); /* MergeResult mr = current.Value.Base == null ? MergeAlgorithm.merge(new RawText(dest.toArray()), new RawText(src.toArray()), new RawText(dest.toArray())) // use the base as "theirs" : MergeAlgorithm.merge(new RawText(dest.toArray()), new RawText(src.toArray()), new RawText( current.Value.Base.OpenRead() .toArray())); bool conflicts = mr.containsConflicts(); bool blurb = conflicts; */ } else using (var dest = current.Key.Create()) if (current.Value.Base == null || !current.Value.Base.Exists || Diff.IsBinary(src) || _copyAsBinary) src.CopyTo(dest); else { byte[] baseBytes = current.Value.Base.OpenRead().toArray(); byte[] srcBytes = src.toArray(); // string baseStr = baseBytes.Aggregate(String.Empty, (current1, b) => current1 + (char) b); // string srcStr = srcBytes.Aggregate(String.Empty, (current1, b) => current1 + (char)b); var diff = new Diff(baseBytes, srcBytes); if (diff.HasDifferences) { var df = new DiffFormatter(); df.FormatEdits(dest, new RawText(baseBytes), new RawText(srcBytes), diff.GetEdits()); /* Stream diffStream = new MemoryStream(); df.FormatEdits(diffStream, new RawText(baseBytes), new RawText(srcBytes), diff.GetEdits()); var fh = new CombinedFileHeader(Patch.ReadFully(diffStream), 0); var outStr = fh.getScriptText(); byte[] bytes = outStr.Cast<byte>().ToArray(); dest.Write(bytes, 0, bytes.Length); */ } else // Not really different, just different metadata. skip it. { dest.Close(); current.Key.Delete(); _queue.Remove(current.Key); continue; } } } // set the attributes and file timestamps (and ACLs if it's ntfs...) current.Key.Attributes = current.Value.Source.Attributes; if (current.Key.FileSystem is NtfsFileSystem) { var D = (NtfsFileSystem) current.Key.FileSystem; var S = (NtfsFileSystem) current.Value.Source.FileSystem; D.SetSecurity(current.Key.FullName, S.GetSecurity(current.Value.Source.FullName)); D.SetFileStandardInformation(current.Key.FullName, S.GetFileStandardInformation(current.Value.Source.FullName)); } else { current.Key.CreationTimeUtc = current.Value.Source.CreationTimeUtc; current.Key.LastWriteTimeUtc = current.Value.Source.LastWriteTimeUtc; current.Key.LastAccessTimeUtc = current.Value.Source.LastAccessTimeUtc; } _queue.Remove(current.Key); } }