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); } }
internal virtual int parseBody(Patch script, int end) { byte[] buf = Buffer; int c = RawParseUtils.nextLF(buf, _startOffset), last = c; OldLinesDeleted = 0; OldLinesAdded = 0; for (; c < end; last = c, c = RawParseUtils.nextLF(buf, c)) { bool breakScan; switch (buf[c]) { case (byte)' ': case (byte)'\n': LinesContext++; continue; case (byte)'-': OldLinesDeleted++; continue; case (byte)'+': OldLinesAdded++; continue; case (byte)'\\': // Matches "\ No newline at end of file" continue; default: breakScan = true; break; } if (breakScan) { break; } } if (last < end && LinesContext + OldLinesDeleted - 1 == OldLineCount && LinesContext + OldLinesAdded == NewLineCount && RawParseUtils.match(buf, last, Patch.SigFooter) >= 0) { // This is an extremely common occurrence of "corruption". // Users add footers with their signatures After this mark, // and git diff adds the git executable version number. // Let it slide; the hunk otherwise looked sound. // OldLinesDeleted--; return last; } if (LinesContext + OldLinesDeleted < OldLineCount) { int missingCount = OldLineCount - (LinesContext + OldLinesDeleted); //script.error(buf, _startOffset, "Truncated hunk, at least " + missingCount + " old lines is missing"); throw new FormatException(String.Format("Truncated hunk, at least {0} old line(s) missing. Hunk start @ {1}. Hunk:\n{2}",missingCount, _startOffset, buf)); } else if (LinesContext + OldLinesAdded < NewLineCount) { int missingCount = NewLineCount - (LinesContext + OldLinesAdded); //script.error(buf, _startOffset, "Truncated hunk, at least " + missingCount + " new lines is missing"); throw new FormatException(String.Format("Truncated hunk, at least {0} new line(s) missing. Hunk start @ {1}. Hunk:\n{2}", missingCount, _startOffset, buf)); } else if (LinesContext + OldLinesDeleted > OldLineCount || LinesContext + OldLinesAdded > NewLineCount) { string oldcnt = OldLineCount + ":" + NewLineCount; string newcnt = (LinesContext + OldLinesDeleted) + ":" + (LinesContext + OldLinesAdded); //script.warn(buf, _startOffset, "Hunk header " + oldcnt + " does not match body line count of " + newcnt); throw new FormatException(String.Format("Hunk header {0} does not match body line count of {1}. Hunk start @ {1}. Hunk:\n{2}" + oldcnt, newcnt, _startOffset, buf)); } return c; }