Skip to content

Commit 98aba49

Browse files
committed
Only copy the actual number of bytes received to the buffer.
Fixes issue #173.
1 parent c392766 commit 98aba49

File tree

4 files changed

+197
-1
lines changed

4 files changed

+197
-1
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using System;
2+
using System.Globalization;
3+
using System.IO;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
using Moq;
6+
using Renci.SshNet.Sftp;
7+
8+
namespace Renci.SshNet.Tests.Classes.Sftp
9+
{
10+
[TestClass]
11+
public class SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof
12+
{
13+
private Mock<ISftpSession> _sftpSessionMock;
14+
private string _path;
15+
private SftpFileStream _sftpFileStream;
16+
private byte[] _handle;
17+
private SftpFileAttributes _fileAttributes;
18+
private uint _bufferSize;
19+
private uint _readBufferSize;
20+
private uint _writeBufferSize;
21+
private int _actual;
22+
private MockSequence _sequence;
23+
24+
[TestInitialize]
25+
public void Setup()
26+
{
27+
Arrange();
28+
Act();
29+
}
30+
31+
public void TearDown()
32+
{
33+
_sftpSessionMock.InSequence(_sequence)
34+
.Setup(p => p.RequestClose(_handle));
35+
}
36+
37+
protected void Arrange()
38+
{
39+
var random = new Random();
40+
_path = random.Next().ToString(CultureInfo.InvariantCulture);
41+
_handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)};
42+
_fileAttributes = SftpFileAttributes.Empty;
43+
_bufferSize = (uint)random.Next(1, 1000);
44+
_readBufferSize = (uint)random.Next(0, 1000);
45+
_writeBufferSize = (uint)random.Next(0, 1000);
46+
47+
_sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
48+
49+
_sequence = new MockSequence();
50+
51+
_sftpSessionMock.InSequence(_sequence)
52+
.Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
53+
.Returns(_handle);
54+
_sftpSessionMock.InSequence(_sequence).Setup(p => p.RequestFStat(_handle, false))
55+
.Returns(_fileAttributes);
56+
_sftpSessionMock.InSequence(_sequence)
57+
.Setup(p => p.CalculateOptimalReadLength(_bufferSize))
58+
.Returns(_readBufferSize);
59+
_sftpSessionMock.InSequence(_sequence)
60+
.Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
61+
.Returns(_writeBufferSize);
62+
_sftpSessionMock.InSequence(_sequence)
63+
.Setup(p => p.IsOpen)
64+
.Returns(true);
65+
_sftpSessionMock.InSequence(_sequence)
66+
.Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
67+
.Returns(new byte[0]);
68+
69+
_sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
70+
}
71+
72+
protected void Act()
73+
{
74+
_actual = _sftpFileStream.ReadByte();
75+
}
76+
77+
[TestMethod]
78+
public void ReadByteShouldReturnMinusOne()
79+
{
80+
Assert.AreEqual(-1, _actual);
81+
}
82+
83+
[TestMethod]
84+
public void PositionShouldReturnZero()
85+
{
86+
_sftpSessionMock.InSequence(_sequence)
87+
.Setup(p => p.IsOpen)
88+
.Returns(true);
89+
90+
Assert.AreEqual(0L, _sftpFileStream.Position);
91+
}
92+
}
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
using System;
2+
using System.Globalization;
3+
using System.IO;
4+
using Microsoft.VisualStudio.TestTools.UnitTesting;
5+
using Moq;
6+
using Renci.SshNet.Abstractions;
7+
using Renci.SshNet.Sftp;
8+
9+
namespace Renci.SshNet.Tests.Classes.Sftp
10+
{
11+
/// <summary>
12+
/// Test for issue #173.
13+
/// </summary>
14+
[TestClass]
15+
public class SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable
16+
{
17+
private Mock<ISftpSession> _sftpSessionMock;
18+
private string _path;
19+
private SftpFileStream _sftpFileStream;
20+
private byte[] _handle;
21+
private SftpFileAttributes _fileAttributes;
22+
private uint _bufferSize;
23+
private uint _readBufferSize;
24+
private uint _writeBufferSize;
25+
private int _actual;
26+
private byte[] _data;
27+
private MockSequence _sequence;
28+
29+
[TestInitialize]
30+
public void Setup()
31+
{
32+
Arrange();
33+
Act();
34+
}
35+
36+
public void TearDown()
37+
{
38+
_sftpSessionMock.InSequence(_sequence)
39+
.Setup(p => p.RequestClose(_handle));
40+
}
41+
42+
protected void Arrange()
43+
{
44+
var random = new Random();
45+
_path = random.Next().ToString(CultureInfo.InvariantCulture);
46+
_handle = new[] { (byte)random.Next(byte.MinValue, byte.MaxValue) };
47+
_fileAttributes = SftpFileAttributes.Empty;
48+
_bufferSize = (uint) random.Next(5, 1000);
49+
_readBufferSize = (uint) random.Next(10, 100);
50+
_writeBufferSize = (uint) random.Next(10, 100);
51+
_data = new byte[_readBufferSize - 2];
52+
CryptoAbstraction.GenerateRandom(_data);
53+
54+
_sftpSessionMock = new Mock<ISftpSession>(MockBehavior.Strict);
55+
56+
_sequence = new MockSequence();
57+
58+
_sftpSessionMock.InSequence(_sequence)
59+
.Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Truncate, true))
60+
.Returns(_handle);
61+
_sftpSessionMock.InSequence(_sequence).Setup(p => p.RequestFStat(_handle, false))
62+
.Returns(_fileAttributes);
63+
_sftpSessionMock.InSequence(_sequence)
64+
.Setup(p => p.CalculateOptimalReadLength(_bufferSize))
65+
.Returns(_readBufferSize);
66+
_sftpSessionMock.InSequence(_sequence)
67+
.Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle))
68+
.Returns(_writeBufferSize);
69+
_sftpSessionMock.InSequence(_sequence)
70+
.Setup(p => p.IsOpen)
71+
.Returns(true);
72+
_sftpSessionMock.InSequence(_sequence)
73+
.Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize))
74+
.Returns(_data);
75+
76+
_sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Create, FileAccess.Read, (int)_bufferSize);
77+
}
78+
79+
protected void Act()
80+
{
81+
_actual = _sftpFileStream.ReadByte();
82+
}
83+
84+
[TestMethod]
85+
public void ReadByteShouldReturnFirstByteThatWasReadFromServer()
86+
{
87+
Assert.AreEqual(_data[0], _actual);
88+
}
89+
90+
[TestMethod]
91+
public void PositionShouldReturnOne()
92+
{
93+
_sftpSessionMock.InSequence(_sequence)
94+
.Setup(p => p.IsOpen)
95+
.Returns(true);
96+
97+
Assert.AreEqual(1L, _sftpFileStream.Position);
98+
}
99+
}
100+
}

