Skip to content

Commit 21a6381

Browse files
committed
Merge pull request #948 from libgit2/ntk/filters_stream_rebound
Filters stream rebound
2 parents 4a0ddd1 + 10df3b1 commit 21a6381

18 files changed

+181
-71
lines changed
983 KB
Binary file not shown.
-981 KB
Binary file not shown.
746 KB
Binary file not shown.
-745 KB
Binary file not shown.

LibGit2Sharp.Tests/FilterFixture.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,54 @@ public void WhenCheckingOutAFileFileSmudgeWritesCorrectFileToWorkingDirectory()
347347
GlobalSettings.DeregisterFilter(filter);
348348
}
349349

350+
[Fact]
351+
public void FilterStreamsAreCoherent()
352+
{
353+
string repoPath = InitNewRepository();
354+
355+
bool? inputCanWrite = null, inputCanRead = null, inputCanSeek = null;
356+
bool? outputCanWrite = null, outputCanRead = null, outputCanSeek = null;
357+
358+
Func<Stream, Stream, int> assertor = (input, output) =>
359+
{
360+
inputCanRead = input.CanRead;
361+
inputCanWrite = input.CanWrite;
362+
inputCanSeek = input.CanSeek;
363+
364+
outputCanRead = output.CanRead;
365+
outputCanWrite = output.CanWrite;
366+
outputCanSeek = output.CanSeek;
367+
368+
return GitPassThrough;
369+
};
370+
371+
var filter = new FakeFilter(FilterName + 18, Attribute, checkSuccess, assertor, assertor);
372+
373+
GlobalSettings.RegisterFilter(filter);
374+
375+
using (var repo = CreateTestRepository(repoPath))
376+
{
377+
StageNewFile(repo);
378+
}
379+
380+
GlobalSettings.DeregisterFilter(filter);
381+
382+
Assert.True(inputCanRead.HasValue);
383+
Assert.True(inputCanWrite.HasValue);
384+
Assert.True(inputCanSeek.HasValue);
385+
Assert.True(outputCanRead.HasValue);
386+
Assert.True(outputCanWrite.HasValue);
387+
Assert.True(outputCanSeek.HasValue);
388+
389+
Assert.True(inputCanRead.Value);
390+
Assert.False(inputCanWrite.Value);
391+
Assert.False(inputCanSeek.Value);
392+
393+
Assert.False(outputCanRead.Value);
394+
Assert.True(outputCanWrite.Value);
395+
Assert.False(outputCanSeek.Value);
396+
}
397+
350398
private FileInfo CheckoutFileForSmudge(string repoPath, string branchName, string content)
351399
{
352400
FileInfo expectedPath;

LibGit2Sharp.Tests/SubstitutionCipherFilterFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,4 @@ private static Blob CommitOnBranchAndReturnDatabaseBlob(Repository repo, string
9393
return blob;
9494
}
9595
}
96-
}
96+
}

LibGit2Sharp.Tests/TestHelpers/SubstitutionCipherFilter.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using System.Collections.Generic;
22
using System.IO;
3-
using System.Linq;
43
using System.Text;
54

65
namespace LibGit2Sharp.Tests.TestHelpers
@@ -59,4 +58,4 @@ public static int RotateByThirteenPlaces(Stream input, Stream output)
5958
}
6059
}
6160
}
62-
}
61+
}

LibGit2Sharp/Core/GitBufReadStream.cs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ namespace LibGit2Sharp.Core
1010
/// </summary>
1111
internal class GitBufReadStream : UnmanagedMemoryStream
1212
{
13-
private readonly GitBuf gitBuf;
14-
1513
internal GitBufReadStream(IntPtr gitBufPointer)
1614
: this(gitBufPointer.MarshalAs<GitBuf>())
1715
{ }
@@ -21,17 +19,7 @@ private unsafe GitBufReadStream(GitBuf gitBuf)
2119
ConvertToLong(gitBuf.size),
2220
ConvertToLong(gitBuf.asize),
2321
FileAccess.Read)
24-
{
25-
this.gitBuf = gitBuf;
26-
}
27-
28-
protected override void Dispose(bool disposing)
29-
{
30-
base.Dispose(disposing);
31-
32-
if (disposing && gitBuf != default(GitBuf))
33-
gitBuf.Dispose();
34-
}
22+
{ }
3523

3624
private static long ConvertToLong(UIntPtr len)
3725
{
@@ -46,5 +34,15 @@ private static long ConvertToLong(UIntPtr len)
4634

4735
return (long)len.ToUInt64();
4836
}
37+
38+
public override long Seek(long offset, SeekOrigin loc)
39+
{
40+
throw new NotSupportedException();
41+
}
42+
43+
public override bool CanSeek
44+
{
45+
get { return false; }
46+
}
4947
}
5048
}
Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,91 @@
11
using System;
22
using System.IO;
3-
using System.Runtime.InteropServices;
43
using LibGit2Sharp.Core.Handles;
54

