浏览代码

Internal cleanup in SftpSession (#1717)

Delete some Begin/End methods, use <inheritdoc/>
Rob Hague 2 天之前
父节点
当前提交
cb1f26d21d

+ 7 - 144
src/Renci.SshNet/Sftp/ISftpSession.cs

@@ -87,32 +87,10 @@ namespace Renci.SshNet.Sftp
         /// Performs SSH_FXP_STAT request.
         /// </summary>
         /// <param name="path">The path.</param>
-        /// <param name="nullOnError">If set to <see langword="true"/>, <see langword="null"/> is returned in case of an error.</param>
         /// <returns>
         /// File attributes.
         /// </returns>
-        SftpFileAttributes RequestStat(string path, bool nullOnError = false);
-
-        /// <summary>
-        /// Performs SSH_FXP_STAT request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginOpen(string, Flags, AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SftpOpenAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        SFtpStatAsyncResult BeginStat(string path, AsyncCallback callback, object state);
-
-        /// <summary>
-        /// Handles the end of an asynchronous read.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SFtpStatAsyncResult"/> that represents an asynchronous call.</param>
-        /// <returns>
-        /// The file attributes.
-        /// </returns>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        SftpFileAttributes EndStat(SFtpStatAsyncResult asyncResult);
+        SftpFileAttributes RequestStat(string path);
 
         /// <summary>
         /// Performs SSH_FXP_LSTAT request.
@@ -134,27 +112,6 @@ namespace Renci.SshNet.Sftp
         /// </returns>
         Task<SftpFileAttributes> RequestLStatAsync(string path, CancellationToken cancellationToken);
 
-        /// <summary>
-        /// Performs SSH_FXP_LSTAT request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginLStat(string, AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SFtpStatAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        SFtpStatAsyncResult BeginLStat(string path, AsyncCallback callback, object state);
-
-        /// <summary>
-        /// Handles the end of an asynchronous SSH_FXP_LSTAT request.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SFtpStatAsyncResult"/> that represents an asynchronous call.</param>
-        /// <returns>
-        /// The file attributes.
-        /// </returns>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        SftpFileAttributes EndLStat(SFtpStatAsyncResult asyncResult);
-
         /// <summary>
         /// Performs SSH_FXP_MKDIR request.
         /// </summary>
@@ -174,11 +131,10 @@ namespace Renci.SshNet.Sftp
         /// </summary>
         /// <param name="path">The path.</param>
         /// <param name="flags">The flags.</param>
-        /// <param name="nullOnError">If set to <see langword="true"/>, <see langword="null"/> is returned in case of an error.</param>
         /// <returns>
         /// The file handle for the specified path.
         /// </returns>
-        byte[] RequestOpen(string path, Flags flags, bool nullOnError = false);
+        byte[] RequestOpen(string path, Flags flags);
 
         /// <summary>
         /// Asynchronously performs a <c>SSH_FXP_OPEN</c> request.
@@ -192,41 +148,14 @@ namespace Renci.SshNet.Sftp
         /// </returns>
         Task<byte[]> RequestOpenAsync(string path, Flags flags, CancellationToken cancellationToken);
 
-        /// <summary>
-        /// Performs SSH_FXP_OPEN request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="flags">The flags.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginOpen(string, Flags, AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SftpOpenAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        SftpOpenAsyncResult BeginOpen(string path, Flags flags, AsyncCallback callback, object state);
-
-        /// <summary>
-        /// Handles the end of an asynchronous read.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SftpOpenAsyncResult"/> that represents an asynchronous call.</param>
-        /// <returns>
-        /// A <see cref="byte"/> array representing a file handle.
-        /// </returns>
-        /// <remarks>
-        /// If all available data has been read, the <see cref="EndOpen(SftpOpenAsyncResult)"/> method completes
-        /// immediately and returns zero bytes.
-        /// </remarks>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        byte[] EndOpen(SftpOpenAsyncResult asyncResult);
-
         /// <summary>
         /// Performs a <c>SSH_FXP_OPENDIR</c> request.
         /// </summary>
         /// <param name="path">The path.</param>
-        /// <param name="nullOnError">If set to <see langword="true"/>, <see langword="null"/> is returned in case of an error.</param>
         /// <returns>
         /// A file handle for the specified path.
         /// </returns>
-        byte[] RequestOpenDir(string path, bool nullOnError = false);
+        byte[] RequestOpenDir(string path);
 
         /// <summary>
         /// Asynchronously performs a <c>SSH_FXP_OPENDIR</c> request.
@@ -252,35 +181,10 @@ namespace Renci.SshNet.Sftp
         /// <param name="handle">The handle.</param>
         /// <param name="offset">The offset.</param>
         /// <param name="length">The length.</param>
-        /// <returns>data array; null if EOF.</returns>
-        byte[] RequestRead(byte[] handle, ulong offset, uint length);
-
-        /// <summary>
-        /// Begins an asynchronous read using a SSH_FXP_READ request.
-        /// </summary>
-        /// <param name="handle">The handle to the file to read from.</param>
-        /// <param name="offset">The offset in the file to start reading from.</param>
-        /// <param name="length">The number of bytes to read.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginRead(byte[], ulong, uint, AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
         /// <returns>
-        /// A <see cref="SftpReadAsyncResult"/> that represents the asynchronous call.
+        /// The data that was read, or an empty array when the end of the file was reached.
         /// </returns>
-        SftpReadAsyncResult BeginRead(byte[] handle, ulong offset, uint length, AsyncCallback callback, object state);
-
-        /// <summary>
-        /// Handles the end of an asynchronous read.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SftpReadAsyncResult"/> that represents an asynchronous call.</param>
-        /// <returns>
-        /// A <see cref="byte"/> array representing the data read.
-        /// </returns>
-        /// <remarks>
-        /// If all available data has been read, the <see cref="EndRead(SftpReadAsyncResult)"/> method completes
-        /// immediately and returns zero bytes.
-        /// </remarks>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        byte[] EndRead(SftpReadAsyncResult asyncResult);
+        byte[] RequestRead(byte[] handle, ulong offset, uint length);
 
         /// <summary>
         /// Asynchronously performs a <c>SSH_FXP_READ</c> request.
@@ -319,27 +223,6 @@ namespace Renci.SshNet.Sftp
         /// </returns>
         Task<KeyValuePair<string, SftpFileAttributes>[]> RequestReadDirAsync(byte[] handle, CancellationToken cancellationToken);
 
-        /// <summary>
-        /// Performs SSH_FXP_REALPATH request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginRealPath(string, AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SftpRealPathAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        SftpRealPathAsyncResult BeginRealPath(string path, AsyncCallback callback, object state);
-
-        /// <summary>
-        /// Handles the end of an asynchronous SSH_FXP_REALPATH request.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SftpRealPathAsyncResult"/> that represents an asynchronous call.</param>
-        /// <returns>
-        /// The absolute path.
-        /// </returns>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        string EndRealPath(SftpRealPathAsyncResult asyncResult);
-
         /// <summary>
         /// Performs a <c>SSH_FXP_REMOVE</c> request.
         /// </summary>
@@ -401,12 +284,10 @@ namespace Renci.SshNet.Sftp
         /// Performs a <c>statvfs@openssh.com</c> extended request.
         /// </summary>
         /// <param name="path">The path.</param>
-        /// <param name="nullOnError">If set to <see langword="true"/>, <see langword="null"/> is returned in case of an error.</param>
         /// <returns>
-        /// The file system information for the specified path, or <see langword="null"/> when
-        /// the request failed and <paramref name="nullOnError"/> is <see langword="true"/>.
+        /// The file system information for the specified path.
         /// </returns>
-        SftpFileSystemInformation RequestStatVfs(string path, bool nullOnError = false);
+        SftpFileSystemInformation RequestStatVfs(string path);
 
         /// <summary>
         /// Asynchronously performs a <c>statvfs@openssh.com</c> extended request.
@@ -482,24 +363,6 @@ namespace Renci.SshNet.Sftp
         /// </returns>
         Task RequestCloseAsync(byte[] handle, CancellationToken cancellationToken);
 
-        /// <summary>
-        /// Performs SSH_FXP_CLOSE request.
-        /// </summary>
-        /// <param name="handle">The handle.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginClose(byte[], AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SftpCloseAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        SftpCloseAsyncResult BeginClose(byte[] handle, AsyncCallback callback, object state);
-
-        /// <summary>
-        /// Handles the end of an asynchronous close.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SftpCloseAsyncResult"/> that represents an asynchronous call.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        void EndClose(SftpCloseAsyncResult asyncResult);
-
         /// <summary>
         /// Calculates the optimal size of the buffer to read data from the channel.
         /// </summary>

+ 0 - 14
src/Renci.SshNet/Sftp/SftpCloseAsyncResult.cs

@@ -1,14 +0,0 @@
-using System;
-
-using Renci.SshNet.Common;
-
-namespace Renci.SshNet.Sftp
-{
-    internal sealed class SftpCloseAsyncResult : AsyncResult
-    {
-        public SftpCloseAsyncResult(AsyncCallback asyncCallback, object state)
-            : base(asyncCallback, state)
-        {
-        }
-    }
-}

+ 0 - 14
src/Renci.SshNet/Sftp/SftpOpenAsyncResult.cs

@@ -1,14 +0,0 @@
-using System;
-
-using Renci.SshNet.Common;
-
-namespace Renci.SshNet.Sftp
-{
-    internal sealed class SftpOpenAsyncResult : AsyncResult<byte[]>
-    {
-        public SftpOpenAsyncResult(AsyncCallback asyncCallback, object state)
-            : base(asyncCallback, state)
-        {
-        }
-    }
-}

+ 0 - 14
src/Renci.SshNet/Sftp/SftpRealPathAsyncResult.cs

@@ -1,14 +0,0 @@
-using System;
-
-using Renci.SshNet.Common;
-
-namespace Renci.SshNet.Sftp
-{
-    internal sealed class SftpRealPathAsyncResult : AsyncResult<string>
-    {
-        public SftpRealPathAsyncResult(AsyncCallback asyncCallback, object state)
-            : base(asyncCallback, state)
-        {
-        }
-    }
-}

+ 46 - 619
src/Renci.SshNet/Sftp/SftpSession.cs

@@ -28,20 +28,10 @@ namespace Renci.SshNet.Sftp
         private EventWaitHandle _sftpVersionConfirmed = new AutoResetEvent(initialState: false);
         private IDictionary<string, string> _supportedExtensions;
 
-        /// <summary>
-        /// Gets the remote working directory.
-        /// </summary>
-        /// <value>
-        /// The remote working directory.
-        /// </value>
+        /// <inheritdoc/>
         public string WorkingDirectory { get; private set; }
 
-        /// <summary>
-        /// Gets the SFTP protocol version.
-        /// </summary>
-        /// <value>
-        /// The SFTP protocol version.
-        /// </value>
+        /// <inheritdoc/>
         public uint ProtocolVersion { get; private set; }
 
         private long _requestId;
@@ -71,10 +61,7 @@ namespace Renci.SshNet.Sftp
             _sftpResponseFactory = sftpResponseFactory;
         }
 