src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,13 +417,15 @@
417417
<Compile Include="Classes\Sftp\Responses\SftpVersionResponseTest.cs" />
418418
<Compile Include="Classes\Sftp\SftpFileStreamTest_Dispose_Disposed.cs" />
419419
<Compile Include="Classes\Sftp\SftpFileStreamTest_Finalize_SessionOpen.cs" />
420+
<Compile Include="Classes\Sftp\SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs" />
420421
<Compile Include="Classes\Sftp\SftpFileStreamTest_SetLength_Closed.cs" />
421422
<Compile Include="Classes\Sftp\SftpFileStreamTest_SetLength_Disposed.cs" />
422423
<Compile Include="Classes\Sftp\SftpFileStreamTest_SetLength_SessionNotOpen.cs" />
423424
<Compile Include="Classes\Sftp\SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs" />
424425
<Compile Include="Classes\Sftp\SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs" />
425426
<Compile Include="Classes\Sftp\SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs" />
426427
<Compile Include="Classes\Sftp\SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs" />
428+
<Compile Include="Classes\Sftp\SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs" />
427429
<Compile Include="Classes\Sftp\SftpFileTest.cs" />
428430
<Compile Include="Classes\Sftp\SftpSessionTest_Connected_RequestRead.cs" />
429431
<Compile Include="Classes\Sftp\SftpSessionTest_Connected_RequestStatVfs.cs" />

src/Renci.SshNet/Sftp/SftpFileStream.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,14 +397,15 @@ public override int ReadByte()
397397
var data = _session.RequestRead(_handle, (ulong)_position, (uint)_readBufferSize);
398398

399399
_bufferLen = data.Length;
400-
Buffer.BlockCopy(data, 0, _readBuffer, 0, _readBufferSize);
401400
_serverFilePosition = (ulong)_position;
402401

403402
if (_bufferLen == 0)
404403
{
405404
// We've reached EOF.
406405
return -1;
407406
}
407+
408+
Buffer.BlockCopy(data, 0, _readBuffer, 0, _bufferLen);
408409
}
409410

410411
// Extract the next byte from the buffer.

0 commit comments

Comments
 (0)