SftpSession
Represents an SFTP session.
using Renci.SshNet.Common;
using Renci.SshNet.Sftp.Requests;
using Renci.SshNet.Sftp.Responses;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Renci.SshNet.Sftp
{
internal sealed class SftpSession : SubsystemSession, ISftpSession, ISubsystemSession, IDisposable
{
internal const int MaximumSupportedVersion = 3;
private const int MinimumSupportedVersion = 0;
private readonly Dictionary<uint, SftpRequest> _requests = new Dictionary<uint, SftpRequest>();
private readonly ISftpResponseFactory _sftpResponseFactory;
private readonly Encoding _encoding;
private System.Net.ArrayBuffer _buffer = new System.Net.ArrayBuffer(32768, false);
private EventWaitHandle _sftpVersionConfirmed = new AutoResetEvent(false);
private IDictionary<string, string> _supportedExtensions;
private long _requestId;
public string WorkingDirectory { get; set; }
public uint ProtocolVersion { get; set; }
public uint NextRequestId => (uint)Interlocked.Increment(ref _requestId);
public SftpSession(ISession session, int operationTimeout, Encoding encoding, ISftpResponseFactory sftpResponseFactory)
: base(session, "sftp", operationTimeout)
{
_encoding = encoding;
_sftpResponseFactory = sftpResponseFactory;
}
public void ChangeDirectory(string path)
{
string canonicalPath = GetCanonicalPath(path);
byte[] handle = RequestOpenDir(canonicalPath);
RequestClose(handle);
WorkingDirectory = canonicalPath;
}
[AsyncStateMachine(typeof(<ChangeDirectoryAsync>d__21))]
public Task ChangeDirectoryAsync(string path, CancellationToken cancellationToken)
{
<ChangeDirectoryAsync>d__21 stateMachine = default(<ChangeDirectoryAsync>d__21);
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>4__this = this;
stateMachine.path = path;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
internal void SendMessage(SftpMessage sftpMessage)
{
byte[] bytes = sftpMessage.GetBytes();
SendData(bytes);
}
public string GetCanonicalPath(string path)
{
string fullRemotePath = GetFullRemotePath(path);
string text = string.Empty;
KeyValuePair<string, SftpFileAttributes>[] array = RequestRealPath(fullRemotePath, true);
if (array != null)
text = array[0].Key;
if (!string.IsNullOrEmpty(text))
return text;
if (fullRemotePath.EndsWith("/.", StringComparison.OrdinalIgnoreCase) || fullRemotePath.EndsWith("/..", StringComparison.OrdinalIgnoreCase) || fullRemotePath.Equals("/", StringComparison.OrdinalIgnoreCase) || fullRemotePath.IndexOf('/') < 0)
return fullRemotePath;
string[] array2 = fullRemotePath.Split(new char[1] {
'/'
});
string text2 = string.Join("/", array2, 0, array2.Length - 1);
if (string.IsNullOrEmpty(text2))
text2 = "/";
array = RequestRealPath(text2, true);
if (array != null)
text = array[0].Key;
if (string.IsNullOrEmpty(text))
return fullRemotePath;
string arg = string.Empty;
if (text[text.Length - 1] != '/')
arg = "/";
return string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", text, arg, array2[array2.Length - 1]);
}
[AsyncStateMachine(typeof(<GetCanonicalPathAsync>d__24))]
public Task<string> GetCanonicalPathAsync(string path, CancellationToken cancellationToken)
{
<GetCanonicalPathAsync>d__24 stateMachine = default(<GetCanonicalPathAsync>d__24);
stateMachine.<>t__builder = AsyncTaskMethodBuilder<string>.Create();
stateMachine.<>4__this = this;
stateMachine.path = path;
stateMachine.cancellationToken = cancellationToken;
stateMachine.<>1__state = -1;
stateMachine.<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
internal string GetFullRemotePath(string path)
{
string result = path;
if (!string.IsNullOrEmpty(path) && path[0] != '/' && WorkingDirectory != null)
result = ((WorkingDirectory[WorkingDirectory.Length - 1] != '/') ? (WorkingDirectory + "/" + path) : (WorkingDirectory + path));
return result;
}
protected override void OnChannelOpen()
{
SendMessage(new SftpInitRequest(3));
WaitOnHandle(_sftpVersionConfirmed, base.OperationTimeout);
if (ProtocolVersion > 3)
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Server SFTP version {0} is not supported.", ProtocolVersion));
WorkingDirectory = RequestRealPath(".", false)[0].Key;
}
protected override void OnDataReceived(ArraySegment<byte> data)
{
Span<byte> span;
if (_buffer.ActiveLength == 0) {
while (data.Count >= 4) {
int num = BinaryPrimitives.ReadInt32BigEndian(data);
if (data.Count - 4 < num)
break;
if (!TryLoadSftpMessage(Extensions.Slice(data, 4, num)))
return;
data = Extensions.Slice(data, 4 + num);
}
if (data.Count > 0) {
_buffer.EnsureAvailableSpace(data.Count);
span = data.AsSpan();
span.CopyTo(_buffer.AvailableSpan);
_buffer.Commit(data.Count);
}
} else {
_buffer.EnsureAvailableSpace(data.Count);
span = data.AsSpan();
span.CopyTo(_buffer.AvailableSpan);
_buffer.Commit(data.Count);
while (_buffer.ActiveLength >= 4) {
data = new ArraySegment<byte>(_buffer.DangerousGetUnderlyingBuffer(), _buffer.ActiveStartOffset, _buffer.ActiveLength);
int num2 = BinaryPrimitives.ReadInt32BigEndian(data);
if (data.Count - 4 < num2)
break;
TryLoadSftpMessage(Extensions.Slice(data, 4, num2));
_buffer.Discard(4 + num2);
}
}
}
private bool TryLoadSftpMessage(ArraySegment<byte> packetData)
{
SftpMessage sftpMessage = _sftpResponseFactory.Create(ProtocolVersion, packetData.Array[packetData.Offset], _encoding);
sftpMessage.Load(packetData.Array, packetData.Offset + 1, packetData.Count - 1);
try {
SftpVersionResponse sftpVersionResponse = sftpMessage as SftpVersionResponse;
if (sftpVersionResponse != null) {
ProtocolVersion = sftpVersionResponse.Version;
_supportedExtensions = sftpVersionResponse.Extensions;
_sftpVersionConfirmed.Set();
} else
HandleResponse(sftpMessage as SftpResponse);
return true;
} catch (Exception error) {
RaiseError(error);
return false;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing) {
EventWaitHandle sftpVersionConfirmed = _sftpVersionConfirmed;
if (sftpVersionConfirmed != null) {
_sftpVersionConfirmed = null;
sftpVersionConfirmed.Dispose();
}
}
}
private void SendRequest(SftpRequest request)
{
lock (_requests) {
_requests.Add(request.RequestId, request);
}
SendMessage(request);
}
public byte[] RequestOpen(string path, Flags flags)
{
byte[] handle = null;
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpOpenRequest request = new SftpOpenRequest(ProtocolVersion, NextRequestId, path, _encoding, flags, delegate(SftpHandleResponse response) {
handle = response.Handle;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, path);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
return handle;
}
public Task<byte[]> RequestOpenAsync(string path, Flags flags, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<byte[]>(cancellationToken);
TaskCompletionSource<byte[]> tcs = new TaskCompletionSource<byte[]>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpOpenRequest(ProtocolVersion, NextRequestId, path, _encoding, flags, delegate(SftpHandleResponse response) {
tcs.TrySetResult(response.Handle);
}, delegate(SftpStatusResponse response) {
tcs.TrySetException(GetSftpException(response, path));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public void RequestClose(byte[] handle)
{
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpCloseRequest request = new SftpCloseRequest(ProtocolVersion, NextRequestId, handle, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
}
public Task RequestCloseAsync(byte[] handle, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled(cancellationToken);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpCloseRequest(ProtocolVersion, NextRequestId, handle, delegate(SftpStatusResponse response) {
if (response.StatusCode == StatusCode.Ok)
tcs.TrySetResult(true);
else
tcs.TrySetException(GetSftpException(response, null));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public byte[] RequestRead(byte[] handle, ulong offset, uint length)
{
SftpException exception = null;
byte[] data = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpReadRequest request = new SftpReadRequest(ProtocolVersion, NextRequestId, handle, offset, length, delegate(SftpDataResponse response) {
data = response.Data;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
if (response.StatusCode != StatusCode.Eof)
exception = GetSftpException(response, null);
else
data = Array.Empty<byte>();
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
return data;
}
public Task<byte[]> RequestReadAsync(byte[] handle, ulong offset, uint length, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<byte[]>(cancellationToken);
TaskCompletionSource<byte[]> tcs = new TaskCompletionSource<byte[]>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpReadRequest(ProtocolVersion, NextRequestId, handle, offset, length, delegate(SftpDataResponse response) {
tcs.TrySetResult(response.Data);
}, delegate(SftpStatusResponse response) {
if (response.StatusCode == StatusCode.Eof)
tcs.TrySetResult(Array.Empty<byte>());
else
tcs.TrySetException(GetSftpException(response, null));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public void RequestWrite(byte[] handle, ulong serverOffset, byte[] data, int offset, int length, AutoResetEvent wait, Action<SftpStatusResponse> writeCompleted = null)
{
SftpException exception = null;
SftpWriteRequest request = new SftpWriteRequest(ProtocolVersion, NextRequestId, handle, serverOffset, data, offset, length, delegate(SftpStatusResponse response) {
if (writeCompleted != null)
writeCompleted(response);
else {
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
}
});
SendRequest(request);
if (wait != null) {
WaitOnHandle(wait, base.OperationTimeout);
if (exception != null)
throw exception;
}
}
public Task RequestWriteAsync(byte[] handle, ulong serverOffset, byte[] data, int offset, int length, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled(cancellationToken);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpWriteRequest(ProtocolVersion, NextRequestId, handle, serverOffset, data, offset, length, delegate(SftpStatusResponse response) {
if (response.StatusCode == StatusCode.Ok)
tcs.TrySetResult(true);
else
tcs.TrySetException(GetSftpException(response, null));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public SftpFileAttributes RequestLStat(string path)
{
SftpException exception = null;
SftpFileAttributes attributes = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpLStatRequest request = new SftpLStatRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpAttrsResponse response) {
attributes = response.Attributes;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, path);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
return attributes;
}
public Task<SftpFileAttributes> RequestLStatAsync(string path, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<SftpFileAttributes>(cancellationToken);
TaskCompletionSource<SftpFileAttributes> tcs = new TaskCompletionSource<SftpFileAttributes>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpLStatRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpAttrsResponse response) {
tcs.TrySetResult(response.Attributes);
}, delegate(SftpStatusResponse response) {
tcs.TrySetException(GetSftpException(response, path));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public SftpFileAttributes RequestFStat(byte[] handle)
{
SftpException exception = null;
SftpFileAttributes attributes = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpFStatRequest request = new SftpFStatRequest(ProtocolVersion, NextRequestId, handle, delegate(SftpAttrsResponse response) {
attributes = response.Attributes;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
return attributes;
}
public Task<SftpFileAttributes> RequestFStatAsync(byte[] handle, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<SftpFileAttributes>(cancellationToken);
TaskCompletionSource<SftpFileAttributes> tcs = new TaskCompletionSource<SftpFileAttributes>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpFStatRequest(ProtocolVersion, NextRequestId, handle, delegate(SftpAttrsResponse response) {
tcs.TrySetResult(response.Attributes);
}, delegate(SftpStatusResponse response) {
tcs.TrySetException(GetSftpException(response, null));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public void RequestSetStat(string path, SftpFileAttributes attributes)
{
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpSetStatRequest request = new SftpSetStatRequest(ProtocolVersion, NextRequestId, path, _encoding, attributes, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, path);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
}
public void RequestFSetStat(byte[] handle, SftpFileAttributes attributes)
{
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpFSetStatRequest request = new SftpFSetStatRequest(ProtocolVersion, NextRequestId, handle, attributes, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
}
public byte[] RequestOpenDir(string path)
{
SftpException exception = null;
byte[] handle = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpOpenDirRequest request = new SftpOpenDirRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpHandleResponse response) {
handle = response.Handle;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, path);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
return handle;
}
public Task<byte[]> RequestOpenDirAsync(string path, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<byte[]>(cancellationToken);
TaskCompletionSource<byte[]> tcs = new TaskCompletionSource<byte[]>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpOpenDirRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpHandleResponse response) {
tcs.TrySetResult(response.Handle);
}, delegate(SftpStatusResponse response) {
tcs.TrySetException(GetSftpException(response, path));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public KeyValuePair<string, SftpFileAttributes>[] RequestReadDir(byte[] handle)
{
SftpException exception = null;
KeyValuePair<string, SftpFileAttributes>[] result = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpReadDirRequest request = new SftpReadDirRequest(ProtocolVersion, NextRequestId, handle, delegate(SftpNameResponse response) {
result = response.Files;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
if (response.StatusCode != StatusCode.Eof)
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
return result;
}
public Task<KeyValuePair<string, SftpFileAttributes>[]> RequestReadDirAsync(byte[] handle, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<KeyValuePair<string, SftpFileAttributes>[]>(cancellationToken);
TaskCompletionSource<KeyValuePair<string, SftpFileAttributes>[]> tcs = new TaskCompletionSource<KeyValuePair<string, SftpFileAttributes>[]>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpReadDirRequest(ProtocolVersion, NextRequestId, handle, delegate(SftpNameResponse response) {
tcs.TrySetResult(response.Files);
}, delegate(SftpStatusResponse response) {
if (response.StatusCode == StatusCode.Eof)
tcs.TrySetResult(null);
else
tcs.TrySetException(GetSftpException(response, null));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public void RequestRemove(string path)
{
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpRemoveRequest request = new SftpRemoveRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, path);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
}
public Task RequestRemoveAsync(string path, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled(cancellationToken);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpRemoveRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpStatusResponse response) {
if (response.StatusCode == StatusCode.Ok)
tcs.TrySetResult(true);
else
tcs.TrySetException(GetSftpException(response, path));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public void RequestMkDir(string path)
{
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpMkDirRequest request = new SftpMkDirRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
}
public Task RequestMkDirAsync(string path, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled(cancellationToken);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpMkDirRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpStatusResponse response) {
if (response.StatusCode == StatusCode.Ok)
tcs.TrySetResult(true);
else
tcs.TrySetException(GetSftpException(response, null));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public void RequestRmDir(string path)
{
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpRmDirRequest request = new SftpRmDirRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, path);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
}
public Task RequestRmDirAsync(string path, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled(cancellationToken);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpRmDirRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpStatusResponse response) {
SftpException sftpException = GetSftpException(response, path);
if (sftpException != null)
tcs.TrySetException(sftpException);
else
tcs.TrySetResult(true);
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
internal KeyValuePair<string, SftpFileAttributes>[] RequestRealPath(string path, bool nullOnError = false)
{
SftpException exception = null;
KeyValuePair<string, SftpFileAttributes>[] result = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpRealPathRequest request = new SftpRealPathRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpNameResponse response) {
result = response.Files;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, path);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (!nullOnError && exception != null)
throw exception;
return result;
}
internal Task<KeyValuePair<string, SftpFileAttributes>[]> RequestRealPathAsync(string path, bool nullOnError, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<KeyValuePair<string, SftpFileAttributes>[]>(cancellationToken);
TaskCompletionSource<KeyValuePair<string, SftpFileAttributes>[]> tcs = new TaskCompletionSource<KeyValuePair<string, SftpFileAttributes>[]>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpRealPathRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpNameResponse response) {
tcs.TrySetResult(response.Files);
}, delegate(SftpStatusResponse response) {
if (nullOnError)
tcs.TrySetResult(null);
else
tcs.TrySetException(GetSftpException(response, path));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
public SftpFileAttributes RequestStat(string path)
{
SftpException exception = null;
SftpFileAttributes attributes = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpStatRequest request = new SftpStatRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpAttrsResponse response) {
attributes = response.Attributes;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, path);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
return attributes;
}
public void RequestRename(string oldPath, string newPath)
{
if (ProtocolVersion < 2)
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "SSH_FXP_RENAME operation is not supported in {0} version that server operates in.", ProtocolVersion));
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpRenameRequest request = new SftpRenameRequest(ProtocolVersion, NextRequestId, oldPath, newPath, _encoding, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
}
public Task RequestRenameAsync(string oldPath, string newPath, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled(cancellationToken);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new SftpRenameRequest(ProtocolVersion, NextRequestId, oldPath, newPath, _encoding, delegate(SftpStatusResponse response) {
if (response.StatusCode == StatusCode.Ok)
tcs.TrySetResult(true);
else
tcs.TrySetException(GetSftpException(response, null));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
internal KeyValuePair<string, SftpFileAttributes>[] RequestReadLink(string path, bool nullOnError = false)
{
if (ProtocolVersion < 3)
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "SSH_FXP_READLINK operation is not supported in {0} version that server operates in.", ProtocolVersion));
SftpException exception = null;
KeyValuePair<string, SftpFileAttributes>[] result = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpReadLinkRequest request = new SftpReadLinkRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpNameResponse response) {
result = response.Files;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, path);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (!nullOnError && exception != null)
throw exception;
return result;
}
public void RequestSymLink(string linkpath, string targetpath)
{
if (ProtocolVersion < 3)
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "SSH_FXP_SYMLINK operation is not supported in {0} version that server operates in.", ProtocolVersion));
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
SftpSymLinkRequest request = new SftpSymLinkRequest(ProtocolVersion, NextRequestId, linkpath, targetpath, _encoding, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
});
SendRequest(request);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
}
public void RequestPosixRename(string oldPath, string newPath)
{
if (ProtocolVersion < 3)
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "SSH_FXP_EXTENDED operation is not supported in {0} version that server operates in.", ProtocolVersion));
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
PosixRenameRequest posixRenameRequest = new PosixRenameRequest(ProtocolVersion, NextRequestId, oldPath, newPath, _encoding, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
});
if (!_supportedExtensions.ContainsKey(posixRenameRequest.Name))
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Extension method {0} currently not supported by the server.", posixRenameRequest.Name));
SendRequest(posixRenameRequest);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
}
public SftpFileSystemInformation RequestStatVfs(string path)
{
if (ProtocolVersion < 3)
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "SSH_FXP_EXTENDED operation is not supported in {0} version that server operates in.", ProtocolVersion));
SftpException exception = null;
SftpFileSystemInformation information = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
StatVfsRequest statVfsRequest = new StatVfsRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpExtendedReplyResponse response) {
information = response.GetReply<StatVfsReplyInfo>().Information;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, path);
wait.SetIgnoringObjectDisposed();
});
if (!_supportedExtensions.ContainsKey(statVfsRequest.Name))
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Extension method {0} currently not supported by the server.", statVfsRequest.Name));
SendRequest(statVfsRequest);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
return information;
}
public Task<SftpFileSystemInformation> RequestStatVfsAsync(string path, CancellationToken cancellationToken)
{
if (ProtocolVersion < 3)
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "SSH_FXP_EXTENDED operation is not supported in {0} version that server operates in.", ProtocolVersion));
if (cancellationToken.IsCancellationRequested)
return Task.FromCanceled<SftpFileSystemInformation>(cancellationToken);
TaskCompletionSource<SftpFileSystemInformation> tcs = new TaskCompletionSource<SftpFileSystemInformation>(TaskCreationOptions.RunContinuationsAsynchronously);
SendRequest(new StatVfsRequest(ProtocolVersion, NextRequestId, path, _encoding, delegate(SftpExtendedReplyResponse response) {
tcs.TrySetResult(response.GetReply<StatVfsReplyInfo>().Information);
}, delegate(SftpStatusResponse response) {
tcs.TrySetException(GetSftpException(response, path));
}));
return WaitOnHandleAsync(tcs, base.OperationTimeout, cancellationToken);
}
internal SftpFileSystemInformation RequestFStatVfs(byte[] handle, bool nullOnError = false)
{
if (ProtocolVersion < 3)
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "SSH_FXP_EXTENDED operation is not supported in {0} version that server operates in.", ProtocolVersion));
SftpException exception = null;
SftpFileSystemInformation information = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
FStatVfsRequest fStatVfsRequest = new FStatVfsRequest(ProtocolVersion, NextRequestId, handle, delegate(SftpExtendedReplyResponse response) {
information = response.GetReply<StatVfsReplyInfo>().Information;
wait.SetIgnoringObjectDisposed();
}, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
});
if (!_supportedExtensions.ContainsKey(fStatVfsRequest.Name))
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Extension method {0} currently not supported by the server.", fStatVfsRequest.Name));
SendRequest(fStatVfsRequest);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (!nullOnError && exception != null)
throw exception;
return information;
}
internal void HardLink(string oldPath, string newPath)
{
if (ProtocolVersion < 3)
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "SSH_FXP_EXTENDED operation is not supported in {0} version that server operates in.", ProtocolVersion));
SftpException exception = null;
AutoResetEvent wait = new AutoResetEvent(false);
try {
HardLinkRequest hardLinkRequest = new HardLinkRequest(ProtocolVersion, NextRequestId, oldPath, newPath, delegate(SftpStatusResponse response) {
exception = GetSftpException(response, null);
wait.SetIgnoringObjectDisposed();
});
if (!_supportedExtensions.ContainsKey(hardLinkRequest.Name))
throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Extension method {0} currently not supported by the server.", hardLinkRequest.Name));
SendRequest(hardLinkRequest);
WaitOnHandle(wait, base.OperationTimeout);
} finally {
if (wait != null)
((IDisposable)wait).Dispose();
}
if (exception != null)
throw exception;
}
public uint CalculateOptimalReadLength(uint bufferSize)
{
uint localPacketSize = base.Channel.LocalPacketSize;
return Math.Min(bufferSize, localPacketSize) - 13;
}
public uint CalculateOptimalWriteLength(uint bufferSize, byte[] handle)
{
uint num = (uint)(25 + handle.Length);
uint remotePacketSize = base.Channel.RemotePacketSize;
return Math.Min(bufferSize, remotePacketSize) - num;
}
internal static SftpException GetSftpException(SftpStatusResponse response, string path = null)
{
switch (response.StatusCode) {
case StatusCode.Ok:
return null;
case StatusCode.PermissionDenied:
return new SftpPermissionDeniedException(response.ErrorMessage);
case StatusCode.NoSuchFile: {
string text = response.ErrorMessage;
if (!string.IsNullOrEmpty(text) && path != null) {
string[] obj = new string[5] {
text,
null,
null,
null,
null
};
string text2 = text;
obj[1] = ((text2[text2.Length - 1] == '.') ? " " : ". ");
obj[2] = "Path: '";
obj[3] = path;
obj[4] = "'.";
text = string.Concat(obj);
}
return new SftpPathNotFoundException(text, path);
}
default:
return new SftpException(response.StatusCode, response.ErrorMessage);
}
}
private void HandleResponse(SftpResponse response)
{
SftpRequest value;
lock (_requests) {
_requests.TryGetValue(response.ResponseId, out value);
if (value != null)
_requests.Remove(response.ResponseId);
}
if (value == null)
throw new InvalidOperationException("Invalid response.");
value.Complete(response);
}
}
}