65
namespace LibGit2Sharp.Core
76
{
8-
/// <summary>
9-
/// Writes data to a <see cref="GitBuf"/> pointer
10-
/// </summary>
11-
internal class GitBufWriteStream : MemoryStream
7+
internal class GitBufWriteStream : Stream
128
{
139
private readonly IntPtr gitBufPointer;
1410

1511
internal GitBufWriteStream(IntPtr gitBufPointer)
1612
{
1713
this.gitBufPointer = gitBufPointer;
14+
15+
//Preallocate the buffer
16+
Proxy.git_buf_grow(gitBufPointer, 1024);
17+
}
18+
19+
public override void Flush()
20+
{
1821
}
1922

20-
protected override void Dispose(bool disposing)
23+
public override long Seek(long offset, SeekOrigin origin)
2124
{
22-
if (base.CanSeek) // False if stream has already been written/closed
25+
throw new NotSupportedException();
26+
}
27+
28+
public override void SetLength(long value)
29+
{
30+
throw new NotSupportedException();
31+
}
32+
33+
public override int Read(byte[] buffer, int offset, int count)
34+
{
35+
throw new NotSupportedException();
36+
}
37+
38+
public override void Write(byte[] buffer, int offset, int count)
39+
{
40+
AutoGrowBuffer(count);
41+
42+
Proxy.git_buf_put(gitBufPointer, buffer, offset, count);
43+
}
44+
45+
private void AutoGrowBuffer(int count)
46+
{
47+
var gitBuf = gitBufPointer.MarshalAs<GitBuf>();
48+
49+
var asize = (uint)gitBuf.asize;
50+
var size = (uint)gitBuf.size;
51+
52+
var isBufferLargeEnoughToHoldTheNewData = (asize - size) > count;
53+
var filledBufferPercentage = (100.0 * size / asize);
54+
55+
if (isBufferLargeEnoughToHoldTheNewData && filledBufferPercentage < 90)
2356
{
24-
using (var gitBuf = gitBufPointer.MarshalAs<GitBuf>())
25-
{
26-
WriteTo(gitBuf);
27-
}
57+
return;
2858
}
2959

30-
base.Dispose(disposing);
60+
var targetSize = (uint)(1.5 * (asize + count));
61+
62+
Proxy.git_buf_grow(gitBufPointer, targetSize);
3163
}
3264

33-
private void WriteTo(GitBuf gitBuf)
65+
public override bool CanRead
3466
{
35-
Seek(0, SeekOrigin.Begin);
67+
get { return false; }
68+
}
3669

37-
var length = (int)Length;
38-
var bytes = new byte[length];
39-
Read(bytes, 0, length);
70+
public override bool CanSeek
71+
{
72+
get { return false; }
73+
}
4074

41-
IntPtr reverseBytesPointer = Marshal.AllocHGlobal(length);
42-
Marshal.Copy(bytes, 0, reverseBytesPointer, bytes.Length);
75+
public override bool CanWrite
76+
{
77+
get { return true; }
78+
}
4379

44-
var size = (UIntPtr)length;
45-
var allocatedSize = (UIntPtr)length;
46-
NativeMethods.git_buf_set(gitBuf, reverseBytesPointer, size);
47-
gitBuf.size = size;
48-
gitBuf.asize = allocatedSize;
80+
public override long Length
81+
{
82+
get { throw new NotSupportedException(); }
83+
}
4984

50-
Marshal.StructureToPtr(gitBuf, gitBufPointer, true);
85+
public override long Position
86+
{
87+
get { throw new NotSupportedException(); }
88+
set { throw new NotSupportedException(); }
5189
}
5290
}
5391
}

LibGit2Sharp/Core/NativeDllName.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ namespace LibGit2Sharp.Core
22
{
33
internal static class NativeDllName
44
{
5-
public const string Name = "git2-e0902fb";
5+
public const string Name = "git2-a2012c4";
66
}
77
}

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,10 @@ internal static extern int git_branch_remote_name(
222222
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string canonical_branch_name);
223223

224224
[DllImport(libgit2)]
225-
internal static extern int git_buf_grow(GitBuf buffer, UIntPtr targetSize);
225+
internal static extern int git_buf_grow(IntPtr buffer, UIntPtr targetSize);
226226

227227
[DllImport(libgit2)]
228-
internal static extern int git_buf_set(GitBuf buffer, IntPtr data, UIntPtr targetSize);
228+
internal static extern int git_buf_put(IntPtr buffer, IntPtr data, UIntPtr len);
229229

