diff --git a/Lib/NativeBinaries/amd64/git2-a2012c4.dll b/Lib/NativeBinaries/amd64/git2-a2012c4.dll new file mode 100644 index 000000000..495a3d663 Binary files /dev/null and b/Lib/NativeBinaries/amd64/git2-a2012c4.dll differ diff --git a/Lib/NativeBinaries/amd64/git2-e0902fb.pdb b/Lib/NativeBinaries/amd64/git2-a2012c4.pdb similarity index 53% rename from Lib/NativeBinaries/amd64/git2-e0902fb.pdb rename to Lib/NativeBinaries/amd64/git2-a2012c4.pdb index bdef63b09..7aa644b1a 100644 Binary files a/Lib/NativeBinaries/amd64/git2-e0902fb.pdb and b/Lib/NativeBinaries/amd64/git2-a2012c4.pdb differ diff --git a/Lib/NativeBinaries/amd64/git2-e0902fb.dll b/Lib/NativeBinaries/amd64/git2-e0902fb.dll deleted file mode 100644 index f4931dbdd..000000000 Binary files a/Lib/NativeBinaries/amd64/git2-e0902fb.dll and /dev/null differ diff --git a/Lib/NativeBinaries/x86/git2-a2012c4.dll b/Lib/NativeBinaries/x86/git2-a2012c4.dll new file mode 100644 index 000000000..59dcdeb8e Binary files /dev/null and b/Lib/NativeBinaries/x86/git2-a2012c4.dll differ diff --git a/Lib/NativeBinaries/x86/git2-e0902fb.pdb b/Lib/NativeBinaries/x86/git2-a2012c4.pdb similarity index 53% rename from Lib/NativeBinaries/x86/git2-e0902fb.pdb rename to Lib/NativeBinaries/x86/git2-a2012c4.pdb index d466f239a..0a873ee0a 100644 Binary files a/Lib/NativeBinaries/x86/git2-e0902fb.pdb and b/Lib/NativeBinaries/x86/git2-a2012c4.pdb differ diff --git a/Lib/NativeBinaries/x86/git2-e0902fb.dll b/Lib/NativeBinaries/x86/git2-e0902fb.dll deleted file mode 100644 index b0c55e6cf..000000000 Binary files a/Lib/NativeBinaries/x86/git2-e0902fb.dll and /dev/null differ diff --git a/LibGit2Sharp.Tests/FilterFixture.cs b/LibGit2Sharp.Tests/FilterFixture.cs index 3c82e76db..ae41df4f8 100644 --- a/LibGit2Sharp.Tests/FilterFixture.cs +++ b/LibGit2Sharp.Tests/FilterFixture.cs @@ -347,6 +347,54 @@ public void WhenCheckingOutAFileFileSmudgeWritesCorrectFileToWorkingDirectory() GlobalSettings.DeregisterFilter(filter); } + [Fact] + public void FilterStreamsAreCoherent() + { + string repoPath = InitNewRepository(); + + bool? inputCanWrite = null, inputCanRead = null, inputCanSeek = null; + bool? outputCanWrite = null, outputCanRead = null, outputCanSeek = null; + + Func assertor = (input, output) => + { + inputCanRead = input.CanRead; + inputCanWrite = input.CanWrite; + inputCanSeek = input.CanSeek; + + outputCanRead = output.CanRead; + outputCanWrite = output.CanWrite; + outputCanSeek = output.CanSeek; + + return GitPassThrough; + }; + + var filter = new FakeFilter(FilterName + 18, Attribute, checkSuccess, assertor, assertor); + + GlobalSettings.RegisterFilter(filter); + + using (var repo = CreateTestRepository(repoPath)) + { + StageNewFile(repo); + } + + GlobalSettings.DeregisterFilter(filter); + + Assert.True(inputCanRead.HasValue); + Assert.True(inputCanWrite.HasValue); + Assert.True(inputCanSeek.HasValue); + Assert.True(outputCanRead.HasValue); + Assert.True(outputCanWrite.HasValue); + Assert.True(outputCanSeek.HasValue); + + Assert.True(inputCanRead.Value); + Assert.False(inputCanWrite.Value); + Assert.False(inputCanSeek.Value); + + Assert.False(outputCanRead.Value); + Assert.True(outputCanWrite.Value); + Assert.False(outputCanSeek.Value); + } + private FileInfo CheckoutFileForSmudge(string repoPath, string branchName, string content) { FileInfo expectedPath; diff --git a/LibGit2Sharp.Tests/SubstitutionCipherFilterFixture.cs b/LibGit2Sharp.Tests/SubstitutionCipherFilterFixture.cs index c214b7d9a..ea362a951 100644 --- a/LibGit2Sharp.Tests/SubstitutionCipherFilterFixture.cs +++ b/LibGit2Sharp.Tests/SubstitutionCipherFilterFixture.cs @@ -93,4 +93,4 @@ private static Blob CommitOnBranchAndReturnDatabaseBlob(Repository repo, string return blob; } } -} \ No newline at end of file +} diff --git a/LibGit2Sharp.Tests/TestHelpers/SubstitutionCipherFilter.cs b/LibGit2Sharp.Tests/TestHelpers/SubstitutionCipherFilter.cs index 11aaebdfc..c97ef23d9 100644 --- a/LibGit2Sharp.Tests/TestHelpers/SubstitutionCipherFilter.cs +++ b/LibGit2Sharp.Tests/TestHelpers/SubstitutionCipherFilter.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; namespace LibGit2Sharp.Tests.TestHelpers @@ -59,4 +58,4 @@ public static int RotateByThirteenPlaces(Stream input, Stream output) } } } -} \ No newline at end of file +} diff --git a/LibGit2Sharp/Core/GitBufReadStream.cs b/LibGit2Sharp/Core/GitBufReadStream.cs index bf9428516..a8b36d16b 100644 --- a/LibGit2Sharp/Core/GitBufReadStream.cs +++ b/LibGit2Sharp/Core/GitBufReadStream.cs @@ -10,8 +10,6 @@ namespace LibGit2Sharp.Core /// internal class GitBufReadStream : UnmanagedMemoryStream { - private readonly GitBuf gitBuf; - internal GitBufReadStream(IntPtr gitBufPointer) : this(gitBufPointer.MarshalAs()) { } @@ -21,17 +19,7 @@ private unsafe GitBufReadStream(GitBuf gitBuf) ConvertToLong(gitBuf.size), ConvertToLong(gitBuf.asize), FileAccess.Read) - { - this.gitBuf = gitBuf; - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing && gitBuf != default(GitBuf)) - gitBuf.Dispose(); - } + { } private static long ConvertToLong(UIntPtr len) { @@ -46,5 +34,15 @@ private static long ConvertToLong(UIntPtr len) return (long)len.ToUInt64(); } + + public override long Seek(long offset, SeekOrigin loc) + { + throw new NotSupportedException(); + } + + public override bool CanSeek + { + get { return false; } + } } } diff --git a/LibGit2Sharp/Core/GitBufWriteStream.cs b/LibGit2Sharp/Core/GitBufWriteStream.cs index 95bd6b8f9..daf031d8b 100644 --- a/LibGit2Sharp/Core/GitBufWriteStream.cs +++ b/LibGit2Sharp/Core/GitBufWriteStream.cs @@ -1,53 +1,91 @@ using System; using System.IO; -using System.Runtime.InteropServices; using LibGit2Sharp.Core.Handles; namespace LibGit2Sharp.Core { - /// - /// Writes data to a pointer - /// - internal class GitBufWriteStream : MemoryStream + internal class GitBufWriteStream : Stream { private readonly IntPtr gitBufPointer; internal GitBufWriteStream(IntPtr gitBufPointer) { this.gitBufPointer = gitBufPointer; + + //Preallocate the buffer + Proxy.git_buf_grow(gitBufPointer, 1024); + } + + public override void Flush() + { } - protected override void Dispose(bool disposing) + public override long Seek(long offset, SeekOrigin origin) { - if (base.CanSeek) // False if stream has already been written/closed + throw new NotSupportedException(); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + AutoGrowBuffer(count); + + Proxy.git_buf_put(gitBufPointer, buffer, offset, count); + } + + private void AutoGrowBuffer(int count) + { + var gitBuf = gitBufPointer.MarshalAs(); + + var asize = (uint)gitBuf.asize; + var size = (uint)gitBuf.size; + + var isBufferLargeEnoughToHoldTheNewData = (asize - size) > count; + var filledBufferPercentage = (100.0 * size / asize); + + if (isBufferLargeEnoughToHoldTheNewData && filledBufferPercentage < 90) { - using (var gitBuf = gitBufPointer.MarshalAs()) - { - WriteTo(gitBuf); - } + return; } - base.Dispose(disposing); + var targetSize = (uint)(1.5 * (asize + count)); + + Proxy.git_buf_grow(gitBufPointer, targetSize); } - private void WriteTo(GitBuf gitBuf) + public override bool CanRead { - Seek(0, SeekOrigin.Begin); + get { return false; } + } - var length = (int)Length; - var bytes = new byte[length]; - Read(bytes, 0, length); + public override bool CanSeek + { + get { return false; } + } - IntPtr reverseBytesPointer = Marshal.AllocHGlobal(length); - Marshal.Copy(bytes, 0, reverseBytesPointer, bytes.Length); + public override bool CanWrite + { + get { return true; } + } - var size = (UIntPtr)length; - var allocatedSize = (UIntPtr)length; - NativeMethods.git_buf_set(gitBuf, reverseBytesPointer, size); - gitBuf.size = size; - gitBuf.asize = allocatedSize; + public override long Length + { + get { throw new NotSupportedException(); } + } - Marshal.StructureToPtr(gitBuf, gitBufPointer, true); + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } } } } diff --git a/LibGit2Sharp/Core/NativeDllName.cs b/LibGit2Sharp/Core/NativeDllName.cs index 5127c4e4d..efc4c7e10 100644 --- a/LibGit2Sharp/Core/NativeDllName.cs +++ b/LibGit2Sharp/Core/NativeDllName.cs @@ -2,6 +2,6 @@ namespace LibGit2Sharp.Core { internal static class NativeDllName { - public const string Name = "git2-e0902fb"; + public const string Name = "git2-a2012c4"; } } diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index cd9a72567..8dd60b705 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -222,10 +222,10 @@ internal static extern int git_branch_remote_name( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string canonical_branch_name); [DllImport(libgit2)] - internal static extern int git_buf_grow(GitBuf buffer, UIntPtr targetSize); + internal static extern int git_buf_grow(IntPtr buffer, UIntPtr targetSize); [DllImport(libgit2)] - internal static extern int git_buf_set(GitBuf buffer, IntPtr data, UIntPtr targetSize); + internal static extern int git_buf_put(IntPtr buffer, IntPtr data, UIntPtr len); [DllImport(libgit2)] internal static extern int git_remote_rename( diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index d8bbd3b7f..41466eefd 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -241,6 +241,33 @@ public static string git_branch_upstream_name(RepositorySafeHandle handle, strin #region git_buf_ + public static void git_buf_grow(IntPtr gitBufPointer, uint target_size) + { + using (ThreadAffinity()) + { + var res = NativeMethods.git_buf_grow(gitBufPointer, (UIntPtr)target_size); + Ensure.ZeroResult(res); + } + } + + public static void git_buf_put(IntPtr gitBufPointer, byte[] data, int offset, int count) + { + using (ThreadAffinity()) + { + unsafe + { + int res; + + fixed (byte* ptr = data) + { + res = NativeMethods.git_buf_put(gitBufPointer, (IntPtr)ptr, (UIntPtr)count); + } + + Ensure.ZeroResult(res); + } + } + } + public static void git_buf_free(GitBuf buf) { NativeMethods.git_buf_free(buf); diff --git a/LibGit2Sharp/Filter.cs b/LibGit2Sharp/Filter.cs index fd49d53b6..a6e7f03fb 100644 --- a/LibGit2Sharp/Filter.cs +++ b/LibGit2Sharp/Filter.cs @@ -23,7 +23,7 @@ public abstract class Filter : IEquatable /// /// Initializes a new instance of the class. - /// And allocates the filter natively. + /// And allocates the filter natively. /// The unique name with which this filtered is registered with /// A list of filterForAttributes which this filter applies to /// @@ -33,7 +33,7 @@ protected Filter(string name, IEnumerable attributes) /// /// Initializes a new instance of the class. - /// And allocates the filter natively. + /// And allocates the filter natively. /// The unique name with which this filtered is registered with /// Either a single attribute, or a comma separated list of filterForAttributes for which this filter applies to /// @@ -87,10 +87,10 @@ internal GitFilter ManagedFilter /// /// Initialize callback on filter - /// + /// /// Specified as `filter.initialize`, this is an optional callback invoked /// before a filter is first used. It will be called once at most. - /// + /// /// If non-NULL, the filter's `initialize` callback will be invoked right /// before the first use of the filter, so you can defer expensive /// initialization operations (in case libgit2 is being used in a way that doesn't need the filter). @@ -191,10 +191,10 @@ public override int GetHashCode() /// /// Initialize callback on filter - /// + /// /// Specified as `filter.initialize`, this is an optional callback invoked /// before a filter is first used. It will be called once at most. - /// + /// /// If non-NULL, the filter's `initialize` callback will be invoked right /// before the first use of the filter, so you can defer expensive /// initialization operations (in case libgit2 is being used in a way that doesn't need the filter). @@ -207,15 +207,15 @@ int InitializeCallback(IntPtr gitFilter) /// /// Callback to decide if a given source needs this filter /// Specified as `filter.check`, this is an optional callback that checks if filtering is needed for a given source. - /// - /// It should return 0 if the filter should be applied (i.e. success), GIT_PASSTHROUGH if the filter should + /// + /// It should return 0 if the filter should be applied (i.e. success), GIT_PASSTHROUGH if the filter should /// not be applied, or an error code to fail out of the filter processing pipeline and return to the caller. - /// + /// /// The `attr_values` will be set to the values of any filterForAttributes given in the filter definition. See `git_filter` below for more detail. - /// - /// The `payload` will be a pointer to a reference payload for the filter. This will start as NULL, but `check` can assign to this + /// + /// The `payload` will be a pointer to a reference payload for the filter. This will start as NULL, but `check` can assign to this /// pointer for later use by the `apply` callback. Note that the value should be heap allocated (not stack), so that it doesn't go - /// away before the `apply` callback can use it. If a filter allocates and assigns a value to the `payload`, it will need a `cleanup` + /// away before the `apply` callback can use it. If a filter allocates and assigns a value to the `payload`, it will need a `cleanup` /// callback to free the payload. /// /// @@ -230,12 +230,12 @@ int CheckCallback(GitFilter gitFilter, IntPtr payload, IntPtr filterSourcePtr, I /// /// Callback to actually perform the data filtering - /// - /// Specified as `filter.apply`, this is the callback that actually filters data. + /// + /// Specified as `filter.apply`, this is the callback that actually filters data. /// If it successfully writes the output, it should return 0. Like `check`, - /// it can return GIT_PASSTHROUGH to indicate that the filter doesn't want to run. + /// it can return GIT_PASSTHROUGH to indicate that the filter doesn't want to run. /// Other error codes will stop filter processing and return to the caller. - /// + /// /// The `payload` value will refer to any payload that was set by the `check` callback. It may be read from or written to as needed. /// int ApplyCallback(GitFilter gitFilter, IntPtr payload, @@ -251,4 +251,4 @@ int ApplyCallback(GitFilter gitFilter, IntPtr payload, } } } -} \ No newline at end of file +} diff --git a/LibGit2Sharp/libgit2_hash.txt b/LibGit2Sharp/libgit2_hash.txt index 4a8fde8aa..f35b5ca25 100644 --- a/LibGit2Sharp/libgit2_hash.txt +++ b/LibGit2Sharp/libgit2_hash.txt @@ -1 +1 @@ -e0902fbce7d14631bd02091c1c70cde3e68f78ab +a2012c43899e6616366b47d7741b3f035e825e84 diff --git a/libgit2 b/libgit2 index e0902fbce..a2012c438 160000 --- a/libgit2 +++ b/libgit2 @@ -1 +1 @@ -Subproject commit e0902fbce7d14631bd02091c1c70cde3e68f78ab +Subproject commit a2012c43899e6616366b47d7741b3f035e825e84 diff --git a/nuget.package/build/LibGit2Sharp.props b/nuget.package/build/LibGit2Sharp.props index 8ffc28d6e..85e0a5907 100644 --- a/nuget.package/build/LibGit2Sharp.props +++ b/nuget.package/build/LibGit2Sharp.props @@ -1,20 +1,20 @@  - - NativeBinaries\amd64\git2-e0902fb.dll + + NativeBinaries\amd64\git2-a2012c4.dll PreserveNewest - - NativeBinaries\amd64\git2-e0902fb.pdb + + NativeBinaries\amd64\git2-a2012c4.pdb PreserveNewest - - NativeBinaries\x86\git2-e0902fb.dll + + NativeBinaries\x86\git2-a2012c4.dll PreserveNewest - - NativeBinaries\x86\git2-e0902fb.pdb + + NativeBinaries\x86\git2-a2012c4.pdb PreserveNewest