-        /// <summary>
-        /// Changes the current working directory to the specified path.
-        /// </summary>
-        /// <param name="path">The new working directory.</param>
+        /// <inheritdoc/>
         public void ChangeDirectory(string path)
         {
             var fullPath = GetCanonicalPath(path);
@@ -84,12 +71,7 @@ namespace Renci.SshNet.Sftp
             WorkingDirectory = fullPath;
         }
 
-        /// <summary>
-        /// Asynchronously requests to change the current working directory to the specified path.
-        /// </summary>
-        /// <param name="path">The new working directory.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>A <see cref="Task"/> that tracks the asynchronous change working directory request.</returns>
+        /// <inheritdoc/>
         public async Task ChangeDirectoryAsync(string path, CancellationToken cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
@@ -108,13 +90,7 @@ namespace Renci.SshNet.Sftp
             SendData(data);
         }
 
-        /// <summary>
-        /// Resolves a given path into an absolute path on the server.
-        /// </summary>
-        /// <param name="path">The path to resolve.</param>
-        /// <returns>
-        /// The absolute path.
-        /// </returns>
+        /// <inheritdoc/>
         public string GetCanonicalPath(string path)
         {
             var fullPath = GetFullRemotePath(path);
@@ -180,14 +156,7 @@ namespace Renci.SshNet.Sftp
             return string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", canonizedPath, slash, pathParts[pathParts.Length - 1]);
         }
 
