<PackageReference Include="SSH.NET" Version="2025.1.0" />

SftpClient

Implementation of the SSH File Transfer Protocol (SFTP) over SSH.
using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Sftp; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Renci.SshNet { [NullableContext(1)] [Nullable(0)] public class SftpClient : BaseClient, ISftpClient, IBaseClient, IDisposable { private static readonly Encoding Utf8NoBOM = new UTF8Encoding(false, true); [Nullable(2)] private ISftpSession _sftpSession; private int _operationTimeout; private uint _bufferSize; public TimeSpan OperationTimeout { get { return TimeSpan.FromMilliseconds(_operationTimeout, 0); } set { _operationTimeout = value.AsTimeout("OperationTimeout"); ISftpSession sftpSession = _sftpSession; if (sftpSession != null) sftpSession.OperationTimeout = _operationTimeout; } } public uint BufferSize { get { CheckDisposed(); return _bufferSize; } set { CheckDisposed(); _bufferSize = value; } } public override bool IsConnected { get { if (base.IsConnected) return _sftpSession?.IsOpen ?? false; return false; } } public string WorkingDirectory { get { CheckDisposed(); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); return _sftpSession.WorkingDirectory; } } public int ProtocolVersion { get { CheckDisposed(); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); return (int)_sftpSession.ProtocolVersion; } } [Nullable(2)] internal ISftpSession SftpSession { [NullableContext(2)] get { return _sftpSession; } } public SftpClient(ConnectionInfo connectionInfo) : this(connectionInfo, false) { } public SftpClient(string host, int port, string username, string password) : this(new PasswordConnectionInfo(host, port, username, password), true) { } public SftpClient(string host, string username, string password) : this(host, 22, username, password) { } public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) { } public SftpClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, 22, username, keyFiles) { } private SftpClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo) : this(connectionInfo, ownsConnectionInfo, new ServiceFactory()) { } internal SftpClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory) { _operationTimeout = -1; _bufferSize = 32768; } public void ChangeDirectory(string path) { CheckDisposed(); ThrowHelper.ThrowIfNull(path, "path"); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); _sftpSession.ChangeDirectory(path); } public Task ChangeDirectoryAsync(string path, CancellationToken cancellationToken = default(CancellationToken)) { CheckDisposed(); ThrowHelper.ThrowIfNull(path, "path"); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); cancellationToken.ThrowIfCancellationRequested(); return _sftpSession.ChangeDirectoryAsync(path, cancellationToken); } public void ChangePermissions(string path, short mode) { Get(path).SetPermissions(mode); } public void CreateDirectory(string path) { CheckDisposed(); ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); string canonicalPath = _sftpSession.GetCanonicalPath(path); _sftpSession.RequestMkDir(canonicalPath); } [AsyncStateMachine(typeof(<CreateDirectoryAsync>d__29))] public Task CreateDirectoryAsync(string path, CancellationToken cancellationToken = default(CancellationToken)) { <CreateDirectoryAsync>d__29 stateMachine = default(<CreateDirectoryAsync>d__29); 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; } public void DeleteDirectory(string path) { CheckDisposed(); ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); string canonicalPath = _sftpSession.GetCanonicalPath(path); _sftpSession.RequestRmDir(canonicalPath); } [AsyncStateMachine(typeof(<DeleteDirectoryAsync>d__31))] public Task DeleteDirectoryAsync(string path, CancellationToken cancellationToken = default(CancellationToken)) { <DeleteDirectoryAsync>d__31 stateMachine = default(<DeleteDirectoryAsync>d__31); 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; } public void DeleteFile(string path) { CheckDisposed(); ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); string canonicalPath = _sftpSession.GetCanonicalPath(path); _sftpSession.RequestRemove(canonicalPath); } [AsyncStateMachine(typeof(<DeleteFileAsync>d__33))] public Task DeleteFileAsync(string path, CancellationToken cancellationToken) { <DeleteFileAsync>d__33 stateMachine = default(<DeleteFileAsync>d__33); 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; } public void RenameFile(string oldPath, string newPath) { RenameFile(oldPath, newPath, false); } public void RenameFile(string oldPath, string newPath, bool isPosix) { CheckDisposed(); ThrowHelper.ThrowIfNull(oldPath, "oldPath"); ThrowHelper.ThrowIfNull(newPath, "newPath"); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); string canonicalPath = _sftpSession.GetCanonicalPath(oldPath); string canonicalPath2 = _sftpSession.GetCanonicalPath(newPath); if (isPosix) _sftpSession.RequestPosixRename(canonicalPath, canonicalPath2); else _sftpSession.RequestRename(canonicalPath, canonicalPath2); } [AsyncStateMachine(typeof(<RenameFileAsync>d__36))] public Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken) { <RenameFileAsync>d__36 stateMachine = default(<RenameFileAsync>d__36); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.oldPath = oldPath; stateMachine.newPath = newPath; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } public void SymbolicLink(string path, string linkPath) { CheckDisposed(); ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); ThrowHelper.ThrowIfNullOrWhiteSpace(linkPath, "linkPath"); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); string canonicalPath = _sftpSession.GetCanonicalPath(path); string canonicalPath2 = _sftpSession.GetCanonicalPath(linkPath); _sftpSession.RequestSymLink(canonicalPath, canonicalPath2); } public IEnumerable<ISftpFile> ListDirectory(string path, [Nullable(2)] Action<int> listCallback = null) { CheckDisposed(); return InternalListDirectory(path, null, listCallback); } [AsyncIteratorStateMachine(typeof(<ListDirectoryAsync>d__39))] public IAsyncEnumerable<ISftpFile> ListDirectoryAsync(string path, [EnumeratorCancellation] CancellationToken cancellationToken) { <ListDirectoryAsync>d__39 <ListDirectoryAsync>d__ = new <ListDirectoryAsync>d__39(-2); <ListDirectoryAsync>d__.<>4__this = this; <ListDirectoryAsync>d__.<>3__path = path; <ListDirectoryAsync>d__.<>3__cancellationToken = cancellationToken; return <ListDirectoryAsync>d__; } [NullableContext(2)] [return: Nullable(1)] public IAsyncResult BeginListDirectory([Nullable(1)] string path, AsyncCallback asyncCallback, object state, Action<int> listCallback = null) { CheckDisposed(); SftpListDirectoryAsyncResult asyncResult = new SftpListDirectoryAsyncResult(asyncCallback, state); ThreadAbstraction.ExecuteThread(delegate { try { List<ISftpFile> result = InternalListDirectory(path, asyncResult, listCallback); asyncResult.SetAsCompleted(result, false); } catch (Exception exception) { asyncResult.SetAsCompleted(exception, false); } }); return asyncResult; } public IEnumerable<ISftpFile> EndListDirectory(IAsyncResult asyncResult) { SftpListDirectoryAsyncResult sftpListDirectoryAsyncResult = asyncResult as SftpListDirectoryAsyncResult; if (sftpListDirectoryAsyncResult == null || sftpListDirectoryAsyncResult.EndInvokeCalled) throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult."); return sftpListDirectoryAsyncResult.EndInvoke(); } public ISftpFile Get(string path) { CheckDisposed(); ThrowHelper.ThrowIfNull(path, "path"); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); string canonicalPath = _sftpSession.GetCanonicalPath(path); SftpFileAttributes attributes = _sftpSession.RequestLStat(canonicalPath); return new SftpFile(_sftpSession, canonicalPath, attributes); } [AsyncStateMachine(typeof(<GetAsync>d__43))] public Task<ISftpFile> GetAsync(string path, CancellationToken cancellationToken) { <GetAsync>d__43 stateMachine = default(<GetAsync>d__43); stateMachine.<>t__builder = AsyncTaskMethodBuilder<ISftpFile>.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; } public bool Exists(string path) { CheckDisposed(); ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); if (_sftpSession != null) { string canonicalPath = _sftpSession.GetCanonicalPath(path); try { _sftpSession.RequestLStat(canonicalPath); return true; } catch (SftpPathNotFoundException) { return false; } } throw new SshConnectionException("Client not connected."); } [AsyncStateMachine(typeof(<ExistsAsync>d__45))] public Task<bool> ExistsAsync(string path, CancellationToken cancellationToken = default(CancellationToken)) { <ExistsAsync>d__45 stateMachine = default(<ExistsAsync>d__45); stateMachine.<>t__builder = AsyncTaskMethodBuilder<bool>.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; } public void DownloadFile(string path, Stream output, [Nullable(2)] Action<ulong> downloadCallback = null) { ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); ThrowHelper.ThrowIfNull(output, "output"); CheckDisposed(); InternalDownloadFile(path, output, null, downloadCallback, false, CancellationToken.None).GetAwaiter().GetResult(); } public Task DownloadFileAsync(string path, Stream output, CancellationToken cancellationToken = default(CancellationToken)) { ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); ThrowHelper.ThrowIfNull(output, "output"); CheckDisposed(); return InternalDownloadFile(path, output, null, null, true, cancellationToken); } public IAsyncResult BeginDownloadFile(string path, Stream output) { return BeginDownloadFile(path, output, null, null, null); } public IAsyncResult BeginDownloadFile(string path, Stream output, [Nullable(2)] AsyncCallback asyncCallback) { return BeginDownloadFile(path, output, asyncCallback, null, null); } public IAsyncResult BeginDownloadFile(string path, Stream output, [Nullable(2)] AsyncCallback asyncCallback, [Nullable(2)] object state, [Nullable(2)] Action<ulong> downloadCallback = null) { ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); ThrowHelper.ThrowIfNull(output, "output"); CheckDisposed(); SftpDownloadAsyncResult asyncResult = new SftpDownloadAsyncResult(asyncCallback, state); object obj; ((<>c__DisplayClass50_0)obj).<BeginDownloadFile>g__DoDownloadAndSetResult|0(); return asyncResult; } public void EndDownloadFile(IAsyncResult asyncResult) { SftpDownloadAsyncResult sftpDownloadAsyncResult = asyncResult as SftpDownloadAsyncResult; if (sftpDownloadAsyncResult == null || sftpDownloadAsyncResult.EndInvokeCalled) throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult."); sftpDownloadAsyncResult.EndInvoke(); } public void UploadFile(Stream input, string path, [Nullable(2)] Action<ulong> uploadCallback = null) { UploadFile(input, path, true, uploadCallback); } public void UploadFile(Stream input, string path, bool canOverride, [Nullable(2)] Action<ulong> uploadCallback = null) { ThrowHelper.ThrowIfNull(input, "input"); ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); CheckDisposed(); Flags flags = Flags.Write | Flags.Truncate; flags = ((!canOverride) ? (flags | Flags.CreateNew) : (flags | Flags.CreateNewOrOpen)); InternalUploadFile(input, path, flags, null, uploadCallback, false, CancellationToken.None).GetAwaiter().GetResult(); } public Task UploadFileAsync(Stream input, string path, CancellationToken cancellationToken = default(CancellationToken)) { ThrowHelper.ThrowIfNull(input, "input"); ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); CheckDisposed(); return InternalUploadFile(input, path, Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate, null, null, true, cancellationToken); } public IAsyncResult BeginUploadFile(Stream input, string path) { return BeginUploadFile(input, path, true, null, null, null); } public IAsyncResult BeginUploadFile(Stream input, string path, [Nullable(2)] AsyncCallback asyncCallback) { return BeginUploadFile(input, path, true, asyncCallback, null, null); } public IAsyncResult BeginUploadFile(Stream input, string path, [Nullable(2)] AsyncCallback asyncCallback, [Nullable(2)] object state, [Nullable(2)] Action<ulong> uploadCallback = null) { return BeginUploadFile(input, path, true, asyncCallback, state, uploadCallback); } public IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, [Nullable(2)] AsyncCallback asyncCallback, [Nullable(2)] object state, [Nullable(2)] Action<ulong> uploadCallback = null) { ThrowHelper.ThrowIfNull(input, "input"); ThrowHelper.ThrowIfNullOrWhiteSpace(path, "path"); CheckDisposed(); Flags flags = Flags.Write | Flags.Truncate; if (canOverride) flags |= Flags.CreateNewOrOpen; else flags |= Flags.CreateNew; SftpUploadAsyncResult asyncResult = new SftpUploadAsyncResult(asyncCallback, state); <>c__DisplayClass58_0 <>c__DisplayClass58_; <>c__DisplayClass58_.<BeginUploadFile>g__DoUploadAndSetResult|0(); return asyncResult; } public void EndUploadFile(IAsyncResult asyncResult) { SftpUploadAsyncResult sftpUploadAsyncResult = asyncResult as SftpUploadAsyncResult; if (sftpUploadAsyncResult == null || sftpUploadAsyncResult.EndInvokeCalled) throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult."); sftpUploadAsyncResult.EndInvoke(); } public SftpFileSystemInformation GetStatus(string path) { CheckDisposed(); ThrowHelper.ThrowIfNull(path, "path"); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); string canonicalPath = _sftpSession.GetCanonicalPath(path); return _sftpSession.RequestStatVfs(canonicalPath); } [AsyncStateMachine(typeof(<GetStatusAsync>d__61))] public Task<SftpFileSystemInformation> GetStatusAsync(string path, CancellationToken cancellationToken) { <GetStatusAsync>d__61 stateMachine = default(<GetStatusAsync>d__61); stateMachine.<>t__builder = AsyncTaskMethodBuilder<SftpFileSystemInformation>.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; } public void AppendAllLines(string path, IEnumerable<string> contents) { CheckDisposed(); ThrowHelper.ThrowIfNull(contents, "contents"); using (StreamWriter streamWriter = AppendText(path)) { foreach (string content in contents) { streamWriter.WriteLine(content); } } } public void AppendAllLines(string path, IEnumerable<string> contents, Encoding encoding) { CheckDisposed(); ThrowHelper.ThrowIfNull(contents, "contents"); using (StreamWriter streamWriter = AppendText(path, encoding)) { foreach (string content in contents) { streamWriter.WriteLine(content); } } } public void AppendAllText(string path, string contents) { using (StreamWriter streamWriter = AppendText(path)) streamWriter.Write(contents); } public void AppendAllText(string path, string contents, Encoding encoding) { using (StreamWriter streamWriter = AppendText(path, encoding)) streamWriter.Write(contents); } public StreamWriter AppendText(string path) { return AppendText(path, Utf8NoBOM); } public StreamWriter AppendText(string path, Encoding encoding) { CheckDisposed(); ThrowHelper.ThrowIfNull(encoding, "encoding"); return new StreamWriter(Open(path, FileMode.Append, FileAccess.Write), encoding); } public SftpFileStream Create(string path) { return Create(path, (int)_bufferSize); } public SftpFileStream Create(string path, int bufferSize) { CheckDisposed(); return SftpFileStream.Open(_sftpSession, path, FileMode.Create, FileAccess.ReadWrite, bufferSize, false); } public StreamWriter CreateText(string path) { return CreateText(path, Utf8NoBOM); } public StreamWriter CreateText(string path, Encoding encoding) { CheckDisposed(); return new StreamWriter(Open(path, FileMode.Create, FileAccess.Write), encoding); } public void Delete(string path) { Get(path).Delete(); } [AsyncStateMachine(typeof(<DeleteAsync>d__73))] public Task DeleteAsync(string path, CancellationToken cancellationToken = default(CancellationToken)) { <DeleteAsync>d__73 stateMachine = default(<DeleteAsync>d__73); 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; } public DateTime GetLastAccessTime(string path) { return Get(path).LastAccessTime; } public DateTime GetLastAccessTimeUtc(string path) { return GetLastAccessTime(path).ToUniversalTime(); } public DateTime GetLastWriteTime(string path) { return Get(path).LastWriteTime; } public DateTime GetLastWriteTimeUtc(string path) { return GetLastWriteTime(path).ToUniversalTime(); } public SftpFileStream Open(string path, FileMode mode) { return Open(path, mode, FileAccess.ReadWrite); } public SftpFileStream Open(string path, FileMode mode, FileAccess access) { CheckDisposed(); return SftpFileStream.Open(_sftpSession, path, mode, access, (int)_bufferSize, false); } public Task<SftpFileStream> OpenAsync(string path, FileMode mode, FileAccess access, CancellationToken cancellationToken) { CheckDisposed(); return SftpFileStream.OpenAsync(_sftpSession, path, mode, access, (int)_bufferSize, cancellationToken, false); } public SftpFileStream OpenRead(string path) { return Open(path, FileMode.Open, FileAccess.Read); } public StreamReader OpenText(string path) { return new StreamReader(OpenRead(path), Encoding.UTF8); } public SftpFileStream OpenWrite(string path) { return Open(path, FileMode.OpenOrCreate, FileAccess.Write); } public byte[] ReadAllBytes(string path) { using (SftpFileStream sftpFileStream = OpenRead(path)) { byte[] array; if (sftpFileStream.CanSeek) { array = new byte[sftpFileStream.Length]; sftpFileStream.ReadExactly(array, 0, array.Length); } else { MemoryStream memoryStream = new MemoryStream(); sftpFileStream.CopyTo(memoryStream); array = memoryStream.ToArray(); } return array; } } public string[] ReadAllLines(string path) { return ReadAllLines(path, Encoding.UTF8); } public string[] ReadAllLines(string path, Encoding encoding) { return ReadLines(path, encoding).ToArray(); } public string ReadAllText(string path) { return ReadAllText(path, Encoding.UTF8); } public string ReadAllText(string path, Encoding encoding) { using (StreamReader streamReader = new StreamReader(OpenRead(path), encoding)) return streamReader.ReadToEnd(); } public IEnumerable<string> ReadLines(string path) { return ReadLines(path, Encoding.UTF8); } public IEnumerable<string> ReadLines(string path, Encoding encoding) { ThrowHelper.ThrowIfNull(path, "path"); object obj; return ((<>c__DisplayClass90_0)obj).<ReadLines>g__Enumerate|0(); } public void SetLastAccessTime(string path, DateTime lastAccessTime) { SftpFileAttributes attributes = GetAttributes(path); attributes.LastAccessTime = lastAccessTime; SetAttributes(path, attributes); } public void SetLastAccessTimeUtc(string path, DateTime lastAccessTimeUtc) { SftpFileAttributes attributes = GetAttributes(path); attributes.LastAccessTimeUtc = lastAccessTimeUtc; SetAttributes(path, attributes); } public void SetLastWriteTime(string path, DateTime lastWriteTime) { SftpFileAttributes attributes = GetAttributes(path); attributes.LastWriteTime = lastWriteTime; SetAttributes(path, attributes); } public void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc) { SftpFileAttributes attributes = GetAttributes(path); attributes.LastWriteTimeUtc = lastWriteTimeUtc; SetAttributes(path, attributes); } public void WriteAllBytes(string path, byte[] bytes) { ThrowHelper.ThrowIfNull(bytes, "bytes"); UploadFile(new MemoryStream(bytes), path, null); } public void WriteAllLines(string path, IEnumerable<string> contents) { WriteAllLines(path, contents, Utf8NoBOM); } public void WriteAllLines(string path, string[] contents) { WriteAllLines(path, contents, Utf8NoBOM); } public void WriteAllLines(string path, IEnumerable<string> contents, Encoding encoding) { using (StreamWriter streamWriter = CreateText(path, encoding)) { foreach (string content in contents) { streamWriter.WriteLine(content); } } } public void WriteAllLines(string path, string[] contents, Encoding encoding) { WriteAllLines(path, (IEnumerable<string>)contents, encoding); } public void WriteAllText(string path, string contents) { using (StreamWriter streamWriter = CreateText(path)) streamWriter.Write(contents); } public void WriteAllText(string path, string contents, Encoding encoding) { using (StreamWriter streamWriter = CreateText(path, encoding)) streamWriter.Write(contents); } public SftpFileAttributes GetAttributes(string path) { CheckDisposed(); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); string canonicalPath = _sftpSession.GetCanonicalPath(path); return _sftpSession.RequestLStat(canonicalPath); } [AsyncStateMachine(typeof(<GetAttributesAsync>d__103))] public Task<SftpFileAttributes> GetAttributesAsync(string path, CancellationToken cancellationToken) { <GetAttributesAsync>d__103 stateMachine = default(<GetAttributesAsync>d__103); stateMachine.<>t__builder = AsyncTaskMethodBuilder<SftpFileAttributes>.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; } public void SetAttributes(string path, SftpFileAttributes fileAttributes) { CheckDisposed(); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); string canonicalPath = _sftpSession.GetCanonicalPath(path); _sftpSession.RequestSetStat(canonicalPath, fileAttributes); } public IEnumerable<FileInfo> SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern) { ThrowHelper.ThrowIfNull(sourcePath, "sourcePath"); ThrowHelper.ThrowIfNullOrWhiteSpace(destinationPath, "destinationPath"); return InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, null); } public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, [Nullable(2)] AsyncCallback asyncCallback, [Nullable(2)] object state) { ThrowHelper.ThrowIfNull(sourcePath, "sourcePath"); ThrowHelper.ThrowIfNullOrWhiteSpace(destinationPath, "destinationPath"); ThrowHelper.ThrowIfNull(searchPattern, "searchPattern"); SftpSynchronizeDirectoriesAsyncResult asyncResult = new SftpSynchronizeDirectoriesAsyncResult(asyncCallback, state); ThreadAbstraction.ExecuteThread(delegate { try { List<FileInfo> result = InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asyncResult); asyncResult.SetAsCompleted(result, false); } catch (Exception exception) { asyncResult.SetAsCompleted(exception, false); } }); return asyncResult; } public IEnumerable<FileInfo> EndSynchronizeDirectories(IAsyncResult asyncResult) { SftpSynchronizeDirectoriesAsyncResult sftpSynchronizeDirectoriesAsyncResult = asyncResult as SftpSynchronizeDirectoriesAsyncResult; if (sftpSynchronizeDirectoriesAsyncResult == null || sftpSynchronizeDirectoriesAsyncResult.EndInvokeCalled) throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult."); return sftpSynchronizeDirectoriesAsyncResult.EndInvoke(); } private List<FileInfo> InternalSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, [Nullable(2)] SftpSynchronizeDirectoriesAsyncResult asyncResult) { if (!Directory.Exists(sourcePath)) throw new FileNotFoundException($"""{sourcePath}"); List<FileInfo> list = new List<FileInfo>(); using (IEnumerator<FileInfo> enumerator = new DirectoryInfo(sourcePath).EnumerateFiles(searchPattern).GetEnumerator()) { if (enumerator.MoveNext()) { List<ISftpFile> list2 = InternalListDirectory(destinationPath, null, null); Dictionary<string, ISftpFile> dictionary = new Dictionary<string, ISftpFile>(); foreach (ISftpFile item in list2) { if (!item.IsDirectory) dictionary.Add(item.Name, item); } do { FileInfo current2 = enumerator.Current; if (current2 != null) { bool flag = true; if (dictionary.TryGetValue(current2.Name, out ISftpFile value)) flag = (current2.Length != value.Length); if (flag) { string text = string.Format(CultureInfo.InvariantCulture, "{0}/{1}", destinationPath, current2.Name); try { using (FileStream input = File.OpenRead(current2.FullName)) InternalUploadFile(input, text, Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate, null, null, false, CancellationToken.None).GetAwaiter().GetResult(); list.Add(current2); asyncResult?.Update(list.Count); } catch (Exception innerException) { throw new SshException("Failed to upload " + current2.FullName + " to " + text, innerException); } } } } while (enumerator.MoveNext()); return list; } return list; } } private List<ISftpFile> InternalListDirectory(string path, [Nullable(2)] SftpListDirectoryAsyncResult asyncResult, [Nullable(2)] Action<int> listCallback) { ThrowHelper.ThrowIfNull(path, "path"); if (_sftpSession == null) throw new SshConnectionException("Client not connected."); string canonicalPath = _sftpSession.GetCanonicalPath(path); byte[] handle = _sftpSession.RequestOpenDir(canonicalPath); string text = canonicalPath; if (!text.EndsWith('/')) text = $"{canonicalPath}"""; List<ISftpFile> result = new List<ISftpFile>(); for (KeyValuePair<string, SftpFileAttributes>[] array = _sftpSession.RequestReadDir(handle); array != null; array = _sftpSession.RequestReadDir(handle)) { KeyValuePair<string, SftpFileAttributes>[] array2 = array; for (int i = 0; i < array2.Length; i++) { KeyValuePair<string, SftpFileAttributes> keyValuePair = array2[i]; result.Add(new SftpFile(_sftpSession, string.Format(CultureInfo.InvariantCulture, "{0}{1}", text, keyValuePair.Key), keyValuePair.Value)); } asyncResult?.Update(result.Count); if (listCallback != null) ThreadAbstraction.ExecuteThread(delegate { listCallback(result.Count); }); } _sftpSession.RequestClose(handle); return result; } [AsyncStateMachine(typeof(<InternalDownloadFile>d__110))] private Task InternalDownloadFile(string path, Stream output, [Nullable(2)] SftpDownloadAsyncResult asyncResult, [Nullable(2)] Action<ulong> downloadCallback, bool isAsync, CancellationToken cancellationToken) { <InternalDownloadFile>d__110 stateMachine = default(<InternalDownloadFile>d__110); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.path = path; stateMachine.output = output; stateMachine.asyncResult = asyncResult; stateMachine.downloadCallback = downloadCallback; stateMachine.isAsync = isAsync; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } [AsyncStateMachine(typeof(<InternalUploadFile>d__111))] private Task InternalUploadFile(Stream input, string path, Flags flags, [Nullable(2)] SftpUploadAsyncResult asyncResult, [Nullable(2)] Action<ulong> uploadCallback, bool isAsync, CancellationToken cancellationToken) { <InternalUploadFile>d__111 stateMachine = default(<InternalUploadFile>d__111); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.input = input; stateMachine.path = path; stateMachine.flags = flags; stateMachine.asyncResult = asyncResult; stateMachine.uploadCallback = uploadCallback; stateMachine.isAsync = isAsync; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } protected override void OnConnected() { base.OnConnected(); _sftpSession?.Dispose(); _sftpSession = CreateAndConnectToSftpSession(); } protected override void OnDisconnecting() { base.OnDisconnecting(); ISftpSession sftpSession = _sftpSession; if (sftpSession != null) { _sftpSession = null; sftpSession.Dispose(); } } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { ISftpSession sftpSession = _sftpSession; if (sftpSession != null) { _sftpSession = null; sftpSession.Dispose(); } } } private ISftpSession CreateAndConnectToSftpSession() { ISftpSession sftpSession = base.ServiceFactory.CreateSftpSession(base.Session, _operationTimeout, base.ConnectionInfo.Encoding, base.ServiceFactory.CreateSftpResponseFactory()); try { sftpSession.Connect(); return sftpSession; } catch { sftpSession.Dispose(); throw; } } } }