Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sftp file stream should consider negative offsets in Seek #1020

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 24 additions & 16 deletions src/Renci.SshNet/Sftp/SftpFileStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#if FEATURE_TAP
using System.Threading.Tasks;
#endif
using System.Reflection;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this for?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dummy change, will remove it


namespace Renci.SshNet.Sftp
{
Expand Down Expand Up @@ -283,8 +284,8 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc
// that ensures we always receive or send the max. number of bytes in a single SSH_FXP_READ
// or SSH_FXP_WRITE message

_readBufferSize = (int) session.CalculateOptimalReadLength((uint) bufferSize);
_writeBufferSize = (int) session.CalculateOptimalWriteLength((uint) bufferSize, _handle);
_readBufferSize = (int)session.CalculateOptimalReadLength((uint)bufferSize);
_writeBufferSize = (int)session.CalculateOptimalWriteLength((uint)bufferSize, _handle);

if (mode == FileMode.Append)
{
Expand Down Expand Up @@ -381,7 +382,7 @@ internal static async Task<SftpFileStream> OpenAsync(ISftpSession session, strin
await session.RequestCloseAsync(handle, cancellationToken).ConfigureAwait(false);
}
catch
{
{
// The original exception is presumably more informative, so we just ignore this one.
}
throw;
Expand Down Expand Up @@ -509,7 +510,7 @@ public override int Read(byte[] buffer, int offset, int count)
var bytesAvailableInBuffer = _bufferLen - _bufferPosition;
if (bytesAvailableInBuffer <= 0)
{
var data = _session.RequestRead(_handle, (ulong) _position, (uint) _readBufferSize);
var data = _session.RequestRead(_handle, (ulong)_position, (uint)_readBufferSize);

if (data.Length == 0)
{
Expand Down Expand Up @@ -726,7 +727,7 @@ public override int ReadByte()
// Read more data into the internal buffer if necessary.
if (_bufferPosition >= _bufferLen)
{
var data = _session.RequestRead(_handle, (ulong) _position, (uint) _readBufferSize);
var data = _session.RequestRead(_handle, (ulong)_position, (uint)_readBufferSize);
if (data.Length == 0)
{
// We've reached EOF.
Expand Down Expand Up @@ -783,6 +784,8 @@ public override long Seek(long offset, SeekOrigin origin)
return _position;
}

var attributes = (SftpFileAttributes)null;

// The behaviour depends upon the read/write mode.
if (_bufferOwnedByWrite)
{
Expand All @@ -798,15 +801,16 @@ public override long Seek(long offset, SeekOrigin origin)
newPosn = _position + offset;
break;
case SeekOrigin.End:
var attributes = _session.RequestFStat(_handle, false);
newPosn = attributes.Size - offset;
attributes = _session.RequestFStat(_handle, false);
newPosn = attributes.Size + offset;
break;
}

if (newPosn == -1)
if (newPosn == -1 || (attributes != null && newPosn > attributes.Size))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seeking past the end of file when writing is valid, it's a way to extend the file size.

{
throw new EndOfStreamException("End of stream.");
}

_position = newPosn;
}
else
Expand All @@ -829,7 +833,7 @@ public override long Seek(long offset, SeekOrigin origin)
if (newPosn >= (_position - _bufferPosition) &&
newPosn < (_position - _bufferPosition + _bufferLen))
{
_bufferPosition = (int) (newPosn - (_position - _bufferPosition));
_bufferPosition = (int)(newPosn - (_position - _bufferPosition));
_position = newPosn;
return _position;
}
Expand All @@ -849,12 +853,16 @@ public override long Seek(long offset, SeekOrigin origin)
newPosn = _position + offset;
break;
case SeekOrigin.End:
var attributes = _session.RequestFStat(_handle, false);
newPosn = attributes.Size - offset;
if (attributes == null)
{
attributes = _session.RequestFStat(_handle, false);
}

newPosn = attributes.Size + offset;
break;
}

if (newPosn < 0)
if (newPosn < 0 || (attributes != null && newPosn > attributes.Size))
{
throw new EndOfStreamException();
}
Expand Down Expand Up @@ -974,7 +982,7 @@ public override void Write(byte[] buffer, int offset, int count)
{
using (var wait = new AutoResetEvent(false))
{
_session.RequestWrite(_handle, (ulong) _position, buffer, offset, tempLen, wait);
_session.RequestWrite(_handle, (ulong)_position, buffer, offset, tempLen, wait);
}
}
else
Expand All @@ -996,7 +1004,7 @@ public override void Write(byte[] buffer, int offset, int count)
{
using (var wait = new AutoResetEvent(false))
{
_session.RequestWrite(_handle, (ulong) (_position - _bufferPosition), GetOrCreateWriteBuffer(), 0, _bufferPosition, wait);
_session.RequestWrite(_handle, (ulong)(_position - _bufferPosition), GetOrCreateWriteBuffer(), 0, _bufferPosition, wait);
}

_bufferPosition = 0;
Expand Down Expand Up @@ -1106,7 +1114,7 @@ public override void WriteByte(byte value)
{
using (var wait = new AutoResetEvent(false))
{
_session.RequestWrite(_handle, (ulong) (_position - _bufferPosition), writeBuffer, 0, _bufferPosition, wait);
_session.RequestWrite(_handle, (ulong)(_position - _bufferPosition), writeBuffer, 0, _bufferPosition, wait);
}

_bufferPosition = 0;
Expand Down Expand Up @@ -1192,7 +1200,7 @@ private void FlushWriteBuffer()
{
using (var wait = new AutoResetEvent(false))
{
_session.RequestWrite(_handle, (ulong) (_position - _bufferPosition), _writeBuffer, 0, _bufferPosition, wait);
_session.RequestWrite(_handle, (ulong)(_position - _bufferPosition), _writeBuffer, 0, _bufferPosition, wait);
}

_bufferPosition = 0;
Expand Down