-        /// <summary>
-        /// Asynchronously resolves a given path into an absolute path on the server.
-        /// </summary>
-        /// <param name="path">The path to resolve.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task representing the absolute path.
-        /// </returns>
+        /// <inheritdoc/>
         public async Task<string> GetCanonicalPathAsync(string path, CancellationToken cancellationToken)
         {
             var fullPath = GetFullRemotePath(path);
@@ -405,14 +374,8 @@ namespace Renci.SshNet.Sftp
             SendMessage(request);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_OPEN request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="flags">The flags.</param>
-        /// <param name="nullOnError">If set to <see langword="true"/> returns <see langword="null"/> instead of throwing an exception.</param>
-        /// <returns>File handle.</returns>
-        public byte[] RequestOpen(string path, Flags flags, bool nullOnError = false)
+        /// <inheritdoc/>
+        public byte[] RequestOpen(string path, Flags flags)
         {
             byte[] handle = null;
             SftpException exception = null;
@@ -440,7 +403,7 @@ namespace Renci.SshNet.Sftp
                 WaitOnHandle(wait, OperationTimeout);
             }
 
-            if (!nullOnError && exception is not null)
+            if (exception is not null)
             {
                 throw exception;
             }
@@ -448,16 +411,7 @@ namespace Renci.SshNet.Sftp
             return handle;
         }
 