230230
[DllImport(libgit2)]
231231
internal static extern int git_remote_rename(

LibGit2Sharp/Core/Proxy.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,33 @@ public static string git_branch_upstream_name(RepositorySafeHandle handle, strin
241241

242242
#region git_buf_
243243

244+
public static void git_buf_grow(IntPtr gitBufPointer, uint target_size)
245+
{
246+
using (ThreadAffinity())
247+
{
248+
var res = NativeMethods.git_buf_grow(gitBufPointer, (UIntPtr)target_size);
249+
Ensure.ZeroResult(res);
250+
}
251+
}
252+
253+
public static void git_buf_put(IntPtr gitBufPointer, byte[] data, int offset, int count)
254+
{
255+
using (ThreadAffinity())
256+
{
257+
unsafe
258+
{
259+
int res;
260+
261+
fixed (byte* ptr = data)
262+
{
263+
res = NativeMethods.git_buf_put(gitBufPointer, (IntPtr)ptr, (UIntPtr)count);
264+
}
265+
266+
Ensure.ZeroResult(res);
267+
}
268+
}
269+
}
270+
244271
public static void git_buf_free(GitBuf buf)
245272
{
246273
NativeMethods.git_buf_free(buf);

LibGit2Sharp/Filter.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public abstract class Filter : IEquatable<Filter>
2323

2424
/// <summary>
2525
/// Initializes a new instance of the <see cref="Filter"/> class.
26-
/// And allocates the filter natively.
26+
/// And allocates the filter natively.
2727
/// <param name="name">The unique name with which this filtered is registered with</param>
2828
/// <param name="attributes">A list of filterForAttributes which this filter applies to</param>
2929
/// </summary>
@@ -33,7 +33,7 @@ protected Filter(string name, IEnumerable<string> attributes)
3333

3434
/// <summary>
3535
/// Initializes a new instance of the <see cref="Filter"/> class.
36-
/// And allocates the filter natively.
36+
/// And allocates the filter natively.
3737
/// <param name="name">The unique name with which this filtered is registered with</param>
3838
/// <param name="attributes">Either a single attribute, or a comma separated list of filterForAttributes for which this filter applies to</param>
3939
/// </summary>
@@ -87,10 +87,10 @@ internal GitFilter ManagedFilter
8787

8888
/// <summary>
8989
/// Initialize callback on filter
90-
///
90+
///
9191
/// Specified as `filter.initialize`, this is an optional callback invoked
9292
/// before a filter is first used. It will be called once at most.
93-
///
93+
///
9494
/// If non-NULL, the filter's `initialize` callback will be invoked right
9595
/// before the first use of the filter, so you can defer expensive
9696
/// 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()
191191

192192
/// <summary>
193193
/// Initialize callback on filter
194-
///
194+
///
195195
/// Specified as `filter.initialize`, this is an optional callback invoked
196196
/// before a filter is first used. It will be called once at most.
197-
///
197+
///
198198
/// If non-NULL, the filter's `initialize` callback will be invoked right
199199
/// before the first use of the filter, so you can defer expensive
200200
/// 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)
207207
/// <summary>
208208
/// Callback to decide if a given source needs this filter
209209
/// Specified as `filter.check`, this is an optional callback that checks if filtering is needed for a given source.
210-
///
211-
/// It should return 0 if the filter should be applied (i.e. success), GIT_PASSTHROUGH if the filter should
210+
///
211+
/// It should return 0 if the filter should be applied (i.e. success), GIT_PASSTHROUGH if the filter should
212212
/// not be applied, or an error code to fail out of the filter processing pipeline and return to the caller.
213-
///
213+
///
214214
/// The `attr_values` will be set to the values of any filterForAttributes given in the filter definition. See `git_filter` below for more detail.
215-
///
216-
/// The `payload` will be a pointer to a reference payload for the filter. This will start as NULL, but `check` can assign to this
215+
///
216+
/// The `payload` will be a pointer to a reference payload for the filter. This will start as NULL, but `check` can assign to this
217217
/// pointer for later use by the `apply` callback. Note that the value should be heap allocated (not stack), so that it doesn't go
218-
/// away before the `apply` callback can use it. If a filter allocates and assigns a value to the `payload`, it will need a `cleanup`
218+
/// away before the `apply` callback can use it. If a filter allocates and assigns a value to the `payload`, it will need a `cleanup`
219219
/// callback to free the payload.
220220
/// </summary>
221221
/// <returns></returns>
@@ -230,12 +230,12 @@ int CheckCallback(GitFilter gitFilter, IntPtr payload, IntPtr filterSourcePtr, I
230230

231231
/// <summary>
232232
/// Callback to actually perform the data filtering
233-
///
234-
/// Specified as `filter.apply`, this is the callback that actually filters data.
233+
///
234+
/// Specified as `filter.apply`, this is the callback that actually filters data.
235235
/// If it successfully writes the output, it should return 0. Like `check`,
236-
/// it can return GIT_PASSTHROUGH to indicate that the filter doesn't want to run.
236+
/// it can return GIT_PASSTHROUGH to indicate that the filter doesn't want to run.
237237
/// Other error codes will stop filter processing and return to the caller.
238-
///
238+
///
239239
/// 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.
240240
/// </summary>
241241
int ApplyCallback(GitFilter gitFilter, IntPtr payload,
@@ -251,4 +251,4 @@ int ApplyCallback(GitFilter gitFilter, IntPtr payload,
251251
}
252252
}
253253
}
254-
}
254+
}

LibGit2Sharp/libgit2_hash.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
e0902fbce7d14631bd02091c1c70cde3e68f78ab
1+
a2012c43899e6616366b47d7741b3f035e825e84

0 commit comments

Comments
 (0)