< Summary

Information
Class: Renci.SshNet.SftpClient
Assembly: Renci.SshNet
File(s): \home\appveyor\projects\ssh-net\src\Renci.SshNet\SftpClient.cs
Line coverage
81%
Covered lines: 711
Uncovered lines: 157
Coverable lines: 868
Total lines: 2546
Line coverage: 81.9%
Branch coverage
69%
Covered branches: 155
Total branches: 224
Branch coverage: 69.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.cctor()100%1100%
get_OperationTimeout()100%1100%
set_OperationTimeout(...)100%6100%
get_BufferSize()100%1100%
set_BufferSize(...)100%1100%
get_WorkingDirectory()50%271.42%
get_ProtocolVersion()0%20%
get_SftpSession()100%1100%
.ctor(...)100%1100%
.ctor(...)100%1100%
.ctor(...)100%1100%
.ctor(...)100%10%
.ctor(...)100%10%
.ctor(...)100%1100%
.ctor(...)100%1100%
ChangeDirectory(...)75%480%
ChangePermissions(...)100%1100%
CreateDirectory(...)50%463.63%
DeleteDirectory(...)75%481.81%
DeleteFile(...)50%463.63%
DeleteFileAsync()25%441.66%
RenameFile(...)100%1100%
RenameFile(...)62.5%866.66%
RenameFileAsync()66.66%675%
SymbolicLink(...)0%60%
ListDirectory(...)100%1100%
ListDirectoryAsync()70%1087.09%
BeginListDirectory(...)75%4100%
EndListDirectory(...)75%4100%
Get(...)75%483.33%
Exists(...)50%475%
DownloadFile(...)100%1100%
BeginDownloadFile(...)100%1100%
BeginDownloadFile(...)100%10%
BeginDownloadFile(...)87.5%8100%
EndDownloadFile(...)100%4100%
UploadFile(...)100%1100%
UploadFile(...)50%275%
BeginUploadFile(...)100%1100%
BeginUploadFile(...)100%1100%
BeginUploadFile(...)100%1100%
BeginUploadFile(...)90%10100%
EndUploadFile(...)100%4100%
GetStatus(...)0%40%
GetStatusAsync()0%40%
AppendAllLines(...)75%484.61%
AppendAllLines(...)75%484.61%
AppendAllText(...)100%1100%
AppendAllText(...)100%1100%
AppendText(...)100%1100%
AppendText(...)50%271.42%
Create(...)100%1100%
Create(...)100%10%
CreateText(...)100%1100%
CreateText(...)100%1100%
Delete(...)100%1100%
GetLastAccessTime(...)100%1100%
GetLastAccessTimeUtc(...)100%1100%
GetLastWriteTime(...)100%1100%
GetLastWriteTimeUtc(...)100%1100%
Open(...)100%1100%
Open(...)100%1100%
OpenAsync(...)50%463.63%
OpenRead(...)100%1100%
OpenText(...)100%10%
OpenWrite(...)100%1100%
ReadAllBytes(...)100%1100%
ReadAllLines(...)100%1100%
ReadAllLines(...)100%2100%
ReadAllText(...)100%1100%
ReadAllText(...)100%1100%
ReadLines(...)100%1100%
ReadLines(...)100%1100%
SetLastAccessTime(...)100%1100%
SetLastAccessTimeUtc(...)100%1100%
SetLastWriteTime(...)100%1100%
SetLastWriteTimeUtc(...)100%1100%
WriteAllBytes(...)100%1100%
WriteAllLines(...)100%1100%
WriteAllLines(...)100%1100%
WriteAllLines(...)100%2100%
WriteAllLines(...)100%2100%
WriteAllText(...)100%1100%
WriteAllText(...)100%1100%
GetAttributes(...)50%275%
SetAttributes(...)50%275%
SynchronizeDirectories(...)50%455.55%
BeginSynchronizeDirectories(...)50%465.21%
EndSynchronizeDirectories(...)50%466.66%
InternalSynchronizeDirectories(...)77.77%1876%
InternalListDirectory(...)91.66%1293.93%
InternalDownloadFile(...)78.57%1481.81%
InternalUploadFile(...)87.5%2488.46%
OnConnected()100%1100%
OnDisconnecting()100%2100%
Dispose(...)75%466.66%
CreateAndConnectToSftpSession()100%1100%

File(s)