-        /// <summary>
-        /// Asynchronously performs a <c>SSH_FXP_OPEN</c> request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="flags">The flags.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task that represents the asynchronous <c>SSH_FXP_OPEN</c> request. The value of its
-        /// <see cref="Task{Task}.Result"/> contains the file handle of the specified path.
-        /// </returns>
+        /// <inheritdoc/>
         public Task<byte[]> RequestOpenAsync(string path, Flags flags, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -478,76 +432,7 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_OPEN request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="flags">The flags.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginOpen(string, Flags, AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SftpOpenAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        public SftpOpenAsyncResult BeginOpen(string path, Flags flags, AsyncCallback callback, object state)
-        {
-            var asyncResult = new SftpOpenAsyncResult(callback, state);
-
-            var request = new SftpOpenRequest(ProtocolVersion,
-                                              NextRequestId,
-                                              path,
-                                              _encoding,
-                                              flags,
-                                              response =>
-                                              {
-                                                  asyncResult.SetAsCompleted(response.Handle, completedSynchronously: false);
-                                              },
-                                              response =>
-                                              {
-                                                  asyncResult.SetAsCompleted(GetSftpException(response, path), completedSynchronously: false);
-                                              });
-
-            SendRequest(request);
-
-            return asyncResult;
-        }
-
-        /// <summary>
-        /// Handles the end of an asynchronous open.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SftpOpenAsyncResult"/> that represents an asynchronous call.</param>
-        /// <returns>
-        /// A <see cref="byte"/> array representing a file handle.
-        /// </returns>
-        /// <remarks>
-        /// If all available data has been read, the <see cref="EndOpen(SftpOpenAsyncResult)"/> method completes
-        /// immediately and returns zero bytes.
-        /// </remarks>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        public byte[] EndOpen(SftpOpenAsyncResult asyncResult)
-        {
-            ThrowHelper.ThrowIfNull(asyncResult);
-
-            if (asyncResult.EndInvokeCalled)
-            {
-                throw new InvalidOperationException("EndOpen has already been called.");
-            }
-
-            if (asyncResult.IsCompleted)
-            {
-                return asyncResult.EndInvoke();
-            }
-
-            using (var waitHandle = asyncResult.AsyncWaitHandle)
-            {
-                WaitOnHandle(waitHandle, OperationTimeout);
-                return asyncResult.EndInvoke();
-            }
-        }
-
-        /// <summary>
-        /// Performs SSH_FXP_CLOSE request.
-        /// </summary>
-        /// <param name="handle">The handle.</param>
+        /// <inheritdoc/>
         public void RequestClose(byte[] handle)
         {
             SftpException exception = null;
@@ -574,14 +459,7 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        /// <summary>
-        /// Performs a <c>SSH_FXP_CLOSE</c> request.
-        /// </summary>
-        /// <param name="handle">The handle.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task that represents the asynchronous <c>SSH_FXP_CLOSE</c> request.
-        /// </returns>
+        /// <inheritdoc/>
         public Task RequestCloseAsync(byte[] handle, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -609,141 +487,7 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_CLOSE request.
-        /// </summary>
-        /// <param name="handle">The handle.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginClose(byte[], AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SftpCloseAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        public SftpCloseAsyncResult BeginClose(byte[] handle, AsyncCallback callback, object state)
-        {
-            var asyncResult = new SftpCloseAsyncResult(callback, state);
-
-            var request = new SftpCloseRequest(ProtocolVersion,
-                                               NextRequestId,
-                                               handle,
-                                               response =>
-                                               {
-                                                   asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false);
-                                               });
-            SendRequest(request);
-
-            return asyncResult;
-        }
-
-        /// <summary>
-        /// Handles the end of an asynchronous close.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SftpCloseAsyncResult"/> that represents an asynchronous call.</param>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        public void EndClose(SftpCloseAsyncResult asyncResult)
-        {
-            ThrowHelper.ThrowIfNull(asyncResult);
-
-            if (asyncResult.EndInvokeCalled)
-            {
-                throw new InvalidOperationException("EndClose has already been called.");
-            }
-
-            if (asyncResult.IsCompleted)
-            {
-                asyncResult.EndInvoke();
-            }
-            else
-            {
-                using (var waitHandle = asyncResult.AsyncWaitHandle)
-                {
-                    WaitOnHandle(waitHandle, OperationTimeout);
-                    asyncResult.EndInvoke();
-                }
-            }
-        }
-
-        /// <summary>
-        /// Begins an asynchronous read using a SSH_FXP_READ request.
-        /// </summary>
-        /// <param name="handle">The handle to the file to read from.</param>
-        /// <param name="offset">The offset in the file to start reading from.</param>
-        /// <param name="length">The number of bytes to read.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginRead(byte[], ulong, uint, AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SftpReadAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        public SftpReadAsyncResult BeginRead(byte[] handle, ulong offset, uint length, AsyncCallback callback, object state)
-        {
-            var asyncResult = new SftpReadAsyncResult(callback, state);
-
-            var request = new SftpReadRequest(ProtocolVersion,
-                                              NextRequestId,
-                                              handle,
-                                              offset,
-                                              length,
-                                              response =>
-                                              {
-                                                  asyncResult.SetAsCompleted(response.Data, completedSynchronously: false);
-                                              },
-                                              response =>
-                                              {
-                                                  if (response.StatusCode != StatusCode.Eof)
-                                                  {
-                                                      asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false);
-                                                  }
-                                                  else
-                                                  {
-                                                      asyncResult.SetAsCompleted(Array.Empty<byte>(), completedSynchronously: false);
-                                                  }
-                                              });
-            SendRequest(request);
-
-            return asyncResult;
-        }
-
-        /// <summary>
-        /// Handles the end of an asynchronous read.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SftpReadAsyncResult"/> that represents an asynchronous call.</param>
-        /// <returns>
-        /// A <see cref="byte"/> array representing the data read.
-        /// </returns>
-        /// <remarks>
-        /// If all available data has been read, the <see cref="EndRead(SftpReadAsyncResult)"/> method completes
-        /// immediately and returns zero bytes.
-        /// </remarks>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        public byte[] EndRead(SftpReadAsyncResult asyncResult)
-        {
-            ThrowHelper.ThrowIfNull(asyncResult);
-
-            if (asyncResult.EndInvokeCalled)
-            {
-                throw new InvalidOperationException("EndRead has already been called.");
-            }
-
-            if (asyncResult.IsCompleted)
-            {
-                return asyncResult.EndInvoke();
-            }
-
-            using (var waitHandle = asyncResult.AsyncWaitHandle)
-            {
-                WaitOnHandle(waitHandle, OperationTimeout);
-                return asyncResult.EndInvoke();
-            }
-        }
-
-        /// <summary>
-        /// Performs SSH_FXP_READ request.
-        /// </summary>
-        /// <param name="handle">The handle.</param>
-        /// <param name="offset">The offset.</param>
-        /// <param name="length">The length.</param>
-        /// <returns>
-        /// The data that was read, or an empty array when the end of the file was reached.
-        /// </returns>
+        /// <inheritdoc/>
         public byte[] RequestRead(byte[] handle, ulong offset, uint length)
         {
             SftpException exception = null;
@@ -789,18 +533,7 @@ namespace Renci.SshNet.Sftp
             return data;
         }
 
-        /// <summary>
-        /// Asynchronously performs a <c>SSH_FXP_READ</c> request.
-        /// </summary>
-        /// <param name="handle">The handle to the file to read from.</param>
-        /// <param name="offset">The offset in the file to start reading from.</param>
-        /// <param name="length">The number of bytes to read.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task that represents the asynchronous <c>SSH_FXP_READ</c> request. The value of
-        /// its <see cref="Task{Task}.Result"/> contains the data read from the file, or an empty
-        /// array when the end of the file is reached.
-        /// </returns>
+        /// <inheritdoc/>
         public Task<byte[]> RequestReadAsync(byte[] handle, ulong offset, uint length, CancellationToken cancellationToken)
         {
             Debug.Assert(length > 0, "This implementation cannot distinguish between EOF and zero-length reads");
@@ -833,16 +566,7 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_WRITE request.
-        /// </summary>
-        /// <param name="handle">The handle.</param>
-        /// <param name="serverOffset">The the zero-based offset (in bytes) relative to the beginning of the file that the write must start at.</param>
-        /// <param name="data">The buffer holding the data to write.</param>
-        /// <param name="offset">the zero-based offset in <paramref name="data" /> at which to begin taking bytes to write.</param>
-        /// <param name="length">The length (in bytes) of the data to write.</param>
-        /// <param name="wait">The wait event handle if needed.</param>
-        /// <param name="writeCompleted">The callback to invoke when the write has completed.</param>
+        /// <inheritdoc/>
         public void RequestWrite(byte[] handle,
                                  ulong serverOffset,
                                  byte[] data,
@@ -888,18 +612,7 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        /// <summary>
-        /// Asynchronouly performs a <c>SSH_FXP_WRITE</c> request.
-        /// </summary>
-        /// <param name="handle">The handle.</param>
-        /// <param name="serverOffset">The the zero-based offset (in bytes) relative to the beginning of the file that the write must start at.</param>
-        /// <param name="data">The buffer holding the data to write.</param>
-        /// <param name="offset">the zero-based offset in <paramref name="data" /> at which to begin taking bytes to write.</param>
-        /// <param name="length">The length (in bytes) of the data to write.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task that represents the asynchronous <c>SSH_FXP_WRITE</c> request.
-        /// </returns>
+        /// <inheritdoc/>
         public Task RequestWriteAsync(byte[] handle, ulong serverOffset, byte[] data, int offset, int length, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -931,18 +644,13 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_LSTAT request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <returns>
-        /// File attributes.
-        /// </returns>
+        /// <inheritdoc/>
         public SftpFileAttributes RequestLStat(string path)
         {
             SftpException exception = null;
 
             SftpFileAttributes attributes = null;
+
             using (var wait = new AutoResetEvent(initialState: false))
             {
                 var request = new SftpLStatRequest(ProtocolVersion,
@@ -973,15 +681,7 @@ namespace Renci.SshNet.Sftp
             return attributes;
         }
 
-        /// <summary>
-        ///  Asynchronously performs SSH_FXP_LSTAT request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task the represents the asynchronous <c>SSH_FXP_LSTAT</c> request. The value of its
-        /// <see cref="Task{SftpFileAttributes}.Result"/> contains the file attributes of the specified path.
-        /// </returns>
+        /// <inheritdoc/>
         public Task<SftpFileAttributes> RequestLStatAsync(string path, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -1001,65 +701,6 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_LSTAT request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginLStat(string, AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SFtpStatAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        public SFtpStatAsyncResult BeginLStat(string path, AsyncCallback callback, object state)
-        {
-            var asyncResult = new SFtpStatAsyncResult(callback, state);
-
-            var request = new SftpLStatRequest(ProtocolVersion,
-                                               NextRequestId,
-                                               path,
-                                               _encoding,
-                                               response =>
-                                               {
-                                                   asyncResult.SetAsCompleted(response.Attributes, completedSynchronously: false);
-                                               },
-                                               response =>
-                                               {
-                                                   asyncResult.SetAsCompleted(GetSftpException(response, path), completedSynchronously: false);
-                                               });
-            SendRequest(request);
-
-            return asyncResult;
-        }
-
-        /// <summary>
-        /// Handles the end of an asynchronous SSH_FXP_LSTAT request.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SFtpStatAsyncResult"/> that represents an asynchronous call.</param>
-        /// <returns>
-        /// The file attributes.
-        /// </returns>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        public SftpFileAttributes EndLStat(SFtpStatAsyncResult asyncResult)
-        {
-            ThrowHelper.ThrowIfNull(asyncResult);
-
-            if (asyncResult.EndInvokeCalled)
-            {
-                throw new InvalidOperationException("EndLStat has already been called.");
-            }
-
-            if (asyncResult.IsCompleted)
-            {
-                return asyncResult.EndInvoke();
-            }
-
-            using (var waitHandle = asyncResult.AsyncWaitHandle)
-            {
-                WaitOnHandle(waitHandle, OperationTimeout);
-                return asyncResult.EndInvoke();
-            }
-        }
-
         /// <inheritdoc/>
         public SftpFileAttributes RequestFStat(byte[] handle)
         {
@@ -1095,15 +736,7 @@ namespace Renci.SshNet.Sftp
             return attributes;
         }
 
-        /// <summary>
-        /// Asynchronously performs a <c>SSH_FXP_FSTAT</c> request.
-        /// </summary>
-        /// <param name="handle">The handle.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task that represents the asynchronous <c>SSH_FXP_FSTAT</c> request. The value of its
-        /// <see cref="Task{Task}.Result"/> contains the file attributes of the specified handle.
-        /// </returns>
+        /// <inheritdoc/>
         public Task<SftpFileAttributes> RequestFStatAsync(byte[] handle, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -1122,11 +755,7 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_SETSTAT request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="attributes">The attributes.</param>
+        /// <inheritdoc/>
         public void RequestSetStat(string path, SftpFileAttributes attributes)
         {
             SftpException exception = null;
@@ -1155,11 +784,7 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_FSETSTAT request.
-        /// </summary>
-        /// <param name="handle">The handle.</param>
-        /// <param name="attributes">The attributes.</param>
+        /// <inheritdoc/>
         public void RequestFSetStat(byte[] handle, SftpFileAttributes attributes)
         {
             SftpException exception = null;
@@ -1187,13 +812,8 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_OPENDIR request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="nullOnError">If set to <see langword="true"/>, returns <see langword="null"/> instead of throwing an exception.</param>
-        /// <returns>File handle.</returns>
-        public byte[] RequestOpenDir(string path, bool nullOnError = false)
+        /// <inheritdoc/>
+        public byte[] RequestOpenDir(string path)
         {
             SftpException exception = null;
 
@@ -1221,7 +841,7 @@ namespace Renci.SshNet.Sftp
                 WaitOnHandle(wait, OperationTimeout);
             }
 
-            if (!nullOnError && exception is not null)
+            if (exception is not null)
             {
                 throw exception;
             }
@@ -1229,15 +849,7 @@ namespace Renci.SshNet.Sftp
             return handle;
         }
 
-        /// <summary>
-        /// Asynchronously performs a <c>SSH_FXP_OPENDIR</c> request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task that represents the asynchronous <c>SSH_FXP_OPENDIR</c> request. The value of its
-        /// <see cref="Task{Task}.Result"/> contains the handle of the specified path.
-        /// </returns>
+        /// <inheritdoc/>
         public Task<byte[]> RequestOpenDirAsync(string path, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -1257,14 +869,7 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_READDIR request.
-        /// </summary>
-        /// <param name="handle">The handle of the directory to read.</param>
-        /// <returns>
-        /// A <see cref="Dictionary{TKey,TValue}"/> where the <c>key</c> is the name of a file in
-        /// the directory and the <c>value</c> is the <see cref="SftpFileAttributes"/> of the file.
-        /// </returns>
+        /// <inheritdoc/>
         public KeyValuePair<string, SftpFileAttributes>[] RequestReadDir(byte[] handle)
         {
             SftpException exception = null;
@@ -1304,17 +909,7 @@ namespace Renci.SshNet.Sftp
             return result;
         }
 
-        /// <summary>
-        /// Performs a <c>SSH_FXP_READDIR</c> request.
-        /// </summary>
-        /// <param name="handle">The handle of the directory to read.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task that represents the asynchronous <c>SSH_FXP_READDIR</c> request. The value of its
-        /// <see cref="Task{Task}.Result"/> contains a <see cref="Dictionary{TKey,TValue}"/> where the
-        /// <c>key</c> is the name of a file in the directory and the <c>value</c> is the <see cref="SftpFileAttributes"/>
-        /// of the file.
-        /// </returns>
+        /// <inheritdoc/>
         public Task<KeyValuePair<string, SftpFileAttributes>[]> RequestReadDirAsync(byte[] handle, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -1343,10 +938,7 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_REMOVE request.
-        /// </summary>
-        /// <param name="path">The path.</param>
+        /// <inheritdoc/>
         public void RequestRemove(string path)
         {
             SftpException exception = null;
@@ -1374,14 +966,7 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        /// <summary>
-        /// Asynchronously performs a <c>SSH_FXP_REMOVE</c> request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task that represents the asynchronous <c>SSH_FXP_REMOVE</c> request.
-        /// </returns>
+        /// <inheritdoc/>
         public Task RequestRemoveAsync(string path, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -1410,10 +995,7 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_MKDIR request.
-        /// </summary>
-        /// <param name="path">The path.</param>
+        /// <inheritdoc/>
         public void RequestMkDir(string path)
         {
             SftpException exception = null;
@@ -1441,12 +1023,7 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        /// <summary>
-        /// Asynchronously performs SSH_FXP_MKDIR request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
-        /// <returns>A <see cref="Task"/> that represents the asynchronous <c>SSH_FXP_MKDIR</c> operation.</returns>
+        /// <inheritdoc/>
         public Task RequestMkDirAsync(string path, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -1475,10 +1052,7 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_RMDIR request.
-        /// </summary>
-        /// <param name="path">The path.</param>
+        /// <inheritdoc/>
         public void RequestRmDir(string path)
         {
             SftpException exception = null;
@@ -1609,68 +1183,8 @@ namespace Renci.SshNet.Sftp
             return WaitOnHandleAsync(tcs, OperationTimeout, cancellationToken);
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_REALPATH request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginRealPath(string, AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SftpRealPathAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        public SftpRealPathAsyncResult BeginRealPath(string path, AsyncCallback callback, object state)
-        {
-            var asyncResult = new SftpRealPathAsyncResult(callback, state);
-
-            var request = new SftpRealPathRequest(ProtocolVersion,
-                                                  NextRequestId,
-                                                  path,
-                                                  _encoding,
-                                                  response => asyncResult.SetAsCompleted(response.Files[0].Key, completedSynchronously: false),
-                                                  response => asyncResult.SetAsCompleted(GetSftpException(response, path), completedSynchronously: false));
-            SendRequest(request);
-
-            return asyncResult;
-        }
-
-        /// <summary>
-        /// Handles the end of an asynchronous SSH_FXP_REALPATH request.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SftpRealPathAsyncResult"/> that represents an asynchronous call.</param>
-        /// <returns>
-        /// The absolute path.
-        /// </returns>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        public string EndRealPath(SftpRealPathAsyncResult asyncResult)
-        {
-            ThrowHelper.ThrowIfNull(asyncResult);
-
-            if (asyncResult.EndInvokeCalled)
-            {
-                throw new InvalidOperationException("EndRealPath has already been called.");
-            }
-
-            if (asyncResult.IsCompleted)
-            {
-                return asyncResult.EndInvoke();
-            }
-
-            using (var waitHandle = asyncResult.AsyncWaitHandle)
-            {
-                WaitOnHandle(waitHandle, OperationTimeout);
-                return asyncResult.EndInvoke();
-            }
-        }
-
-        /// <summary>
-        /// Performs SSH_FXP_STAT request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="nullOnError">if set to <see langword="true"/> returns null instead of throwing an exception.</param>
-        /// <returns>
-        /// File attributes.
-        /// </returns>
-        public SftpFileAttributes RequestStat(string path, bool nullOnError = false)
+        /// <inheritdoc/>
+        public SftpFileAttributes RequestStat(string path)
         {
             SftpException exception = null;
 
@@ -1698,7 +1212,7 @@ namespace Renci.SshNet.Sftp
                 WaitOnHandle(wait, OperationTimeout);
             }
 
-            if (!nullOnError && exception is not null)
+            if (exception is not null)
             {
                 throw exception;
             }
@@ -1706,64 +1220,7 @@ namespace Renci.SshNet.Sftp
             return attributes;
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_STAT request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginStat(string, AsyncCallback, object)"/> completes.</param>
-        /// <param name="state">An object that contains any additional user-defined data.</param>
-        /// <returns>
-        /// A <see cref="SFtpStatAsyncResult"/> that represents the asynchronous call.
-        /// </returns>
-        public SFtpStatAsyncResult BeginStat(string path, AsyncCallback callback, object state)
-        {
-            var asyncResult = new SFtpStatAsyncResult(callback, state);
-
-            var request = new SftpStatRequest(ProtocolVersion,
-                                              NextRequestId,
-                                              path,
-                                              _encoding,
-                                              response => asyncResult.SetAsCompleted(response.Attributes, completedSynchronously: false),
-                                              response => asyncResult.SetAsCompleted(GetSftpException(response, path), completedSynchronously: false));
-            SendRequest(request);
-
-            return asyncResult;
-        }
-
-        /// <summary>
-        /// Handles the end of an asynchronous stat.
-        /// </summary>
-        /// <param name="asyncResult">An <see cref="SFtpStatAsyncResult"/> that represents an asynchronous call.</param>
-        /// <returns>
-        /// The file attributes.
-        /// </returns>
-        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <see langword="null"/>.</exception>
-        public SftpFileAttributes EndStat(SFtpStatAsyncResult asyncResult)
-        {
-            ThrowHelper.ThrowIfNull(asyncResult);
-
-            if (asyncResult.EndInvokeCalled)
-            {
-                throw new InvalidOperationException("EndStat has already been called.");
-            }
-
-            if (asyncResult.IsCompleted)
-            {
-                return asyncResult.EndInvoke();
-            }
-
-            using (var waitHandle = asyncResult.AsyncWaitHandle)
-            {
-                WaitOnHandle(waitHandle, OperationTimeout);
-                return asyncResult.EndInvoke();
-            }
-        }
-
-        /// <summary>
-        /// Performs SSH_FXP_RENAME request.
-        /// </summary>
-        /// <param name="oldPath">The old path.</param>
-        /// <param name="newPath">The new path.</param>
+        /// <inheritdoc/>
         public void RequestRename(string oldPath, string newPath)
         {
             if (ProtocolVersion < 2)
@@ -1797,15 +1254,7 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        /// <summary>
-        /// Asynchronously performs a <c>SSH_FXP_RENAME</c> request.
-        /// </summary>
-        /// <param name="oldPath">The old path.</param>
-        /// <param name="newPath">The new path.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task that represents the asynchronous <c>SSH_FXP_RENAME</c> request.
-        /// </returns>
+        /// <inheritdoc/>
         public Task RequestRenameAsync(string oldPath, string newPath, CancellationToken cancellationToken)
         {
             if (cancellationToken.IsCancellationRequested)
@@ -1885,11 +1334,7 @@ namespace Renci.SshNet.Sftp
             return result;
         }
 
-        /// <summary>
-        /// Performs SSH_FXP_SYMLINK request.
-        /// </summary>
-        /// <param name="linkpath">The linkpath.</param>
-        /// <param name="targetpath">The targetpath.</param>
+        /// <inheritdoc/>
         public void RequestSymLink(string linkpath, string targetpath)
         {
             if (ProtocolVersion < 3)
@@ -1923,11 +1368,7 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        /// <summary>
-        /// Performs posix-rename@openssh.com extended request.
-        /// </summary>
-        /// <param name="oldPath">The old path.</param>
-        /// <param name="newPath">The new path.</param>
+        /// <inheritdoc/>
         public void RequestPosixRename(string oldPath, string newPath)
         {
             if (ProtocolVersion < 3)
@@ -1966,15 +1407,8 @@ namespace Renci.SshNet.Sftp
             }
         }
 
-        /// <summary>
-        /// Performs statvfs@openssh.com extended request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="nullOnError">if set to <see langword="true"/> [null on error].</param>
-        /// <returns>
-        /// A <see cref="SftpFileSystemInformation"/> for the specified path.
-        /// </returns>
-        public SftpFileSystemInformation RequestStatVfs(string path, bool nullOnError = false)
+        /// <inheritdoc/>
+        public SftpFileSystemInformation RequestStatVfs(string path)
         {
             if (ProtocolVersion < 3)
             {
@@ -2012,24 +1446,17 @@ namespace Renci.SshNet.Sftp
                 WaitOnHandle(wait, OperationTimeout);
             }
 
-            if (!nullOnError && exception is not null)
+            if (exception is not null)
             {
                 throw exception;
             }
 
+            Debug.Assert(information is not null);
+
             return information;
         }
 
-        /// <summary>
-        /// Asynchronously performs a <c>statvfs@openssh.com</c> extended request.
-        /// </summary>
-        /// <param name="path">The path.</param>
-        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
-        /// <returns>
-        /// A task that represents the <c>statvfs@openssh.com</c> extended request. The value of its
-        /// <see cref="Task{Task}.Result"/> contains the file system information for the specified
-        /// path.
-        /// </returns>
+        /// <inheritdoc/>
         public Task<SftpFileSystemInformation> RequestStatVfsAsync(string path, CancellationToken cancellationToken)
         {
             if (ProtocolVersion < 3)

+ 8 - 4
test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesInSingleSshDataMessage.cs

@@ -1,5 +1,7 @@
 using System;
 using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
 
 using Microsoft.Extensions.Logging.Abstractions;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -184,11 +186,13 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
         protected void Act()
         {
-            var openAsyncResult = _sftpSession.BeginOpen(_path, Flags.Read, null, null);
-            var readAsyncResult = _sftpSession.BeginRead(_handle, _offset, _length, null, null);
+            Task<byte[]> openTask = _sftpSession.RequestOpenAsync(_path, Flags.Read, CancellationToken.None);
+            Task<byte[]> readTask = _sftpSession.RequestReadAsync(_handle, _offset, _length, CancellationToken.None);
 
-            _actualHandle = _sftpSession.EndOpen(openAsyncResult);
-            _actualData = _sftpSession.EndRead(readAsyncResult);
+            Task.WaitAll(openTask, readTask);
+
+            _actualHandle = openTask.Result;
+            _actualData = readTask.Result;
         }
 
         [TestMethod]

+ 2 - 5
test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesSplitOverMultipleSshDataMessages.cs

@@ -191,11 +191,8 @@ namespace Renci.SshNet.Tests.Classes.Sftp
 
         protected void Act()
         {
-            var openAsyncResult = _sftpSession.BeginOpen(_path, Flags.Read, null, null);
-            var readAsyncResult = _sftpSession.BeginRead(_handle, _offset, _length, null, null);
-
-            _actualHandle = _sftpSession.EndOpen(openAsyncResult);
-            _actualData = _sftpSession.EndRead(readAsyncResult);
+            _actualHandle = _sftpSession.RequestOpen(_path, Flags.Read);
+            _actualData = _sftpSession.RequestRead(_handle, _offset, _length);
         }
 
         [TestMethod]