\home\appveyor\projects\ssh-net\src\Renci.SshNet\SftpClient.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Diagnostics.CodeAnalysis;
 4using System.Globalization;
 5using System.IO;
 6using System.Net;
 7using System.Runtime.CompilerServices;
 8using System.Text;
 9using System.Threading;
 10using System.Threading.Tasks;
 11
 12using Renci.SshNet.Abstractions;
 13using Renci.SshNet.Common;
 14using Renci.SshNet.Sftp;
 15
 16namespace Renci.SshNet
 17{
 18    /// <summary>
 19    /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH.
 20    /// </summary>
 21    public class SftpClient : BaseClient, ISftpClient
 22    {
 223        private static readonly Encoding Utf8NoBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInv
 24
 25        /// <summary>
 26        /// Holds the <see cref="ISftpSession"/> instance that is used to communicate to the
 27        /// SFTP server.
 28        /// </summary>
 29        private ISftpSession _sftpSession;
 30
 31        /// <summary>
 32        /// Holds the operation timeout.
 33        /// </summary>
 34        private int _operationTimeout;
 35
 36        /// <summary>
 37        /// Holds the size of the buffer.
 38        /// </summary>
 39        private uint _bufferSize;
 40
 41        /// <summary>
 42        /// Gets or sets the operation timeout.
 43        /// </summary>
 44        /// <value>
 45        /// The timeout to wait until an operation completes. The default value is negative
 46        /// one (-1) milliseconds, which indicates an infinite timeout period.
 47        /// </value>
 48        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 49        /// <exception cref="ArgumentOutOfRangeException"><paramref name="value"/> represents a value that is less than 
 50        public TimeSpan OperationTimeout
 51        {
 52            get
 1553            {
 1554                CheckDisposed();
 55
 1256                return TimeSpan.FromMilliseconds(_operationTimeout);
 1257            }
 58            set
 11059            {
 11060                CheckDisposed();
 61
 10762                var timeoutInMilliseconds = value.TotalMilliseconds;
 10763                if (timeoutInMilliseconds is < -1d or > int.MaxValue)
 664                {
 665                    throw new ArgumentOutOfRangeException(nameof(value), "The timeout must represent a value between -1 
 66                }
 67
 10168                _operationTimeout = (int) timeoutInMilliseconds;
 10169            }
 70        }
 71
 72        /// <summary>
 73        /// Gets or sets the maximum size of the buffer in bytes.
 74        /// </summary>
 75        /// <value>
 76        /// The size of the buffer. The default buffer size is 32768 bytes (32 KB).
 77        /// </value>
 78        /// <remarks>
 79        /// <para>
 80        /// For write operations, this limits the size of the payload for
 81        /// individual SSH_FXP_WRITE messages. The actual size is always
 82        /// capped at the maximum packet size supported by the peer
 83        /// (minus the size of protocol fields).
 84        /// </para>
 85        /// <para>
 86        /// For read operations, this controls the size of the payload which
 87        /// is requested from the peer in a SSH_FXP_READ message. The peer
 88        /// will send the requested number of bytes in a SSH_FXP_DATA message,
 89        /// possibly split over multiple SSH_MSG_CHANNEL_DATA messages.
 90        /// </para>
 91        /// <para>
 92        /// To optimize the size of the SSH packets sent by the peer,
 93        /// the actual requested size will take into account the size of the
 94        /// SSH_FXP_DATA protocol fields.
 95        /// </para>
 96        /// <para>
 97        /// The size of the each individual SSH_FXP_DATA message is limited to the
 98        /// local maximum packet size of the channel, which is set to <c>64 KB</c>
 99        /// for SSH.NET. However, the peer can limit this even further.
 100        /// </para>
 101        /// </remarks>
 102        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 103        public uint BufferSize
 104        {
 105            get
 7106            {
 7107                CheckDisposed();
 7108                return _bufferSize;
 7109            }
 110            set
 5111            {
 5112                CheckDisposed();
 5113                _bufferSize = value;
 5114            }
 115        }
 116
 117        /// <summary>
 118        /// Gets remote working directory.
 119        /// </summary>
 120        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 121        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 122        public string WorkingDirectory
 123        {
 124            get
 80125            {
 80126                CheckDisposed();
 127
 80128                if (_sftpSession is null)
 0129                {
 0130                    throw new SshConnectionException("Client not connected.");
 131                }
 132
 80133                return _sftpSession.WorkingDirectory;
 80134            }
 135        }
 136
 137        /// <summary>
 138        /// Gets sftp protocol version.
 139        /// </summary>
 140        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 141        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 142        public int ProtocolVersion
 143        {
 144            get
 0145            {
 0146                CheckDisposed();
 147
 0148                if (_sftpSession is null)
 0149                {
 0150                    throw new SshConnectionException("Client not connected.");
 151                }
 152
 0153                return (int) _sftpSession.ProtocolVersion;
 0154            }
 155        }
 156
 157        /// <summary>
 158        /// Gets the current SFTP session.
 159        /// </summary>
 160        /// <value>
 161        /// The current SFTP session.
 162        /// </value>
 163        internal ISftpSession SftpSession
 164        {
 9165            get { return _sftpSession; }
 166        }
 167
 168        #region Constructors
 169
 170        /// <summary>
 171        /// Initializes a new instance of the <see cref="SftpClient"/> class.
 172        /// </summary>
 173        /// <param name="connectionInfo">The connection info.</param>
 174        /// <exception cref="ArgumentNullException"><paramref name="connectionInfo"/> is <see langword="null"/>.</except
 175        public SftpClient(ConnectionInfo connectionInfo)
 319176            : this(connectionInfo, ownsConnectionInfo: false)
 319177        {
 319178        }
 179
 180        /// <summary>
 181        /// Initializes a new instance of the <see cref="SftpClient"/> class.
 182        /// </summary>
 183        /// <param name="host">Connection host.</param>
 184        /// <param name="port">Connection port.</param>
 185        /// <param name="username">Authentication username.</param>
 186        /// <param name="password">Authentication password.</param>
 187        /// <exception cref="ArgumentNullException"><paramref name="password"/> is <see langword="null"/>.</exception>
 188        /// <exception cref="ArgumentException"><paramref name="host"/> is invalid. <para>-or-</para> <paramref name="us
 189        /// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.Mi
 190        [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in
 191        public SftpClient(string host, int port, string username, string password)
 69192            : this(new PasswordConnectionInfo(host, port, username, password), ownsConnectionInfo: true)
 69193        {
 69194        }
 195
 196        /// <summary>
 197        /// Initializes a new instance of the <see cref="SftpClient"/> class.
 198        /// </summary>
 199        /// <param name="host">Connection host.</param>
 200        /// <param name="username">Authentication username.</param>
 201        /// <param name="password">Authentication password.</param>
 202        /// <exception cref="ArgumentNullException"><paramref name="password"/> is <see langword="null"/>.</exception>
 203        /// <exception cref="ArgumentException"><paramref name="host"/> is invalid. <para>-or-</para> <paramref name="us
 204        public SftpClient(string host, string username, string password)
 15205            : this(host, ConnectionInfo.DefaultPort, username, password)
 15206        {
 15207        }
 208
 209        /// <summary>
 210        /// Initializes a new instance of the <see cref="SftpClient"/> class.
 211        /// </summary>
 212        /// <param name="host">Connection host.</param>
 213        /// <param name="port">Connection port.</param>
 214        /// <param name="username">Authentication username.</param>
 215        /// <param name="keyFiles">Authentication private key file(s) .</param>
 216        /// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <see langword="null"/>.</exception>
 217        /// <exception cref="ArgumentException"><paramref name="host"/> is invalid. <para>-or-</para> <paramref name="us
 218        /// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="IPEndPoint.Mi
 219        [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in
 220        public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles)
 0221            : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true)
 0222        {
 0223        }
 224
 225        /// <summary>
 226        /// Initializes a new instance of the <see cref="SftpClient"/> class.
 227        /// </summary>
 228        /// <param name="host">Connection host.</param>
 229        /// <param name="username">Authentication username.</param>
 230        /// <param name="keyFiles">Authentication private key file(s) .</param>
 231        /// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is <see langword="null"/>.</exception>
 232        /// <exception cref="ArgumentException"><paramref name="host"/> is invalid. <para>-or-</para> <paramref name="us
 233        public SftpClient(string host, string username, params IPrivateKeySource[] keyFiles)
 0234            : this(host, ConnectionInfo.DefaultPort, username, keyFiles)
 0235        {
 0236        }
 237
 238        /// <summary>
 239        /// Initializes a new instance of the <see cref="SftpClient"/> class.
 240        /// </summary>
 241        /// <param name="connectionInfo">The connection info.</param>
 242        /// <param name="ownsConnectionInfo">Specified whether this instance owns the connection info.</param>
 243        /// <exception cref="ArgumentNullException"><paramref name="connectionInfo"/> is <see langword="null"/>.</except
 244        /// <remarks>
 245        /// If <paramref name="ownsConnectionInfo"/> is <see langword="true"/>, the connection info will be disposed whe
 246        /// instance is disposed.
 247        /// </remarks>
 248        private SftpClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo)
 388249            : this(connectionInfo, ownsConnectionInfo, new ServiceFactory())
 388250        {
 388251        }
 252
 253        /// <summary>
 254        /// Initializes a new instance of the <see cref="SftpClient"/> class.
 255        /// </summary>
 256        /// <param name="connectionInfo">The connection info.</param>
 257        /// <param name="ownsConnectionInfo">Specified whether this instance owns the connection info.</param>
 258        /// <param name="serviceFactory">The factory to use for creating new services.</param>
 259        /// <exception cref="ArgumentNullException"><paramref name="connectionInfo"/> is <see langword="null"/>.</except
 260        /// <exception cref="ArgumentNullException"><paramref name="serviceFactory"/> is <see langword="null"/>.</except
 261        /// <remarks>
 262        /// If <paramref name="ownsConnectionInfo"/> is <see langword="true"/>, the connection info will be disposed whe
 263        /// instance is disposed.
 264        /// </remarks>
 265        internal SftpClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory)
 493266            : base(connectionInfo, ownsConnectionInfo, serviceFactory)
 493267        {
 493268            _operationTimeout = SshNet.Session.Infinite;
 493269            _bufferSize = 1024 * 32;
 493270        }
 271
 272        #endregion Constructors
 273
 274        /// <summary>
 275        /// Changes remote directory to path.
 276        /// </summary>
 277        /// <param name="path">New directory path.</param>
 278        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 279        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 280        /// <exception cref="SftpPermissionDeniedException">Permission to change directory denied by remote host. <para>
 281        /// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</excep
 282        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the rem
 283        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 284        public void ChangeDirectory(string path)
 21285        {
 21286            CheckDisposed();
 287
 21288            if (path is null)
 1289            {
 1290                throw new ArgumentNullException(nameof(path));
 291            }
 292
 20293            if (_sftpSession is null)
 0294            {
 0295                throw new SshConnectionException("Client not connected.");
 296            }
 297
 20298            _sftpSession.ChangeDirectory(path);
 15299        }
 300
 301        /// <summary>
 302        /// Changes permissions of file(s) to specified mode.
 303        /// </summary>
 304        /// <param name="path">File(s) path, may match multiple files.</param>
 305        /// <param name="mode">The mode.</param>
 306        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 307        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 308        /// <exception cref="SftpPermissionDeniedException">Permission to change permission on the path(s) was denied by
 309        /// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</excep
 310        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the rem
 311        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 312        public void ChangePermissions(string path, short mode)
 1313        {
 1314            var file = Get(path);
 1315            file.SetPermissions(mode);
 1316        }
 317
 318        /// <summary>
 319        /// Creates remote directory specified by path.
 320        /// </summary>
 321        /// <param name="path">Directory path to create.</param>
 322        /// <exception cref="ArgumentException"><paramref name="path"/> is <see langword="null"/> or contains only white
 323        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 324        /// <exception cref="SftpPermissionDeniedException">Permission to create the directory was denied by the remote 
 325        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the rem
 326        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 327        public void CreateDirectory(string path)
 10037328        {
 10037329            CheckDisposed();
 330
 10037331            if (string.IsNullOrWhiteSpace(path))
 0332            {
 0333                throw new ArgumentException(path);
 334            }
 335
 10037336            if (_sftpSession is null)
 0337            {
 0338                throw new SshConnectionException("Client not connected.");
 339            }
 340
 10037341            var fullPath = _sftpSession.GetCanonicalPath(path);
 342
 10037343            _sftpSession.RequestMkDir(fullPath);
 10034344        }
 345
 346        /// <summary>
 347        /// Deletes remote directory specified by path.
 348        /// </summary>
 349        /// <param name="path">Directory to be deleted path.</param>
 350        /// <exception cref="ArgumentException"><paramref name="path"/> is <see langword="null"/> or contains only white
 351        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 352        /// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</excep
 353        /// <exception cref="SftpPermissionDeniedException">Permission to delete the directory was denied by the remote 
 354        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the rem
 355        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 356        public void DeleteDirectory(string path)
 42357        {
 42358            CheckDisposed();
 359
 42360            if (string.IsNullOrWhiteSpace(path))
 1361            {
 1362                throw new ArgumentException("path");
 363            }
 364
 41365            if (_sftpSession is null)
 3366            {
 3367                throw new SshConnectionException("Client not connected.");
 368            }
 369
 38370            var fullPath = _sftpSession.GetCanonicalPath(path);
 371
 38372            _sftpSession.RequestRmDir(fullPath);
 36373        }
 374
 375        /// <summary>
 376        /// Deletes remote file specified by path.
 377        /// </summary>
 378        /// <param name="path">File to be deleted path.</param>
 379        /// <exception cref="ArgumentException"><paramref name="path"/> is <see langword="null"/> or contains only white
 380        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 381        /// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</excep
 382        /// <exception cref="SftpPermissionDeniedException">Permission to delete the file was denied by the remote host.
 383        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the rem
 384        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 385        public void DeleteFile(string path)
 155386        {
 155387            CheckDisposed();
 388
 155389            if (string.IsNullOrWhiteSpace(path))
 3390            {
 3391                throw new ArgumentException("path");
 392            }
 393
 152394            if (_sftpSession is null)
 0395            {
 0396                throw new SshConnectionException("Client not connected.");
 397            }
 398
 152399            var fullPath = _sftpSession.GetCanonicalPath(path);
 400
 152401            _sftpSession.RequestRemove(fullPath);
 152402        }
 403
 404        /// <summary>
 405        /// Asynchronously deletes remote file specified by path.
 406        /// </summary>
 407        /// <param name="path">File to be deleted path.</param>
 408        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
 409        /// <returns>A <see cref="Task"/> that represents the asynchronous delete operation.</returns>
 410        /// <exception cref="ArgumentException"><paramref name="path"/> is <see langword="null"/> or contains only white
 411        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 412        /// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</excep
 413        /// <exception cref="SftpPermissionDeniedException">Permission to delete the file was denied by the remote host.
 414        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the rem
 415        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 416        public async Task DeleteFileAsync(string path, CancellationToken cancellationToken)
 3417        {
 3418            CheckDisposed();
 419
 3420            if (string.IsNullOrWhiteSpace(path))
 3421            {
 3422                throw new ArgumentException("path");
 423            }
 424
 0425            if (_sftpSession is null)
 0426            {
 0427                throw new SshConnectionException("Client not connected.");
 428            }
 429
 0430            cancellationToken.ThrowIfCancellationRequested();
 431
 0432            var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false);
 0433            await _sftpSession.RequestRemoveAsync(fullPath, cancellationToken).ConfigureAwait(false);
 0434        }
 435
 436        /// <summary>
 437        /// Renames remote file from old path to new path.
 438        /// </summary>
 439        /// <param name="oldPath">Path to the old file location.</param>
 440        /// <param name="newPath">Path to the new file location.</param>
 441        /// <exception cref="ArgumentNullException"><paramref name="oldPath"/> is <see langword="null"/>. <para>-or-</pa
 442        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 443        /// <exception cref="SftpPermissionDeniedException">Permission to rename the file was denied by the remote host.
 444        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the rem
 445        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 446        public void RenameFile(string oldPath, string newPath)
 2447        {
 2448            RenameFile(oldPath, newPath, isPosix: false);
 1449        }
 450
 451        /// <summary>
 452        /// Renames remote file from old path to new path.
 453        /// </summary>
 454        /// <param name="oldPath">Path to the old file location.</param>
 455        /// <param name="newPath">Path to the new file location.</param>
 456        /// <param name="isPosix">if set to <see langword="true"/> then perform a posix rename.</param>
 457        /// <exception cref="ArgumentNullException"><paramref name="oldPath" /> is <see langword="null"/>. <para>-or-</p
 458        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 459        /// <exception cref="SftpPermissionDeniedException">Permission to rename the file was denied by the remote host.
 460        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 461        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 462        public void RenameFile(string oldPath, string newPath, bool isPosix)
 2463        {
 2464            CheckDisposed();
 465
 2466            if (oldPath is null)
 1467            {
 1468                throw new ArgumentNullException(nameof(oldPath));
 469            }
 470
 1471            if (newPath is null)
 0472            {
 0473                throw new ArgumentNullException(nameof(newPath));
 474            }
 475
 1476            if (_sftpSession is null)
 0477            {
 0478                throw new SshConnectionException("Client not connected.");
 479            }
 480
 1481            var oldFullPath = _sftpSession.GetCanonicalPath(oldPath);
 482
 1483            var newFullPath = _sftpSession.GetCanonicalPath(newPath);
 484
 1485            if (isPosix)
 0486            {
 0487                _sftpSession.RequestPosixRename(oldFullPath, newFullPath);
 0488            }
 489            else
 1490            {
 1491                _sftpSession.RequestRename(oldFullPath, newFullPath);
 1492            }
 1493        }
 494
 495        /// <summary>
 496        /// Asynchronously renames remote file from old path to new path.
 497        /// </summary>
 498        /// <param name="oldPath">Path to the old file location.</param>
 499        /// <param name="newPath">Path to the new file location.</param>
 500        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
 501        /// <returns>A <see cref="Task"/> that represents the asynchronous rename operation.</returns>
 502        /// <exception cref="ArgumentNullException"><paramref name="oldPath"/> is <see langword="null"/>. <para>-or-</pa
 503        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 504        /// <exception cref="SftpPermissionDeniedException">Permission to rename the file was denied by the remote host.
 505        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the rem
 506        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 507        public async Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken)
 2508        {
 2509            CheckDisposed();
 510
 2511            if (oldPath is null)
 1512            {
 1513                throw new ArgumentNullException(nameof(oldPath));
 514            }
 515
 1516            if (newPath is null)
 0517            {
 0518                throw new ArgumentNullException(nameof(newPath));
 519            }
 520
 1521            if (_sftpSession is null)
 0522            {
 0523                throw new SshConnectionException("Client not connected.");
 524            }
 525
 1526            cancellationToken.ThrowIfCancellationRequested();
 527
 1528            var oldFullPath = await _sftpSession.GetCanonicalPathAsync(oldPath, cancellationToken).ConfigureAwait(false)
 1529            var newFullPath = await _sftpSession.GetCanonicalPathAsync(newPath, cancellationToken).ConfigureAwait(false)
 1530            await _sftpSession.RequestRenameAsync(oldFullPath, newFullPath, cancellationToken).ConfigureAwait(false);
 1531        }
 532
 533        /// <summary>
 534        /// Creates a symbolic link from old path to new path.
 535        /// </summary>
 536        /// <param name="path">The old path.</param>
 537        /// <param name="linkPath">The new path.</param>
 538        /// <exception cref="ArgumentException"><paramref name="path"/> is <see langword="null"/>. <para>-or-</para> <pa
 539        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 540        /// <exception cref="SftpPermissionDeniedException">Permission to create the symbolic link was denied by the rem
 541        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the rem
 542        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 543        public void SymbolicLink(string path, string linkPath)
 0544        {
 0545            CheckDisposed();
 546
 0547            if (string.IsNullOrWhiteSpace(path))
 0548            {
 0549                throw new ArgumentException("path");
 550            }
 551
 0552            if (string.IsNullOrWhiteSpace(linkPath))
 0553            {
 0554                throw new ArgumentException("linkPath");
 555            }
 556
 0557            if (_sftpSession is null)
 0558            {
 0559                throw new SshConnectionException("Client not connected.");
 560            }
 561
 0562            var fullPath = _sftpSession.GetCanonicalPath(path);
 563
 0564            var linkFullPath = _sftpSession.GetCanonicalPath(linkPath);
 565
 0566            _sftpSession.RequestSymLink(fullPath, linkFullPath);
 0567        }
 568
 569        /// <summary>
 570        /// Retrieves list of files in remote directory.
 571        /// </summary>
 572        /// <param name="path">The path.</param>
 573        /// <param name="listCallback">The list callback.</param>
 574        /// <returns>
 575        /// A list of files.
 576        /// </returns>
 577        /// <exception cref="ArgumentNullException"><paramref name="path" /> is <see langword="null"/>.</exception>
 578        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 579        /// <exception cref="SftpPermissionDeniedException">Permission to list the contents of the directory was denied 
 580        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 581        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 582        public IEnumerable<ISftpFile> ListDirectory(string path, Action<int> listCallback = null)
 16583        {
 16584            CheckDisposed();
 585
 16586            return InternalListDirectory(path, listCallback);
 7587        }
 588
 589        /// <summary>
 590        /// Asynchronously enumerates the files in remote directory.
 591        /// </summary>
 592        /// <param name="path">The path.</param>
 593        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
 594        /// <returns>
 595        /// An <see cref="IAsyncEnumerable{T}"/> of <see cref="ISftpFile"/> that represents the asynchronous enumeration
 596        /// The enumeration contains an async stream of <see cref="ISftpFile"/> for the files in the directory specified
 597        /// </returns>
 598        /// <exception cref="ArgumentNullException"><paramref name="path" /> is <see langword="null"/>.</exception>
 599        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 600        /// <exception cref="SftpPermissionDeniedException">Permission to list the contents of the directory was denied 
 601        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 602        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 603        public async IAsyncEnumerable<ISftpFile> ListDirectoryAsync(string path, [EnumeratorCancellation] CancellationTo
 5604        {
 5605            CheckDisposed();
 606
 5607            if (path is null)
 0608            {
 0609                throw new ArgumentNullException(nameof(path));
 610            }
 611
 5612            if (_sftpSession is null)
 3613            {
 3614                throw new SshConnectionException("Client not connected.");
 615            }
 616
 2617            cancellationToken.ThrowIfCancellationRequested();
 618
 2619            var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false);
 620
 2621            var handle = await _sftpSession.RequestOpenDirAsync(fullPath, cancellationToken).ConfigureAwait(false);
 622            try
 2623            {
 2624                var basePath = (fullPath[fullPath.Length - 1] == '/') ?
 2625                    fullPath :
 2626                    fullPath + '/';
 627
 4628                while (true)
 4629                {
 4630                    var files = await _sftpSession.RequestReadDirAsync(handle, cancellationToken).ConfigureAwait(false);
 4631                    if (files is null)
 2632                    {
 2633                        break;
 634                    }
 635
 86636                    foreach (var file in files)
 40637                    {
 40638                        yield return new SftpFile(_sftpSession, basePath + file.Key, file.Value);
 40639                    }
 2640                }
 2641            }
 642            finally
 2643            {
 2644                await _sftpSession.RequestCloseAsync(handle, cancellationToken).ConfigureAwait(false);
 2645            }
 2646        }
 647
 648        /// <summary>
 649        /// Begins an asynchronous operation of retrieving list of files in remote directory.
 650        /// </summary>
 651        /// <param name="path">The path.</param>
 652        /// <param name="asyncCallback">The method to be called when the asynchronous write operation is completed.</par
 653        /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request fro
 654        /// <param name="listCallback">The list callback.</param>
 655        /// <returns>
 656        /// An <see cref="IAsyncResult" /> that references the asynchronous operation.
 657        /// </returns>
 658        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 659        public IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback, object state, Action<int> listC
 5660        {
 5661            CheckDisposed();
 662
 5663            var asyncResult = new SftpListDirectoryAsyncResult(asyncCallback, state);
 664
 5665            ThreadAbstraction.ExecuteThread(() =>
 5666            {
 5667                try
 5668                {
 5669                    var result = InternalListDirectory(path, count =>
 3670                    {
 3671                        asyncResult.Update(count);
 5672
 3673                        listCallback?.Invoke(count);
 8674                    });
 5675
 3676                    asyncResult.SetAsCompleted(result, completedSynchronously: false);
 3677                }
 1678                catch (Exception exp)
 1679                {
 1680                    asyncResult.SetAsCompleted(exp, completedSynchronously: false);
 1681                }
 9682            });
 683
 5684            return asyncResult;
 5685        }
 686
 687        /// <summary>
 688        /// Ends an asynchronous operation of retrieving list of files in remote directory.
 689        /// </summary>
 690        /// <param name="asyncResult">The pending asynchronous SFTP request.</param>
 691        /// <returns>
 692        /// A list of files.
 693        /// </returns>
 694        /// <exception cref="ArgumentException">The <see cref="IAsyncResult"/> object did not come from the correspondin
 695        public IEnumerable<ISftpFile> EndListDirectory(IAsyncResult asyncResult)
 4696        {
 4697            if (asyncResult is not SftpListDirectoryAsyncResult ar || ar.EndInvokeCalled)
 1698            {
 1699                throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async me
 700            }
 701
 702            // Wait for operation to complete, then return result or throw exception
 3703            return ar.EndInvoke();
 2704        }
 705
 706        /// <summary>
 707        /// Gets reference to remote file or directory.
 708        /// </summary>
 709        /// <param name="path">The path.</param>
 710        /// <returns>
 711        /// A reference to <see cref="ISftpFile"/> file object.
 712        /// </returns>
 713        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 714        /// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</excep
 715        /// <exception cref="ArgumentNullException"><paramref name="path" /> is <see langword="null"/>.</exception>
 716        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 717        public ISftpFile Get(string path)
 52718        {
 52719            CheckDisposed();
 720
 52721            if (path is null)
 1722            {
 1723                throw new ArgumentNullException(nameof(path));
 724            }
 725
 51726            if (_sftpSession is null)
 0727            {
 0728                throw new SshConnectionException("Client not connected.");
 729            }
 730
 51731            var fullPath = _sftpSession.GetCanonicalPath(path);
 732
 51733            var attributes = _sftpSession.RequestLStat(fullPath);
 734
 50735            return new SftpFile(_sftpSession, fullPath, attributes);
 50736        }
 737
 738        /// <summary>
 739        /// Checks whether file or directory exists.
 740        /// </summary>
 741        /// <param name="path">The path.</param>
 742        /// <returns>
 743        /// <see langword="true"/> if directory or file exists; otherwise <see langword="false"/>.
 744        /// </returns>
 745        /// <exception cref="ArgumentException"><paramref name="path"/> is <see langword="null"/> or contains only white
 746        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 747        /// <exception cref="SftpPermissionDeniedException">Permission to perform the operation was denied by the remote
 748        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the rem
 749        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 750        public bool Exists(string path)
 439751        {
 439752            CheckDisposed();
 753
 439754            if (string.IsNullOrWhiteSpace(path))
 0755            {
 0756                throw new ArgumentException("path");
 757            }
 758
 439759            if (_sftpSession is null)
 0760            {
 0761                throw new SshConnectionException("Client not connected.");
 762            }
 763
 439764            var fullPath = _sftpSession.GetCanonicalPath(path);
 765
 766            /*
 767             * Using SSH_FXP_REALPATH is not an alternative as the SFTP specification has not always
 768             * been clear on how the server should respond when the specified path is not present on
 769             * the server:
 770             *
 771             * SSH 1 to 4:
 772             * No mention of how the server should respond if the path is not present on the server.
 773             *
 774             * SSH 5:
 775             * The server SHOULD fail the request if the path is not present on the server.
 776             *
 777             * SSH 6:
 778             * Draft 06: The server SHOULD fail the request if the path is not present on the server.
 779             * Draft 07 to 13: The server MUST NOT fail the request if the path does not exist.
 780             *
 781             * Note that SSH 6 (draft 06 and forward) allows for more control options, but we
 782             * currently only support up to v3.
 783             */
 784
 785            try
 439786            {
 439787                _ = _sftpSession.RequestLStat(fullPath);
 185788                return true;
 789            }
 254790            catch (SftpPathNotFoundException)
 254791            {
 254792                return false;
 793            }
 439794        }
 795
 796        /// <summary>
 797        /// Downloads remote file specified by the path into the stream.
 798        /// </summary>
 799        /// <param name="path">File to download.</param>
 800        /// <param name="output">Stream to write the file into.</param>
 801        /// <param name="downloadCallback">The download callback.</param>
 802        /// <exception cref="ArgumentNullException"><paramref name="output" /> is <see langword="null"/>.</exception>
 803        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains only whit
 804        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 805        /// <exception cref="SftpPermissionDeniedException">Permission to perform the operation was denied by the remote
 806        /// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</excep
 807        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 808        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 809        /// <remarks>
 810        /// Method calls made by this method to <paramref name="output" />, may under certain conditions result in excep
 811        /// </remarks>
 812        public void DownloadFile(string path, Stream output, Action<ulong> downloadCallback = null)
 38813        {
 38814            CheckDisposed();
 815
 38816            InternalDownloadFile(path, output, asyncResult: null, downloadCallback);
 35817        }
 818
 819        /// <summary>
 820        /// Begins an asynchronous file downloading into the stream.
 821        /// </summary>
 822        /// <param name="path">The path.</param>
 823        /// <param name="output">The output.</param>
 824        /// <returns>
 825        /// An <see cref="IAsyncResult" /> that references the asynchronous operation.
 826        /// </returns>
 827        /// <exception cref="ArgumentNullException"><paramref name="output" /> is <see langword="null"/>.</exception>
 828        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains only whit
 829        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 830        /// <exception cref="SftpPermissionDeniedException">Permission to perform the operation was denied by the remote
 831        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 832        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 833        /// <remarks>
 834        /// Method calls made by this method to <paramref name="output" />, may under certain conditions result in excep
 835        /// </remarks>
 836        public IAsyncResult BeginDownloadFile(string path, Stream output)
 1837        {
 1838            return BeginDownloadFile(path, output, asyncCallback: null, state: null);
 1839        }
 840
 841        /// <summary>
 842        /// Begins an asynchronous file downloading into the stream.
 843        /// </summary>
 844        /// <param name="path">The path.</param>
 845        /// <param name="output">The output.</param>
 846        /// <param name="asyncCallback">The method to be called when the asynchronous write operation is completed.</par
 847        /// <returns>
 848        /// An <see cref="IAsyncResult" /> that references the asynchronous operation.
 849        /// </returns>
 850        /// <exception cref="ArgumentNullException"><paramref name="output" /> is <see langword="null"/>.</exception>
 851        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains only whit
 852        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 853        /// <exception cref="SftpPermissionDeniedException">Permission to perform the operation was denied by the remote
 854        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 855        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 856        /// <remarks>
 857        /// Method calls made by this method to <paramref name="output" />, may under certain conditions result in excep
 858        /// </remarks>
 859        public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback asyncCallback)
 0860        {
 0861            return BeginDownloadFile(path, output, asyncCallback, state: null);
 0862        }
 863
 864        /// <summary>
 865        /// Begins an asynchronous file downloading into the stream.
 866        /// </summary>
 867        /// <param name="path">The path.</param>
 868        /// <param name="output">The output.</param>
 869        /// <param name="asyncCallback">The method to be called when the asynchronous write operation is completed.</par
 870        /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request fro
 871        /// <param name="downloadCallback">The download callback.</param>
 872        /// <returns>
 873        /// An <see cref="IAsyncResult" /> that references the asynchronous operation.
 874        /// </returns>
 875        /// <exception cref="ArgumentNullException"><paramref name="output" /> is <see langword="null"/>.</exception>
 876        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains only whit
 877        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 878        /// <remarks>
 879        /// Method calls made by this method to <paramref name="output" />, may under certain conditions result in excep
 880        /// </remarks>
 881        public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback asyncCallback, object state, Act
 16882        {
 16883            CheckDisposed();
 884
 16885            if (string.IsNullOrWhiteSpace(path))
 2886            {
 2887                throw new ArgumentException("path");
 888            }
 889
 14890            if (output is null)
 1891            {
 1892                throw new ArgumentNullException(nameof(output));
 893            }
 894
 13895            var asyncResult = new SftpDownloadAsyncResult(asyncCallback, state);
 896
 13897            ThreadAbstraction.ExecuteThread(() =>
 13898            {
 13899                try
 13900                {
 13901                    InternalDownloadFile(path, output, asyncResult, offset =>
 1643902                    {
 1643903                        asyncResult.Update(offset);
 13904
 1643905                        downloadCallback?.Invoke(offset);
 1656906                    });
 13907
 11908                    asyncResult.SetAsCompleted(exception: null, completedSynchronously: false);
 11909                }
 2910                catch (Exception exp)
 2911                {
 2912                    asyncResult.SetAsCompleted(exp, completedSynchronously: false);
 2913                }
 26914            });
 915
 13916            return asyncResult;
 13917        }
 918
 919        /// <summary>
 920        /// Ends an asynchronous file downloading into the stream.
 921        /// </summary>
 922        /// <param name="asyncResult">The pending asynchronous SFTP request.</param>
 923        /// <exception cref="ArgumentException">The <see cref="IAsyncResult"/> object did not come from the correspondin
 924        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 925        /// <exception cref="SftpPermissionDeniedException">Permission to perform the operation was denied by the remote
 926        /// <exception cref="SftpPathNotFoundException">The path was not found on the remote host.</exception>
 927        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 928        public void EndDownloadFile(IAsyncResult asyncResult)
 13929        {
 13930            if (asyncResult is not SftpDownloadAsyncResult ar || ar.EndInvokeCalled)
 1931            {
 1932                throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async me
 933            }
 934
 935            // Wait for operation to complete, then return result or throw exception
 12936            ar.EndInvoke();
 11937        }
 938
 939        /// <summary>
 940        /// Uploads stream into remote file.
 941        /// </summary>
 942        /// <param name="input">Data input stream.</param>
 943        /// <param name="path">Remote file path.</param>
 944        /// <param name="uploadCallback">The upload callback.</param>
 945        /// <exception cref="ArgumentNullException"><paramref name="input" /> is <see langword="null"/>.</exception>
 946        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains only whit
 947        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 948        /// <exception cref="SftpPermissionDeniedException">Permission to upload the file was denied by the remote host.
 949        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 950        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 951        /// <remarks>
 952        /// Method calls made by this method to <paramref name="input" />, may under certain conditions result in except
 953        /// </remarks>
 954        public void UploadFile(Stream input, string path, Action<ulong> uploadCallback = null)
 34955        {
 34956            UploadFile(input, path, canOverride: true, uploadCallback);
 33957        }
 958
 959        /// <summary>
 960        /// Uploads stream into remote file.
 961        /// </summary>
 962        /// <param name="input">Data input stream.</param>
 963        /// <param name="path">Remote file path.</param>
 964        /// <param name="canOverride">if set to <see langword="true"/> then existing file will be overwritten.</param>
 965        /// <param name="uploadCallback">The upload callback.</param>
 966        /// <exception cref="ArgumentNullException"><paramref name="input" /> is <see langword="null"/>.</exception>
 967        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains only whit
 968        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 969        /// <exception cref="SftpPermissionDeniedException">Permission to upload the file was denied by the remote host.
 970        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 971        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 972        /// <remarks>
 973        /// Method calls made by this method to <paramref name="input" />, may under certain conditions result in except
 974        /// </remarks>
 975        public void UploadFile(Stream input, string path, bool canOverride, Action<ulong> uploadCallback = null)
 34976        {
 34977            CheckDisposed();
 978
 34979            var flags = Flags.Write | Flags.Truncate;
 980
 34981            if (canOverride)
 34982            {
 34983                flags |= Flags.CreateNewOrOpen;
 34984            }
 985            else
 0986            {
 0987                flags |= Flags.CreateNew;
 0988            }
 989
 34990            InternalUploadFile(input, path, flags, asyncResult: null, uploadCallback);
 33991        }
 992
 993        /// <summary>
 994        /// Begins an asynchronous uploading the stream into remote file.
 995        /// </summary>
 996        /// <param name="input">Data input stream.</param>
 997        /// <param name="path">Remote file path.</param>
 998        /// <returns>
 999        /// An <see cref="IAsyncResult" /> that references the asynchronous operation.
 1000        /// </returns>
 1001        /// <exception cref="ArgumentNullException"><paramref name="input" /> is <see langword="null"/>.</exception>
 1002        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains only whit
 1003        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1004        /// <exception cref="SftpPermissionDeniedException">Permission to list the contents of the directory was denied 
 1005        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 1006        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1007        /// <remarks>
 1008        /// <para>
 1009        /// Method calls made by this method to <paramref name="input" />, may under certain conditions result in except
 1010        /// </para>
 1011        /// <para>
 1012        /// If the remote file already exists, it is overwritten and truncated.
 1013        /// </para>
 1014        /// </remarks>
 1015        public IAsyncResult BeginUploadFile(Stream input, string path)
 31016        {
 31017            return BeginUploadFile(input, path, canOverride: true, asyncCallback: null, state: null);
 31018        }
 1019
 1020        /// <summary>
 1021        /// Begins an asynchronous uploading the stream into remote file.
 1022        /// </summary>
 1023        /// <param name="input">Data input stream.</param>
 1024        /// <param name="path">Remote file path.</param>
 1025        /// <param name="asyncCallback">The method to be called when the asynchronous write operation is completed.</par
 1026        /// <returns>
 1027        /// An <see cref="IAsyncResult" /> that references the asynchronous operation.
 1028        /// </returns>
 1029        /// <exception cref="ArgumentNullException"><paramref name="input" /> is <see langword="null"/>.</exception>
 1030        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains only whit
 1031        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1032        /// <exception cref="SftpPermissionDeniedException">Permission to list the contents of the directory was denied 
 1033        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 1034        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1035        /// <remarks>
 1036        /// <para>
 1037        /// Method calls made by this method to <paramref name="input" />, may under certain conditions result in except
 1038        /// </para>
 1039        /// <para>
 1040        /// If the remote file already exists, it is overwritten and truncated.
 1041        /// </para>
 1042        /// </remarks>
 1043        public IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback asyncCallback)
 11044        {
 11045            return BeginUploadFile(input, path, canOverride: true, asyncCallback, state: null);
 11046        }
 1047
 1048        /// <summary>
 1049        /// Begins an asynchronous uploading the stream into remote file.
 1050        /// </summary>
 1051        /// <param name="input">Data input stream.</param>
 1052        /// <param name="path">Remote file path.</param>
 1053        /// <param name="asyncCallback">The method to be called when the asynchronous write operation is completed.</par
 1054        /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request fro
 1055        /// <param name="uploadCallback">The upload callback.</param>
 1056        /// <returns>
 1057        /// An <see cref="IAsyncResult" /> that references the asynchronous operation.
 1058        /// </returns>
 1059        /// <exception cref="ArgumentNullException"><paramref name="input" /> is <see langword="null"/>.</exception>
 1060        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains only whit
 1061        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1062        /// <exception cref="SftpPermissionDeniedException">Permission to list the contents of the directory was denied 
 1063        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 1064        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1065        /// <remarks>
 1066        /// <para>
 1067        /// Method calls made by this method to <paramref name="input" />, may under certain conditions result in except
 1068        /// </para>
 1069        /// <para>
 1070        /// If the remote file already exists, it is overwritten and truncated.
 1071        /// </para>
 1072        /// </remarks>
 1073        public IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback asyncCallback, object state, Action
 151074        {
 151075            return BeginUploadFile(input, path, canOverride: true, asyncCallback, state, uploadCallback);
 121076        }
 1077
 1078        /// <summary>
 1079        /// Begins an asynchronous uploading the stream into remote file.
 1080        /// </summary>
 1081        /// <param name="input">Data input stream.</param>
 1082        /// <param name="path">Remote file path.</param>
 1083        /// <param name="canOverride">Specified whether an existing file can be overwritten.</param>
 1084        /// <param name="asyncCallback">The method to be called when the asynchronous write operation is completed.</par
 1085        /// <param name="state">A user-provided object that distinguishes this particular asynchronous write request fro
 1086        /// <param name="uploadCallback">The upload callback.</param>
 1087        /// <returns>
 1088        /// An <see cref="IAsyncResult" /> that references the asynchronous operation.
 1089        /// </returns>
 1090        /// <exception cref="ArgumentNullException"><paramref name="input" /> is <see langword="null"/>.</exception>
 1091        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains only whit
 1092        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1093        /// <remarks>
 1094        /// <para>
 1095        /// Method calls made by this method to <paramref name="input" />, may under certain conditions result in except
 1096        /// </para>
 1097        /// <para>
 1098        /// When <paramref name="path"/> refers to an existing file, set <paramref name="canOverride"/> to <see langword
 1099        /// If <paramref name="canOverride"/> is <see langword="false"/>, the upload will fail and <see cref="EndUploadF
 1100        /// <see cref="SshException"/>.
 1101        /// </para>
 1102        /// </remarks>
 1103        public IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, AsyncCallback asyncCallback, ob
 251104        {
 251105            CheckDisposed();
 1106
 251107            if (input is null)
 11108            {
 11109                throw new ArgumentNullException(nameof(input));
 1110            }
 1111
 241112            if (string.IsNullOrWhiteSpace(path))
 21113            {
 21114                throw new ArgumentException("path");
 1115            }
 1116
 221117            var flags = Flags.Write | Flags.Truncate;
 1118
 221119            if (canOverride)
 191120            {
 191121                flags |= Flags.CreateNewOrOpen;
 191122            }
 1123            else
 31124            {
 31125                flags |= Flags.CreateNew;
 31126            }
 1127
 221128            var asyncResult = new SftpUploadAsyncResult(asyncCallback, state);
 1129
 221130            ThreadAbstraction.ExecuteThread(() =>
 221131            {
 221132                try
 221133                {
 221134                    InternalUploadFile(input, path, flags, asyncResult, offset =>
 16491135                        {
 16491136                            asyncResult.Update(offset);
 16491137                            uploadCallback?.Invoke(offset);
 16711138                        });
 221139
 171140                    asyncResult.SetAsCompleted(exception: null, completedSynchronously: false);
 171141                }
 51142                catch (Exception exp)
 51143                {
 51144                    asyncResult.SetAsCompleted(exception: exp, completedSynchronously: false);
 51145                }
 441146            });
 1147
 221148            return asyncResult;
 221149        }
 1150
 1151        /// <summary>
 1152        /// Ends an asynchronous uploading the stream into remote file.
 1153        /// </summary>
 1154        /// <param name="asyncResult">The pending asynchronous SFTP request.</param>
 1155        /// <exception cref="ArgumentException">The <see cref="IAsyncResult"/> object did not come from the correspondin
 1156        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1157        /// <exception cref="SftpPathNotFoundException">The directory of the file was not found on the remote host.</exc
 1158        /// <exception cref="SftpPermissionDeniedException">Permission to upload the file was denied by the remote host.
 1159        /// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the re
 1160        public void EndUploadFile(IAsyncResult asyncResult)
 211161        {
 211162            if (asyncResult is not SftpUploadAsyncResult ar || ar.EndInvokeCalled)
 11163            {
 11164                throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async me
 1165            }
 1166
 1167            // Wait for operation to complete, then return result or throw exception
 201168            ar.EndInvoke();
 161169        }
 1170
 1171        /// <summary>
 1172        /// Gets status using statvfs@openssh.com request.
 1173        /// </summary>
 1174        /// <param name="path">The path.</param>
 1175        /// <returns>
 1176        /// A <see cref="SftpFileSytemInformation"/> instance that contains file status information.
 1177        /// </returns>
 1178        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1179        /// <exception cref="ArgumentNullException"><paramref name="path" /> is <see langword="null"/>.</exception>
 1180        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1181        public SftpFileSytemInformation GetStatus(string path)
 01182        {
 01183            CheckDisposed();
 1184
 01185            if (path is null)
 01186            {
 01187                throw new ArgumentNullException(nameof(path));
 1188            }
 1189
 01190            if (_sftpSession is null)
 01191            {
 01192                throw new SshConnectionException("Client not connected.");
 1193            }
 1194
 01195            var fullPath = _sftpSession.GetCanonicalPath(path);
 1196
 01197            return _sftpSession.RequestStatVfs(fullPath);
 01198        }
 1199
 1200        /// <summary>
 1201        /// Asynchronously gets status using statvfs@openssh.com request.
 1202        /// </summary>
 1203        /// <param name="path">The path.</param>
 1204        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
 1205        /// <returns>
 1206        /// A <see cref="Task{SftpFileSytemInformation}"/> that represents the status operation.
 1207        /// The task result contains the <see cref="SftpFileSytemInformation"/> instance that contains file status infor
 1208        /// </returns>
 1209        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1210        /// <exception cref="ArgumentNullException"><paramref name="path" /> is <see langword="null"/>.</exception>
 1211        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1212        public async Task<SftpFileSytemInformation> GetStatusAsync(string path, CancellationToken cancellationToken)
 01213        {
 01214            CheckDisposed();
 1215
 01216            if (path is null)
 01217            {
 01218                throw new ArgumentNullException(nameof(path));
 1219            }
 1220
 01221            if (_sftpSession is null)
 01222            {
 01223                throw new SshConnectionException("Client not connected.");
 1224            }
 1225
 01226            cancellationToken.ThrowIfCancellationRequested();
 1227
 01228            var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false);
 01229            return await _sftpSession.RequestStatVfsAsync(fullPath, cancellationToken).ConfigureAwait(false);
 01230        }
 1231
 1232        #region File Methods
 1233
 1234        /// <summary>
 1235        /// Appends lines to a file, creating the file if it does not already exist.
 1236        /// </summary>
 1237        /// <param name="path">The file to append the lines to. The file is created if it does not already exist.</param
 1238        /// <param name="contents">The lines to append to the file.</param>
 1239        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>. <para>-or-</para>
 1240        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1241        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1242        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1243        /// <remarks>
 1244        /// The characters are written to the file using UTF-8 encoding without a byte-order mark (BOM).
 1245        /// </remarks>
 1246        public void AppendAllLines(string path, IEnumerable<string> contents)
 31247        {
 31248            CheckDisposed();
 1249
 31250            if (contents is null)
 01251            {
 01252                throw new ArgumentNullException(nameof(contents));
 1253            }
 1254
 31255            using (var stream = AppendText(path))
 21256            {
 181257                foreach (var line in contents)
 61258                {
 61259                    stream.WriteLine(line);
 61260                }
 21261            }
 21262        }
 1263
 1264        /// <summary>
 1265        /// Appends lines to a file by using a specified encoding, creating the file if it does not already exist.
 1266        /// </summary>
 1267        /// <param name="path">The file to append the lines to. The file is created if it does not already exist.</param
 1268        /// <param name="contents">The lines to append to the file.</param>
 1269        /// <param name="encoding">The character encoding to use.</param>
 1270        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>. <para>-or-</para>
 1271        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1272        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1273        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1274        public void AppendAllLines(string path, IEnumerable<string> contents, Encoding encoding)
 31275        {
 31276            CheckDisposed();
 1277
 31278            if (contents is null)
 01279            {
 01280                throw new ArgumentNullException(nameof(contents));
 1281            }
 1282
 31283            using (var stream = AppendText(path, encoding))
 21284            {
 181285                foreach (var line in contents)
 61286                {
 61287                    stream.WriteLine(line);
 61288                }
 21289            }
 21290        }
 1291
 1292        /// <summary>
 1293        /// Appends the specified string to the file, creating the file if it does not already exist.
 1294        /// </summary>
 1295        /// <param name="path">The file to append the specified string to.</param>
 1296        /// <param name="contents">The string to append to the file.</param>
 1297        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>. <para>-or-</para>
 1298        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1299        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1300        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1301        /// <remarks>
 1302        /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
 1303        /// </remarks>
 1304        public void AppendAllText(string path, string contents)
 31305        {
 31306            using (var stream = AppendText(path))
 21307            {
 21308                stream.Write(contents);
 21309            }
 21310        }
 1311
 1312        /// <summary>
 1313        /// Appends the specified string to the file, creating the file if it does not already exist.
 1314        /// </summary>
 1315        /// <param name="path">The file to append the specified string to.</param>
 1316        /// <param name="contents">The string to append to the file.</param>
 1317        /// <param name="encoding">The character encoding to use.</param>
 1318        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>. <para>-or-</para>
 1319        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1320        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1321        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1322        public void AppendAllText(string path, string contents, Encoding encoding)
 31323        {
 31324            using (var stream = AppendText(path, encoding))
 21325            {
 21326                stream.Write(contents);
 21327            }
 21328        }
 1329
 1330        /// <summary>
 1331        /// Creates a <see cref="StreamWriter"/> that appends UTF-8 encoded text to the specified file,
 1332        /// creating the file if it does not already exist.
 1333        /// </summary>
 1334        /// <param name="path">The path to the file to append to.</param>
 1335        /// <returns>
 1336        /// A <see cref="StreamWriter"/> that appends text to a file using UTF-8 encoding without a
 1337        /// Byte-Order Mark (BOM).
 1338        /// </returns>
 1339        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1340        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1341        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1342        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1343        public StreamWriter AppendText(string path)
 121344        {
 121345            return AppendText(path, Utf8NoBOM);
 91346        }
 1347
 1348        /// <summary>
 1349        /// Creates a <see cref="StreamWriter"/> that appends text to a file using the specified
 1350        /// encoding, creating the file if it does not already exist.
 1351        /// </summary>
 1352        /// <param name="path">The path to the file to append to.</param>
 1353        /// <param name="encoding">The character encoding to use.</param>
 1354        /// <returns>
 1355        /// A <see cref="StreamWriter"/> that appends text to a file using the specified encoding.
 1356        /// </returns>
 1357        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>. <para>-or-</para>
 1358        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1359        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1360        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1361        public StreamWriter AppendText(string path, Encoding encoding)
 241362        {
 241363            CheckDisposed();
 1364
 241365            if (encoding is null)
 01366            {
 01367                throw new ArgumentNullException(nameof(encoding));
 1368            }
 1369
 241370            return new StreamWriter(new SftpFileStream(_sftpSession, path, FileMode.Append, FileAccess.Write, (int) _buf
 181371        }
 1372
 1373        /// <summary>
 1374        /// Creates or overwrites a file in the specified path.
 1375        /// </summary>
 1376        /// <param name="path">The path and name of the file to create.</param>
 1377        /// <returns>
 1378        /// A <see cref="SftpFileStream"/> that provides read/write access to the file specified in path.
 1379        /// </returns>
 1380        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1381        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1382        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1383        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1384        /// <remarks>
 1385        /// If the target file already exists, it is first truncated to zero bytes.
 1386        /// </remarks>
 1387        public SftpFileStream Create(string path)
 51388        {
 51389            CheckDisposed();
 1390
 51391            return new SftpFileStream(_sftpSession, path, FileMode.Create, FileAccess.ReadWrite, (int) _bufferSize);
 41392        }
 1393
 1394        /// <summary>
 1395        /// Creates or overwrites the specified file.
 1396        /// </summary>
 1397        /// <param name="path">The path and name of the file to create.</param>
 1398        /// <param name="bufferSize">The maximum number of bytes buffered for reads and writes to the file.</param>
 1399        /// <returns>
 1400        /// A <see cref="SftpFileStream"/> that provides read/write access to the file specified in path.
 1401        /// </returns>
 1402        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1403        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1404        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1405        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1406        /// <remarks>
 1407        /// If the target file already exists, it is first truncated to zero bytes.
 1408        /// </remarks>
 1409        public SftpFileStream Create(string path, int bufferSize)
 01410        {
 01411            CheckDisposed();
 1412
 01413            return new SftpFileStream(_sftpSession, path, FileMode.Create, FileAccess.ReadWrite, bufferSize);
 01414        }
 1415
 1416        /// <summary>
 1417        /// Creates or opens a file for writing UTF-8 encoded text.
 1418        /// </summary>
 1419        /// <param name="path">The file to be opened for writing.</param>
 1420        /// <returns>
 1421        /// A <see cref="StreamWriter"/> that writes text to a file using UTF-8 encoding without
 1422        /// a Byte-Order Mark (BOM).
 1423        /// </returns>
 1424        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1425        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1426        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1427        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1428        /// <remarks>
 1429        /// <para>
 1430        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
 1431        /// </para>
 1432        /// <para>
 1433        /// If the target file does not exist, it is created.
 1434        /// </para>
 1435        /// </remarks>
 1436        public StreamWriter CreateText(string path)
 211437        {
 211438            return CreateText(path, Utf8NoBOM);
 191439        }
 1440
 1441        /// <summary>
 1442        /// Creates or opens a file for writing text using the specified encoding.
 1443        /// </summary>
 1444        /// <param name="path">The file to be opened for writing.</param>
 1445        /// <param name="encoding">The character encoding to use.</param>
 1446        /// <returns>
 1447        /// A <see cref="StreamWriter"/> that writes to a file using the specified encoding.
 1448        /// </returns>
 1449        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1450        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1451        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1452        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1453        /// <remarks>
 1454        /// <para>
 1455        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
 1456        /// </para>
 1457        /// <para>
 1458        /// If the target file does not exist, it is created.
 1459        /// </para>
 1460        /// </remarks>
 1461        public StreamWriter CreateText(string path, Encoding encoding)
 541462        {
 541463            CheckDisposed();
 1464
 541465            return new StreamWriter(OpenWrite(path), encoding);
 461466        }
 1467
 1468        /// <summary>
 1469        /// Deletes the specified file or directory.
 1470        /// </summary>
 1471        /// <param name="path">The name of the file or directory to be deleted. Wildcard characters are not supported.</
 1472        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1473        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1474        /// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</excep
 1475        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1476        public void Delete(string path)
 101477        {
 101478            var file = Get(path);
 101479            file.Delete();
 101480        }
 1481
 1482        /// <summary>
 1483        /// Returns the date and time the specified file or directory was last accessed.
 1484        /// </summary>
 1485        /// <param name="path">The file or directory for which to obtain access date and time information.</param>
 1486        /// <returns>
 1487        /// A <see cref="DateTime"/> structure set to the date and time that the specified file or directory was last ac
 1488        /// This value is expressed in local time.
 1489        /// </returns>
 1490        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1491        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1492        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1493        public DateTime GetLastAccessTime(string path)
 41494        {
 41495            var file = Get(path);
 41496            return file.LastAccessTime;
 41497        }
 1498
 1499        /// <summary>
 1500        /// Returns the date and time, in coordinated universal time (UTC), that the specified file or directory was las
 1501        /// </summary>
 1502        /// <param name="path">The file or directory for which to obtain access date and time information.</param>
 1503        /// <returns>
 1504        /// A <see cref="DateTime"/> structure set to the date and time that the specified file or directory was last ac
 1505        /// This value is expressed in UTC time.
 1506        /// </returns>
 1507        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1508        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1509        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1510        public DateTime GetLastAccessTimeUtc(string path)
 21511        {
 21512            var lastAccessTime = GetLastAccessTime(path);
 21513            return lastAccessTime.ToUniversalTime();
 21514        }
 1515
 1516        /// <summary>
 1517        /// Returns the date and time the specified file or directory was last written to.
 1518        /// </summary>
 1519        /// <param name="path">The file or directory for which to obtain write date and time information.</param>
 1520        /// <returns>
 1521        /// A <see cref="DateTime"/> structure set to the date and time that the specified file or directory was last wr
 1522        /// This value is expressed in local time.
 1523        /// </returns>
 1524        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1525        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1526        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1527        public DateTime GetLastWriteTime(string path)
 41528        {
 41529            var file = Get(path);
 41530            return file.LastWriteTime;
 41531        }
 1532
 1533        /// <summary>
 1534        /// Returns the date and time, in coordinated universal time (UTC), that the specified file or directory was las
 1535        /// </summary>
 1536        /// <param name="path">The file or directory for which to obtain write date and time information.</param>
 1537        /// <returns>
 1538        /// A <see cref="DateTime"/> structure set to the date and time that the specified file or directory was last wr
 1539        /// This value is expressed in UTC time.
 1540        /// </returns>
 1541        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1542        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1543        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1544        public DateTime GetLastWriteTimeUtc(string path)
 21545        {
 21546            var lastWriteTime = GetLastWriteTime(path);
 21547            return lastWriteTime.ToUniversalTime();
 21548        }
 1549
 1550        /// <summary>
 1551        /// Opens a <see cref="SftpFileStream"/> on the specified path with read/write access.
 1552        /// </summary>
 1553        /// <param name="path">The file to open.</param>
 1554        /// <param name="mode">A <see cref="FileMode"/> value that specifies whether a file is created if one does not e
 1555        /// <returns>
 1556        /// An unshared <see cref="SftpFileStream"/> that provides access to the specified file, with the specified mode
 1557        /// </returns>
 1558        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1559        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1560        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1561        public SftpFileStream Open(string path, FileMode mode)
 31562        {
 31563            return Open(path, mode, FileAccess.ReadWrite);
 31564        }
 1565
 1566        /// <summary>
 1567        /// Opens a <see cref="SftpFileStream"/> on the specified path, with the specified mode and access.
 1568        /// </summary>
 1569        /// <param name="path">The file to open.</param>
 1570        /// <param name="mode">A <see cref="FileMode"/> value that specifies whether a file is created if one does not e
 1571        /// <param name="access">A <see cref="FileAccess"/> value that specifies the operations that can be performed on
 1572        /// <returns>
 1573        /// An unshared <see cref="SftpFileStream"/> that provides access to the specified file, with the specified mode
 1574        /// </returns>
 1575        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1576        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1577        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1578        public SftpFileStream Open(string path, FileMode mode, FileAccess access)
 1541579        {
 1541580            CheckDisposed();
 1581
 1541582            return new SftpFileStream(_sftpSession, path, mode, access, (int) _bufferSize);
 1441583        }
 1584
 1585        /// <summary>
 1586        /// Asynchronously opens a <see cref="SftpFileStream"/> on the specified path, with the specified mode and acces
 1587        /// </summary>
 1588        /// <param name="path">The file to open.</param>
 1589        /// <param name="mode">A <see cref="FileMode"/> value that specifies whether a file is created if one does not e
 1590        /// <param name="access">A <see cref="FileAccess"/> value that specifies the operations that can be performed on
 1591        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
 1592        /// <returns>
 1593        /// A <see cref="Task{SftpFileStream}"/> that represents the asynchronous open operation.
 1594        /// The task result contains the <see cref="SftpFileStream"/> that provides access to the specified file, with t
 1595        /// </returns>
 1596        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1597        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1598        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1599        public Task<SftpFileStream> OpenAsync(string path, FileMode mode, FileAccess access, CancellationToken cancellat
 11600        {
 11601            CheckDisposed();
 1602
 11603            if (path is null)
 01604            {
 01605                throw new ArgumentNullException(nameof(path));
 1606            }
 1607
 11608            if (_sftpSession is null)
 01609            {
 01610                throw new SshConnectionException("Client not connected.");
 1611            }
 1612
 11613            cancellationToken.ThrowIfCancellationRequested();
 1614
 11615            return SftpFileStream.OpenAsync(_sftpSession, path, mode, access, (int) _bufferSize, cancellationToken);
 11616        }
 1617
 1618        /// <summary>
 1619        /// Opens an existing file for reading.
 1620        /// </summary>
 1621        /// <param name="path">The file to be opened for reading.</param>
 1622        /// <returns>
 1623        /// A read-only <see cref="SftpFileStream"/> on the specified path.
 1624        /// </returns>
 1625        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1626        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1627        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1628        public SftpFileStream OpenRead(string path)
 1161629        {
 1161630            return Open(path, FileMode.Open, FileAccess.Read);
 1091631        }
 1632
 1633        /// <summary>
 1634        /// Opens an existing UTF-8 encoded text file for reading.
 1635        /// </summary>
 1636        /// <param name="path">The file to be opened for reading.</param>
 1637        /// <returns>
 1638        /// A <see cref="StreamReader"/> on the specified path.
 1639        /// </returns>
 1640        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1641        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1642        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1643        public StreamReader OpenText(string path)
 01644        {
 01645            return new StreamReader(OpenRead(path), Encoding.UTF8);
 01646        }
 1647
 1648        /// <summary>
 1649        /// Opens a file for writing.
 1650        /// </summary>
 1651        /// <param name="path">The file to be opened for writing.</param>
 1652        /// <returns>
 1653        /// An unshared <see cref="SftpFileStream"/> object on the specified path with <see cref="FileAccess.Write"/> ac
 1654        /// </returns>
 1655        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1656        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1657        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1658        /// <remarks>
 1659        /// If the file does not exist, it is created.
 1660        /// </remarks>
 1661        public SftpFileStream OpenWrite(string path)
 1051662        {
 1051663            CheckDisposed();
 1664
 1051665            return new SftpFileStream(_sftpSession, path, FileMode.OpenOrCreate, FileAccess.Write, (int) _bufferSize);
 961666        }
 1667
 1668        /// <summary>
 1669        /// Opens a binary file, reads the contents of the file into a byte array, and closes the file.
 1670        /// </summary>
 1671        /// <param name="path">The file to open for reading.</param>
 1672        /// <returns>
 1673        /// A byte array containing the contents of the file.
 1674        /// </returns>
 1675        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1676        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1677        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1678        public byte[] ReadAllBytes(string path)
 111679        {
 111680            using (var stream = OpenRead(path))
 101681            {
 101682                var buffer = new byte[stream.Length];
 101683                _ = stream.Read(buffer, 0, buffer.Length);
 101684                return buffer;
 1685            }
 101686        }
 1687
 1688        /// <summary>
 1689        /// Opens a text file, reads all lines of the file using UTF-8 encoding, and closes the file.
 1690        /// </summary>
 1691        /// <param name="path">The file to open for reading.</param>
 1692        /// <returns>
 1693        /// A string array containing all lines of the file.
 1694        /// </returns>
 1695        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1696        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1697        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1698        public string[] ReadAllLines(string path)
 41699        {
 41700            return ReadAllLines(path, Encoding.UTF8);
 21701        }
 1702
 1703        /// <summary>
 1704        /// Opens a file, reads all lines of the file with the specified encoding, and closes the file.
 1705        /// </summary>
 1706        /// <param name="path">The file to open for reading.</param>
 1707        /// <param name="encoding">The encoding applied to the contents of the file.</param>
 1708        /// <returns>
 1709        /// A string array containing all lines of the file.
 1710        /// </returns>
 1711        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1712        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1713        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1714        public string[] ReadAllLines(string path, Encoding encoding)
 81715        {
 1716            /*
 1717             * We use the default buffer size for StreamReader - which is 1024 bytes - and the configured buffer size
 1718             * for the SftpFileStream. We may want to revisit this later.
 1719             */
 1720
 81721            var lines = new List<string>();
 1722
 81723            using (var stream = new StreamReader(OpenRead(path), encoding))
 41724            {
 201725                while (!stream.EndOfStream)
 161726                {
 161727                    lines.Add(stream.ReadLine());
 161728                }
 41729            }
 1730
 41731            return lines.ToArray();
 41732        }
 1733
 1734        /// <summary>
 1735        /// Opens a text file, reads all lines of the file with the UTF-8 encoding, and closes the file.
 1736        /// </summary>
 1737        /// <param name="path">The file to open for reading.</param>
 1738        /// <returns>
 1739        /// A string containing all lines of the file.
 1740        /// </returns>
 1741        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1742        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1743        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1744        public string ReadAllText(string path)
 91745        {
 91746            return ReadAllText(path, Encoding.UTF8);
 81747        }
 1748
 1749        /// <summary>
 1750        /// Opens a file, reads all lines of the file with the specified encoding, and closes the file.
 1751        /// </summary>
 1752        /// <param name="path">The file to open for reading.</param>
 1753        /// <param name="encoding">The encoding applied to the contents of the file.</param>
 1754        /// <returns>
 1755        /// A string containing all lines of the file.
 1756        /// </returns>
 1757        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1758        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1759        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1760        public string ReadAllText(string path, Encoding encoding)
 191761        {
 1762            /*
 1763             * We use the default buffer size for StreamReader - which is 1024 bytes - and the configured buffer size
 1764             * for the SftpFileStream. We may want to revisit this later.
 1765             */
 1766
 191767            using (var stream = new StreamReader(OpenRead(path), encoding))
 171768            {
 171769                return stream.ReadToEnd();
 1770            }
 171771        }
 1772
 1773        /// <summary>
 1774        /// Reads the lines of a file with the UTF-8 encoding.
 1775        /// </summary>
 1776        /// <param name="path">The file to read.</param>
 1777        /// <returns>
 1778        /// The lines of the file.
 1779        /// </returns>
 1780        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1781        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1782        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1783        public IEnumerable<string> ReadLines(string path)
 21784        {
 21785            return ReadAllLines(path);
 11786        }
 1787
 1788        /// <summary>
 1789        /// Read the lines of a file that has a specified encoding.
 1790        /// </summary>
 1791        /// <param name="path">The file to read.</param>
 1792        /// <param name="encoding">The encoding that is applied to the contents of the file.</param>
 1793        /// <returns>
 1794        /// The lines of the file.
 1795        /// </returns>
 1796        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1797        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1798        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1799        public IEnumerable<string> ReadLines(string path, Encoding encoding)
 21800        {
 21801            return ReadAllLines(path, encoding);
 11802        }
 1803
 1804        /// <summary>
 1805        /// Sets the date and time the specified file was last accessed.
 1806        /// </summary>
 1807        /// <param name="path">The file for which to set the access date and time information.</param>
 1808        /// <param name="lastAccessTime">A <see cref="DateTime"/> containing the value to set for the last access date a
 1809        public void SetLastAccessTime(string path, DateTime lastAccessTime)
 11810        {
 11811            var attributes = GetAttributes(path);
 11812            attributes.LastAccessTime = lastAccessTime;
 11813            SetAttributes(path, attributes);
 11814        }
 1815
 1816        /// <summary>
 1817        /// Sets the date and time, in coordinated universal time (UTC), that the specified file was last accessed.
 1818        /// </summary>
 1819        /// <param name="path">The file for which to set the access date and time information.</param>
 1820        /// <param name="lastAccessTimeUtc">A <see cref="DateTime"/> containing the value to set for the last access dat
 1821        public void SetLastAccessTimeUtc(string path, DateTime lastAccessTimeUtc)
 11822        {
 11823            var attributes = GetAttributes(path);
 11824            attributes.LastAccessTimeUtc = lastAccessTimeUtc;
 11825            SetAttributes(path, attributes);
 11826        }
 1827
 1828        /// <summary>
 1829        /// Sets the date and time that the specified file was last written to.
 1830        /// </summary>
 1831        /// <param name="path">The file for which to set the date and time information.</param>
 1832        /// <param name="lastWriteTime">A <see cref="DateTime"/> containing the value to set for the last write date and
 1833        public void SetLastWriteTime(string path, DateTime lastWriteTime)
 11834        {
 11835            var attributes = GetAttributes(path);
 11836            attributes.LastWriteTime = lastWriteTime;
 11837            SetAttributes(path, attributes);
 11838        }
 1839
 1840        /// <summary>
 1841        /// Sets the date and time, in coordinated universal time (UTC), that the specified file was last written to.
 1842        /// </summary>
 1843        /// <param name="path">The file for which to set the date and time information.</param>
 1844        /// <param name="lastWriteTimeUtc">A <see cref="DateTime"/> containing the value to set for the last write date 
 1845        public void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc)
 11846        {
 11847            var attributes = GetAttributes(path);
 11848            attributes.LastWriteTimeUtc = lastWriteTimeUtc;
 11849            SetAttributes(path, attributes);
 11850        }
 1851
 1852        /// <summary>
 1853        /// Writes the specified byte array to the specified file, and closes the file.
 1854        /// </summary>
 1855        /// <param name="path">The file to write to.</param>
 1856        /// <param name="bytes">The bytes to write to the file.</param>
 1857        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1858        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1859        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1860        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1861        /// <remarks>
 1862        /// <para>
 1863        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
 1864        /// </para>
 1865        /// <para>
 1866        /// If the target file does not exist, it is created.
 1867        /// </para>
 1868        /// </remarks>
 1869        public void WriteAllBytes(string path, byte[] bytes)
 81870        {
 81871            using (var stream = OpenWrite(path))
 71872            {
 71873                stream.Write(bytes, 0, bytes.Length);
 71874            }
 71875        }
 1876
 1877        /// <summary>
 1878        /// Writes a collection of strings to the file using the UTF-8 encoding, and closes the file.
 1879        /// </summary>
 1880        /// <param name="path">The file to write to.</param>
 1881        /// <param name="contents">The lines to write to the file.</param>
 1882        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1883        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1884        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1885        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1886        /// <remarks>
 1887        /// <para>
 1888        /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
 1889        /// </para>
 1890        /// <para>
 1891        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
 1892        /// </para>
 1893        /// <para>
 1894        /// If the target file does not exist, it is created.
 1895        /// </para>
 1896        /// </remarks>
 1897        public void WriteAllLines(string path, IEnumerable<string> contents)
 41898        {
 41899            WriteAllLines(path, contents, Utf8NoBOM);
 31900        }
 1901
 1902        /// <summary>
 1903        /// Write the specified string array to the file using the UTF-8 encoding, and closes the file.
 1904        /// </summary>
 1905        /// <param name="path">The file to write to.</param>
 1906        /// <param name="contents">The string array to write to the file.</param>
 1907        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1908        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1909        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1910        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1911        /// <remarks>
 1912        /// <para>
 1913        /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
 1914        /// </para>
 1915        /// <para>
 1916        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
 1917        /// </para>
 1918        /// <para>
 1919        /// If the target file does not exist, it is created.
 1920        /// </para>
 1921        /// </remarks>
 1922        public void WriteAllLines(string path, string[] contents)
 41923        {
 41924            WriteAllLines(path, contents, Utf8NoBOM);
 31925        }
 1926
 1927        /// <summary>
 1928        /// Writes a collection of strings to the file using the specified encoding, and closes the file.
 1929        /// </summary>
 1930        /// <param name="path">The file to write to.</param>
 1931        /// <param name="contents">The lines to write to the file.</param>
 1932        /// <param name="encoding">The character encoding to use.</param>
 1933        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1934        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1935        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1936        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1937        /// <remarks>
 1938        /// <para>
 1939        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
 1940        /// </para>
 1941        /// <para>
 1942        /// If the target file does not exist, it is created.
 1943        /// </para>
 1944        /// </remarks>
 1945        public void WriteAllLines(string path, IEnumerable<string> contents, Encoding encoding)
 81946        {
 81947            using (var stream = CreateText(path, encoding))
 61948            {
 621949                foreach (var line in contents)
 221950                {
 221951                    stream.WriteLine(line);
 221952                }
 61953            }
 61954        }
 1955
 1956        /// <summary>
 1957        /// Writes the specified string array to the file by using the specified encoding, and closes the file.
 1958        /// </summary>
 1959        /// <param name="path">The file to write to.</param>
 1960        /// <param name="contents">The string array to write to the file.</param>
 1961        /// <param name="encoding">An <see cref="Encoding"/> object that represents the character encoding applied to th
 1962        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1963        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1964        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1965        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1966        /// <remarks>
 1967        /// <para>
 1968        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
 1969        /// </para>
 1970        /// <para>
 1971        /// If the target file does not exist, it is created.
 1972        /// </para>
 1973        /// </remarks>
 1974        public void WriteAllLines(string path, string[] contents, Encoding encoding)
 81975        {
 81976            using (var stream = CreateText(path, encoding))
 61977            {
 621978                foreach (var line in contents)
 221979                {
 221980                    stream.WriteLine(line);
 221981                }
 61982            }
 61983        }
 1984
 1985        /// <summary>
 1986        /// Writes the specified string to the file using the UTF-8 encoding, and closes the file.
 1987        /// </summary>
 1988        /// <param name="path">The file to write to.</param>
 1989        /// <param name="contents">The string to write to the file.</param>
 1990        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 1991        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 1992        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 1993        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 1994        /// <remarks>
 1995        /// <para>
 1996        /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM).
 1997        /// </para>
 1998        /// <para>
 1999        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
 2000        /// </para>
 2001        /// <para>
 2002        /// If the target file does not exist, it is created.
 2003        /// </para>
 2004        /// </remarks>
 2005        public void WriteAllText(string path, string contents)
 152006        {
 152007            using (var stream = CreateText(path))
 142008            {
 142009                stream.Write(contents);
 142010            }
 142011        }
 2012
 2013        /// <summary>
 2014        /// Writes the specified string to the file using the specified encoding, and closes the file.
 2015        /// </summary>
 2016        /// <param name="path">The file to write to.</param>
 2017        /// <param name="contents">The string to write to the file.</param>
 2018        /// <param name="encoding">The encoding to apply to the string.</param>
 2019        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 2020        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 2021        /// <exception cref="SftpPathNotFoundException">The specified path is invalid, or its directory was not found on
 2022        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 2023        /// <remarks>
 2024        /// <para>
 2025        /// If the target file already exists, it is overwritten. It is not first truncated to zero bytes.
 2026        /// </para>
 2027        /// <para>
 2028        /// If the target file does not exist, it is created.
 2029        /// </para>
 2030        /// </remarks>
 2031        public void WriteAllText(string path, string contents, Encoding encoding)
 122032        {
 122033            using (var stream = CreateText(path, encoding))
 112034            {
 112035                stream.Write(contents);
 112036            }
 112037        }
 2038
 2039        /// <summary>
 2040        /// Gets the <see cref="SftpFileAttributes"/> of the file on the path.
 2041        /// </summary>
 2042        /// <param name="path">The path to the file.</param>
 2043        /// <returns>
 2044        /// The <see cref="SftpFileAttributes"/> of the file on the path.
 2045        /// </returns>
 2046        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 2047        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 2048        /// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</excep
 2049        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 2050        public SftpFileAttributes GetAttributes(string path)
 152051        {
 152052            CheckDisposed();
 2053
 152054            if (_sftpSession is null)
 02055            {
 02056                throw new SshConnectionException("Client not connected.");
 2057            }
 2058
 152059            var fullPath = _sftpSession.GetCanonicalPath(path);
 2060
 152061            return _sftpSession.RequestLStat(fullPath);
 152062        }
 2063
 2064        /// <summary>
 2065        /// Sets the specified <see cref="SftpFileAttributes"/> of the file on the specified path.
 2066        /// </summary>
 2067        /// <param name="path">The path to the file.</param>
 2068        /// <param name="fileAttributes">The desired <see cref="SftpFileAttributes"/>.</param>
 2069        /// <exception cref="ArgumentNullException"><paramref name="path"/> is <see langword="null"/>.</exception>
 2070        /// <exception cref="SshConnectionException">Client is not connected.</exception>
 2071        /// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
 2072        public void SetAttributes(string path, SftpFileAttributes fileAttributes)
 42073        {
 42074            CheckDisposed();
 2075
 42076            if (_sftpSession is null)
 02077            {
 02078                throw new SshConnectionException("Client not connected.");
 2079            }
 2080
 42081            var fullPath = _sftpSession.GetCanonicalPath(path);
 2082
 42083            _sftpSession.RequestSetStat(fullPath, fileAttributes);
 42084        }
 2085
 2086        #endregion // File Methods
 2087
 2088        #region SynchronizeDirectories
 2089
 2090        /// <summary>
 2091        /// Synchronizes the directories.
 2092        /// </summary>
 2093        /// <param name="sourcePath">The source path.</param>
 2094        /// <param name="destinationPath">The destination path.</param>
 2095        /// <param name="searchPattern">The search pattern.</param>
 2096        /// <returns>
 2097        /// A list of uploaded files.
 2098        /// </returns>
 2099        /// <exception cref="ArgumentNullException"><paramref name="sourcePath"/> is <see langword="null"/>.</exception>
 2100        /// <exception cref="ArgumentException"><paramref name="destinationPath"/> is <see langword="null"/> or contains
 2101        /// <exception cref="SftpPathNotFoundException"><paramref name="destinationPath"/> was not found on the remote h
 2102        /// <exception cref="SshException">If a problem occurs while copying the file.</exception>
 2103        public IEnumerable<FileInfo> SynchronizeDirectories(string sourcePath, string destinationPath, string searchPatt
 12104        {
 12105            if (sourcePath is null)
 02106            {
 02107                throw new ArgumentNullException(nameof(sourcePath));
 2108            }
 2109
 12110            if (string.IsNullOrWhiteSpace(destinationPath))
 02111            {
 02112                throw new ArgumentException("destinationPath");
 2113            }
 2114
 12115            return InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asynchResult: null);
 12116        }
 2117
 2118        /// <summary>
 2119        /// Begins the synchronize directories.
 2120        /// </summary>
 2121        /// <param name="sourcePath">The source path.</param>
 2122        /// <param name="destinationPath">The destination path.</param>
 2123        /// <param name="searchPattern">The search pattern.</param>
 2124        /// <param name="asyncCallback">The async callback.</param>
 2125        /// <param name="state">The state.</param>
 2126        /// <returns>
 2127        /// An <see cref="IAsyncResult" /> that represents the asynchronous directory synchronization.
 2128        /// </returns>
 2129        /// <exception cref="ArgumentNullException"><paramref name="sourcePath"/> is <see langword="null"/>.</exception>
 2130        /// <exception cref="ArgumentException"><paramref name="destinationPath"/> is <see langword="null"/> or contains
 2131        /// <exception cref="SshException">If a problem occurs while copying the file.</exception>
 2132        public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern,
 12133        {
 12134            if (sourcePath is null)
 02135            {
 02136                throw new ArgumentNullException(nameof(sourcePath));
 2137            }
 2138
 12139            if (string.IsNullOrWhiteSpace(destinationPath))
 02140            {
 02141                throw new ArgumentException("destDir");
 2142            }
 2143
 12144            var asyncResult = new SftpSynchronizeDirectoriesAsyncResult(asyncCallback, state);
 2145
 12146            ThreadAbstraction.ExecuteThread(() =>
 12147                {
 12148                    try
 12149                    {
 12150                        var result = InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asyncRes
 12151
 12152                        asyncResult.SetAsCompleted(result, completedSynchronously: false);
 12153                    }
 02154                    catch (Exception exp)
 02155                    {
 02156                        asyncResult.SetAsCompleted(exp, completedSynchronously: false);
 02157                    }
 22158                });
 2159
 12160            return asyncResult;
 12161        }
 2162
 2163        /// <summary>
 2164        /// Ends the synchronize directories.
 2165        /// </summary>
 2166        /// <param name="asyncResult">The async result.</param>
 2167        /// <returns>
 2168        /// A list of uploaded files.
 2169        /// </returns>
 2170        /// <exception cref="ArgumentException">The <see cref="IAsyncResult"/> object did not come from the correspondin
 2171        /// <exception cref="SftpPathNotFoundException">The destination path was not found on the remote host.</exceptio
 2172        public IEnumerable<FileInfo> EndSynchronizeDirectories(IAsyncResult asyncResult)
 12173        {
 12174            if (asyncResult is not SftpSynchronizeDirectoriesAsyncResult ar || ar.EndInvokeCalled)
 02175            {
 02176                throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async me
 2177            }
 2178
 2179            // Wait for operation to complete, then return result or throw exception
 12180            return ar.EndInvoke();
 12181        }
 2182
 2183        private List<FileInfo> InternalSynchronizeDirectories(string sourcePath, string destinationPath, string searchPa
 22184        {
 22185            if (!Directory.Exists(sourcePath))
 02186            {
 02187                throw new FileNotFoundException(string.Format("Source directory not found: {0}", sourcePath));
 2188            }
 2189
 22190            var uploadedFiles = new List<FileInfo>();
 2191
 22192            var sourceDirectory = new DirectoryInfo(sourcePath);
 2193
 22194            using (var sourceFiles = sourceDirectory.EnumerateFiles(searchPattern).GetEnumerator())
 22195            {
 22196                if (!sourceFiles.MoveNext())
 02197                {
 02198                    return uploadedFiles;
 2199                }
 2200
 2201                #region Existing Files at The Destination
 2202
 22203                var destFiles = InternalListDirectory(destinationPath, listCallback: null);
 22204                var destDict = new Dictionary<string, ISftpFile>();
 222205                foreach (var destFile in destFiles)
 82206                {
 82207                    if (destFile.IsDirectory)
 62208                    {
 62209                        continue;
 2210                    }
 2211
 22212                    destDict.Add(destFile.Name, destFile);
 22213                }
 2214
 2215                #endregion
 2216
 2217                #region Upload the difference
 2218
 2219                const Flags uploadFlag = Flags.Write | Flags.Truncate | Flags.CreateNewOrOpen;
 2220                do
 22221                {
 22222                    var localFile = sourceFiles.Current;
 22223                    if (localFile is null)
 02224                    {
 02225                        continue;
 2226                    }
 2227
 22228                    var isDifferent = true;
 22229                    if (destDict.TryGetValue(localFile.Name, out var remoteFile))
 02230                    {
 2231                        // File exists at the destination, use filesize to detect if there's a difference
 02232                        isDifferent = localFile.Length != remoteFile.Length;
 02233                    }
 2234
 22235                    if (isDifferent)
 22236                    {
 22237                        var remoteFileName = string.Format(CultureInfo.InvariantCulture, @"{0}/{1}", destinationPath, lo
 2238                        try
 22239                        {
 2240#pragma warning disable CA2000 // Dispose objects before losing scope; false positive
 22241                            using (var file = File.OpenRead(localFile.FullName))
 2242#pragma warning restore CA2000 // Dispose objects before losing scope; false positive
 22243                            {
 22244                                InternalUploadFile(file, remoteFileName, uploadFlag, asyncResult: null, uploadCallback: 
 22245                            }
 2246
 22247                            uploadedFiles.Add(localFile);
 2248
 22249                            asynchResult?.Update(uploadedFiles.Count);
 22250                        }
 02251                        catch (Exception ex)
 02252                        {
 02253                            throw new SshException($"Failed to upload {localFile.FullName} to {remoteFileName}", ex);
 2254                        }
 22255                    }
 22256                }
 22257                while (sourceFiles.MoveNext());
 22258            }
 2259
 2260            #endregion
 2261
 22262            return uploadedFiles;
 22263        }
 2264
 2265        #endregion
 2266
 2267        /// <summary>
 2268        /// Internals the list directory.
 2269        /// </summary>
 2270        /// <param name="path">The path.</param>
 2271        /// <param name="listCallback">The list callback.</param>
 2272        /// <returns>
 2273        /// A list of files in the specfied directory.
 2274        /// </returns>
 2275        /// <exception cref="ArgumentNullException"><paramref name="path" /> is <see langword="null"/>.</exception>
 2276        /// <exception cref="SshConnectionException">Client not connected.</exception>
 2277        private List<ISftpFile> InternalListDirectory(string path, Action<int> listCallback)
 232278        {
 232279            if (path is null)
 12280            {
 12281                throw new ArgumentNullException(nameof(path));
 2282            }
 2283
 222284            if (_sftpSession is null)
 32285            {
 32286                throw new SshConnectionException("Client not connected.");
 2287            }
 2288
 192289            var fullPath = _sftpSession.GetCanonicalPath(path);
 2290
 162291            var handle = _sftpSession.RequestOpenDir(fullPath);
 2292
 122293            var basePath = fullPath;
 2294
 2295#if NET || NETSTANDARD2_1_OR_GREATER
 122296            if (!basePath.EndsWith('/'))
 2297#else
 02298            if (!basePath.EndsWith("/", StringComparison.Ordinal))
 2299#endif // NET || NETSTANDARD2_1_OR_GREATER
 102300            {
 102301                basePath = string.Format("{0}/", fullPath);
 102302            }
 2303
 122304            var result = new List<ISftpFile>();
 2305
 122306            var files = _sftpSession.RequestReadDir(handle);
 2307
 1242308            while (files is not null)
 1122309            {
 206942310                foreach (var f in files)
 101792311                {
 101792312                    result.Add(new SftpFile(_sftpSession,
 101792313                                            string.Format(CultureInfo.InvariantCulture, "{0}{1}", basePath, f.Key),
 101792314                                            f.Value));
 101792315                }
 2316
 2317                // Call callback to report number of files read
 1122318                if (listCallback is not null)
 32319                {
 2320                    // Execute callback on different thread
 62321                    ThreadAbstraction.ExecuteThread(() => listCallback(result.Count));
 32322                }
 2323
 1122324                files = _sftpSession.RequestReadDir(handle);
 1122325            }
 2326
 122327            _sftpSession.RequestClose(handle);
 2328
 122329            return result;
 122330        }
 2331
 2332        /// <summary>
 2333        /// Internals the download file.
 2334        /// </summary>
 2335        /// <param name="path">The path.</param>
 2336        /// <param name="output">The output.</param>
 2337        /// <param name="asyncResult">An <see cref="IAsyncResult"/> that references the asynchronous request.</param>
 2338        /// <param name="downloadCallback">The download callback.</param>
 2339        /// <exception cref="ArgumentNullException"><paramref name="output" /> is <see langword="null"/>.</exception>
 2340        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains whitespac
 2341        /// <exception cref="SshConnectionException">Client not connected.</exception>
 2342        private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncResult asyncResult, Action<ulong>
 512343        {
 512344            if (output is null)
 02345            {
 02346                throw new ArgumentNullException(nameof(output));
 2347            }
 2348
 512349            if (string.IsNullOrWhiteSpace(path))
 02350            {
 02351                throw new ArgumentException("path");
 2352            }
 2353
 512354            if (_sftpSession is null)
 12355            {
 12356                throw new SshConnectionException("Client not connected.");
 2357            }
 2358
 502359            var fullPath = _sftpSession.GetCanonicalPath(path);
 2360
 502361            using (var fileReader = ServiceFactory.CreateSftpFileReader(fullPath, _sftpSession, _bufferSize))
 462362            {
 462363                var totalBytesRead = 0UL;
 2364
 36932365                while (true)
 36932366                {
 2367                    // Cancel download
 36932368                    if (asyncResult is not null && asyncResult.IsDownloadCanceled)
 02369                    {
 02370                        break;
 2371                    }
 2372
 36932373                    var data = fileReader.Read();
 36932374                    if (data.Length == 0)
 462375                    {
 462376                        break;
 2377                    }
 2378
 36472379                    output.Write(data, 0, data.Length);
 2380
 36472381                    totalBytesRead += (ulong) data.Length;
 2382
 36472383                    if (downloadCallback is not null)
 16432384                    {
 2385                        // Copy offset to ensure it's not modified between now and execution of callback
 16432386                        var downloadOffset = totalBytesRead;
 2387
 2388                        // Execute callback on different thread
 65722389                        ThreadAbstraction.ExecuteThread(() => { downloadCallback(downloadOffset); });
 16432390                    }
 36472391                }
 462392            }
 462393        }
 2394
 2395        /// <summary>
 2396        /// Internals the upload file.
 2397        /// </summary>
 2398        /// <param name="input">The input.</param>
 2399        /// <param name="path">The path.</param>
 2400        /// <param name="flags">The flags.</param>
 2401        /// <param name="asyncResult">An <see cref="IAsyncResult"/> that references the asynchronous request.</param>
 2402        /// <param name="uploadCallback">The upload callback.</param>
 2403        /// <exception cref="ArgumentNullException"><paramref name="input" /> is <see langword="null"/>.</exception>
 2404        /// <exception cref="ArgumentException"><paramref name="path" /> is <see langword="null"/> or contains whitespac
 2405        /// <exception cref="SshConnectionException">Client not connected.</exception>
 2406        private void InternalUploadFile(Stream input, string path, Flags flags, SftpUploadAsyncResult asyncResult, Actio
 582407        {
 582408            if (input is null)
 02409            {
 02410                throw new ArgumentNullException(nameof(input));
 2411            }
 2412
 582413            if (string.IsNullOrWhiteSpace(path))
 02414            {
 02415                throw new ArgumentException("path");
 2416            }
 2417
 582418            if (_sftpSession is null)
 12419            {
 12420                throw new SshConnectionException("Client not connected.");
 2421            }
 2422
 572423            var fullPath = _sftpSession.GetCanonicalPath(path);
 2424
 572425            var handle = _sftpSession.RequestOpen(fullPath, flags);
 2426
 522427            ulong offset = 0;
 2428
 2429            // create buffer of optimal length
 522430            var buffer = new byte[_sftpSession.CalculateOptimalWriteLength(_bufferSize, handle)];
 2431
 522432            var bytesRead = input.Read(buffer, 0, buffer.Length);
 522433            var expectedResponses = 0;
 522434            var responseReceivedWaitHandle = new AutoResetEvent(initialState: false);
 2435
 2436            do
 38232437            {
 2438                // Cancel upload
 38232439                if (asyncResult is not null && asyncResult.IsUploadCanceled)
 02440                {
 02441                    break;
 2442                }
 2443
 38232444                if (bytesRead > 0)
 37412445                {
 37412446                    var writtenBytes = offset + (ulong) bytesRead;
 2447
 37412448                    _sftpSession.RequestWrite(handle, offset, buffer, offset: 0, bytesRead, wait: null, s =>
 37412449                        {
 37412450                            if (s.StatusCode == StatusCodes.Ok)
 37412451                            {
 37412452                                _ = Interlocked.Decrement(ref expectedResponses);
 37412453                                _ = responseReceivedWaitHandle.Set();
 37412454
 37412455                                // Call callback to report number of bytes written
 37412456                                if (uploadCallback is not null)
 16492457                                {
 37412458                                    // Execute callback on different thread
 32982459                                    ThreadAbstraction.ExecuteThread(() => uploadCallback(writtenBytes));
 16492460                                }
 37412461                            }
 74822462                        });
 2463
 37412464                    _ = Interlocked.Increment(ref expectedResponses);
 2465
 37412466                    offset += (ulong) bytesRead;
 2467
 37412468                    bytesRead = input.Read(buffer, 0, buffer.Length);
 37412469                }
 822470                else if (expectedResponses > 0)
 752471                {
 2472                    // Wait for expectedResponses to change
 752473                    _sftpSession.WaitOnHandle(responseReceivedWaitHandle, _operationTimeout);
 752474                }
 38232475            }
 38232476            while (expectedResponses > 0 || bytesRead > 0);
 2477
 522478            _sftpSession.RequestClose(handle);
 522479            responseReceivedWaitHandle.Dispose();
 522480        }
 2481
 2482        /// <summary>
 2483        /// Called when client is connected to the server.
 2484        /// </summary>
 2485        protected override void OnConnected()
 7232486        {
 7232487            base.OnConnected();
 2488
 7232489            _sftpSession = CreateAndConnectToSftpSession();
 7072490        }
 2491
 2492        /// <summary>
 2493        /// Called when client is disconnecting from the server.
 2494        /// </summary>
 2495        protected override void OnDisconnecting()
 7872496        {
 7872497            base.OnDisconnecting();
 2498
 2499            // disconnect, dispose and dereference the SFTP session since we create a new SFTP session
 2500            // on each connect
 7872501            var sftpSession = _sftpSession;
 7872502            if (sftpSession is not null)
 6982503            {
 6982504                _sftpSession = null;
 6982505                sftpSession.Dispose();
 6982506            }
 7872507        }
 2508
 2509        /// <summary>
 2510        /// Releases unmanaged and - optionally - managed resources.
 2511        /// </summary>
 2512        /// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langwor
 2513        protected override void Dispose(bool disposing)
 5212514        {
 5212515            base.Dispose(disposing);
 2516
 5212517            if (disposing)
 4672518            {
 4672519                var sftpSession = _sftpSession;
 4672520                if (sftpSession is not null)
 02521                {
 02522                    _sftpSession = null;
 02523                    sftpSession.Dispose();
 02524                }
 4672525            }
 5212526        }
 2527
 2528        private ISftpSession CreateAndConnectToSftpSession()
 7232529        {
 7232530            var sftpSession = ServiceFactory.CreateSftpSession(Session,
 7232531                                                               _operationTimeout,
 7232532                                                               ConnectionInfo.Encoding,
 7232533                                                               ServiceFactory.CreateSftpResponseFactory());
 2534            try
 7232535            {
 7232536                sftpSession.Connect();
 7072537                return sftpSession;
 2538            }
 162539            catch
 162540            {
 162541                sftpSession.Dispose();
 162542                throw;
 2543            }
 7072544        }
 2545    }
 2546}

Methods/Properties

.cctor()
get_OperationTimeout()
set_OperationTimeout(System.TimeSpan)
get_BufferSize()
set_BufferSize(System.UInt32)
get_WorkingDirectory()
get_ProtocolVersion()
get_SftpSession()
.ctor(Renci.SshNet.ConnectionInfo)
.ctor(System.String,System.Int32,System.String,System.String)
.ctor(System.String,System.String,System.String)
.ctor(System.String,System.Int32,System.String,Renci.SshNet.IPrivateKeySource[])
.ctor(System.String,System.String,Renci.SshNet.IPrivateKeySource[])
.ctor(Renci.SshNet.ConnectionInfo,System.Boolean)
.ctor(Renci.SshNet.ConnectionInfo,System.Boolean,Renci.SshNet.IServiceFactory)
ChangeDirectory(System.String)
ChangePermissions(System.String,System.Int16)
CreateDirectory(System.String)
DeleteDirectory(System.String)
DeleteFile(System.String)
DeleteFileAsync()
RenameFile(System.String,System.String)
RenameFile(System.String,System.String,System.Boolean)
RenameFileAsync()
SymbolicLink(System.String,System.String)
ListDirectory(System.String,System.Action`1<System.Int32>)
ListDirectoryAsync()
BeginListDirectory(System.String,System.AsyncCallback,System.Object,System.Action`1<System.Int32>)
EndListDirectory(System.IAsyncResult)
Get(System.String)
Exists(System.String)
DownloadFile(System.String,System.IO.Stream,System.Action`1<System.UInt64>)
BeginDownloadFile(System.String,System.IO.Stream)
BeginDownloadFile(System.String,System.IO.Stream,System.AsyncCallback)
BeginDownloadFile(System.String,System.IO.Stream,System.AsyncCallback,System.Object,System.Action`1<System.UInt64>)
EndDownloadFile(System.IAsyncResult)
UploadFile(System.IO.Stream,System.String,System.Action`1<System.UInt64>)
UploadFile(System.IO.Stream,System.String,System.Boolean,System.Action`1<System.UInt64>)
BeginUploadFile(System.IO.Stream,System.String)
BeginUploadFile(System.IO.Stream,System.String,System.AsyncCallback)
BeginUploadFile(System.IO.Stream,System.String,System.AsyncCallback,System.Object,System.Action`1<System.UInt64>)
BeginUploadFile(System.IO.Stream,System.String,System.Boolean,System.AsyncCallback,System.Object,System.Action`1<System.UInt64>)
EndUploadFile(System.IAsyncResult)
GetStatus(System.String)
GetStatusAsync()
AppendAllLines(System.String,System.Collections.Generic.IEnumerable`1<System.String>)
AppendAllLines(System.String,System.Collections.Generic.IEnumerable`1<System.String>,System.Text.Encoding)
AppendAllText(System.String,System.String)
AppendAllText(System.String,System.String,System.Text.Encoding)
AppendText(System.String)
AppendText(System.String,System.Text.Encoding)
Create(System.String)
Create(System.String,System.Int32)
CreateText(System.String)
CreateText(System.String,System.Text.Encoding)
Delete(System.String)
GetLastAccessTime(System.String)
GetLastAccessTimeUtc(System.String)
GetLastWriteTime(System.String)
GetLastWriteTimeUtc(System.String)
Open(System.String,System.IO.FileMode)
Open(System.String,System.IO.FileMode,System.IO.FileAccess)
OpenAsync(System.String,System.IO.FileMode,System.IO.FileAccess,System.Threading.CancellationToken)
OpenRead(System.String)
OpenText(System.String)
OpenWrite(System.String)
ReadAllBytes(System.String)
ReadAllLines(System.String)
ReadAllLines(System.String,System.Text.Encoding)
ReadAllText(System.String)
ReadAllText(System.String,System.Text.Encoding)
ReadLines(System.String)
ReadLines(System.String,System.Text.Encoding)
SetLastAccessTime(System.String,System.DateTime)
SetLastAccessTimeUtc(System.String,System.DateTime)
SetLastWriteTime(System.String,System.DateTime)
SetLastWriteTimeUtc(System.String,System.DateTime)
WriteAllBytes(System.String,System.Byte[])
WriteAllLines(System.String,System.Collections.Generic.IEnumerable`1<System.String>)
WriteAllLines(System.String,System.String[])
WriteAllLines(System.String,System.Collections.Generic.IEnumerable`1<System.String>,System.Text.Encoding)
WriteAllLines(System.String,System.String[],System.Text.Encoding)
WriteAllText(System.String,System.String)
WriteAllText(System.String,System.String,System.Text.Encoding)
GetAttributes(System.String)
SetAttributes(System.String,Renci.SshNet.Sftp.SftpFileAttributes)
SynchronizeDirectories(System.String,System.String,System.String)
BeginSynchronizeDirectories(System.String,System.String,System.String,System.AsyncCallback,System.Object)
EndSynchronizeDirectories(System.IAsyncResult)
InternalSynchronizeDirectories(System.String,System.String,System.String,Renci.SshNet.Sftp.SftpSynchronizeDirectoriesAsyncResult)
InternalListDirectory(System.String,System.Action`1<System.Int32>)
InternalDownloadFile(System.String,System.IO.Stream,Renci.SshNet.Sftp.SftpDownloadAsyncResult,System.Action`1<System.UInt64>)
InternalUploadFile(System.IO.Stream,System.String,Renci.SshNet.Sftp.Flags,Renci.SshNet.Sftp.SftpUploadAsyncResult,System.Action`1<System.UInt64>)
OnConnected()
OnDisconnecting()
Dispose(System.Boolean)
CreateAndConnectToSftpSession()