diff --git a/Directory.Build.props b/Directory.Build.props
index 284b26d09..b263d4fa9 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -23,6 +23,13 @@
true
+
+
+ $(NoWarn);CS8602
+
+
diff --git a/src/Renci.SshNet/NetConfClient.cs b/src/Renci.SshNet/NetConfClient.cs
index 49be11766..e9ebace45 100644
--- a/src/Renci.SshNet/NetConfClient.cs
+++ b/src/Renci.SshNet/NetConfClient.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable enable
+using System;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Threading;
@@ -19,7 +20,7 @@ public class NetConfClient : BaseClient
///
/// Holds instance that used to communicate to the server.
///
- private INetConfSession _netConfSession;
+ private INetConfSession? _netConfSession;
///
/// Gets or sets the operation timeout.
@@ -47,7 +48,7 @@ public TimeSpan OperationTimeout
///
/// The current NetConf session.
///
- internal INetConfSession NetConfSession
+ internal INetConfSession? NetConfSession
{
get { return _netConfSession; }
}
@@ -160,9 +161,18 @@ internal NetConfClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, I
///
/// The NetConf server capabilities.
///
+ /// Client is not connected.
public XmlDocument ServerCapabilities
{
- get { return _netConfSession.ServerCapabilities; }
+ get
+ {
+ if (_netConfSession is null)
+ {
+ throw new SshConnectionException("Client not connected.");
+ }
+
+ return _netConfSession.ServerCapabilities;
+ }
}
///
@@ -171,9 +181,18 @@ public XmlDocument ServerCapabilities
///
/// The NetConf client capabilities.
///
+ /// Client is not connected.
public XmlDocument ClientCapabilities
{
- get { return _netConfSession.ClientCapabilities; }
+ get
+ {
+ if (_netConfSession is null)
+ {
+ throw new SshConnectionException("Client not connected.");
+ }
+
+ return _netConfSession.ClientCapabilities;
+ }
}
///
@@ -196,6 +215,11 @@ public XmlDocument ClientCapabilities
/// Client is not connected.
public XmlDocument SendReceiveRpc(XmlDocument rpc)
{
+ if (_netConfSession is null)
+ {
+ throw new SshConnectionException("Client not connected.");
+ }
+
return _netConfSession.SendReceiveRpc(rpc, AutomaticMessageIdHandling);
}
@@ -222,6 +246,11 @@ public XmlDocument SendReceiveRpc(string xml)
/// Client is not connected.
public XmlDocument SendCloseRpc()
{
+ if (_netConfSession is null)
+ {
+ throw new SshConnectionException("Client not connected.");
+ }
+
var rpc = new XmlDocument();
rpc.LoadXml("");
return _netConfSession.SendReceiveRpc(rpc, AutomaticMessageIdHandling);
@@ -244,7 +273,7 @@ protected override void OnDisconnecting()
{
base.OnDisconnecting();
- _netConfSession.Disconnect();
+ _netConfSession?.Disconnect();
}
///
diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs
index 8dd42a215..0355a0a55 100644
--- a/src/Renci.SshNet/ScpClient.cs
+++ b/src/Renci.SshNet/ScpClient.cs
@@ -1,5 +1,7 @@
-using System;
+#nullable enable
+using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
@@ -127,12 +129,12 @@ public IRemotePathTransformation RemotePathTransformation
///
/// Occurs when downloading file.
///
- public event EventHandler Downloading;
+ public event EventHandler? Downloading;
///
/// Occurs when uploading file.
///
- public event EventHandler Uploading;
+ public event EventHandler? Uploading;
///
/// Initializes a new instance of the class.
@@ -246,8 +248,14 @@ internal ScpClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServ
/// is a zero-length .
/// A directory with the specified path exists on the remote host.
/// The secure copy execution request was rejected by the server.
+ /// Client is not connected.
public void Upload(Stream source, string path)
{
+ if (Session is null)
+ {
+ throw new SshConnectionException("Client not connected.");
+ }
+
var posixPath = PosixPath.CreateAbsoluteOrRelativeFilePath(path);
using (var input = ServiceFactory.CreatePipeStream())
@@ -280,6 +288,7 @@ public void Upload(Stream source, string path)
/// is a zero-length .
/// A directory with the specified path exists on the remote host.
/// The secure copy execution request was rejected by the server.
+ /// Client is not connected.
public void Upload(FileInfo fileInfo, string path)
{
if (fileInfo is null)
@@ -287,6 +296,11 @@ public void Upload(FileInfo fileInfo, string path)
throw new ArgumentNullException(nameof(fileInfo));
}
+ if (Session is null)
+ {
+ throw new SshConnectionException("Client not connected.");
+ }
+
var posixPath = PosixPath.CreateAbsoluteOrRelativeFilePath(path);
using (var input = ServiceFactory.CreatePipeStream())
@@ -323,6 +337,7 @@ public void Upload(FileInfo fileInfo, string path)
/// is a zero-length string.
/// does not exist on the remote host, is not a directory or the user does not have the required permission.
/// The secure copy execution request was rejected by the server.
+ /// Client is not connected.
public void Upload(DirectoryInfo directoryInfo, string path)
{
if (directoryInfo is null)
@@ -340,6 +355,11 @@ public void Upload(DirectoryInfo directoryInfo, string path)
throw new ArgumentException("The path cannot be a zero-length string.", nameof(path));
}
+ if (Session is null)
+ {
+ throw new SshConnectionException("Client not connected.");
+ }
+
using (var input = ServiceFactory.CreatePipeStream())
using (var channel = Session.CreateChannelSession())
{
@@ -371,6 +391,7 @@ public void Upload(DirectoryInfo directoryInfo, string path)
/// is or empty.
/// exists on the remote host, and is not a regular file.
/// The secure copy execution request was rejected by the server.
+ /// Client is not connected.
public void Download(string filename, FileInfo fileInfo)
{
if (string.IsNullOrEmpty(filename))
@@ -383,6 +404,11 @@ public void Download(string filename, FileInfo fileInfo)
throw new ArgumentNullException(nameof(fileInfo));
}
+ if (Session is null)
+ {
+ throw new SshConnectionException("Client not connected.");
+ }
+
using (var input = ServiceFactory.CreatePipeStream())
using (var channel = Session.CreateChannelSession())
{
@@ -411,6 +437,7 @@ public void Download(string filename, FileInfo fileInfo)
/// is .
/// File or directory with the specified path does not exist on the remote host.
/// The secure copy execution request was rejected by the server.
+ /// Client is not connected.
public void Download(string directoryName, DirectoryInfo directoryInfo)
{
if (string.IsNullOrEmpty(directoryName))
@@ -423,6 +450,11 @@ public void Download(string directoryName, DirectoryInfo directoryInfo)
throw new ArgumentNullException(nameof(directoryInfo));
}
+ if (Session is null)
+ {
+ throw new SshConnectionException("Client not connected.");
+ }
+
using (var input = ServiceFactory.CreatePipeStream())
using (var channel = Session.CreateChannelSession())
{
@@ -451,6 +483,7 @@ public void Download(string directoryName, DirectoryInfo directoryInfo)
/// is .
/// exists on the remote host, and is not a regular file.
/// The secure copy execution request was rejected by the server.
+ /// Client is not connected.
public void Download(string filename, Stream destination)
{
if (string.IsNullOrWhiteSpace(filename))
@@ -463,6 +496,11 @@ public void Download(string filename, Stream destination)
throw new ArgumentNullException(nameof(destination));
}
+ if (Session is null)
+ {
+ throw new SshConnectionException("Client not connected.");
+ }
+
using (var input = ServiceFactory.CreatePipeStream())
using (var channel = Session.CreateChannelSession())
{
@@ -767,13 +805,17 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI
directoryCounter--;
- currentDirectoryFullName = new DirectoryInfo(currentDirectoryFullName).Parent.FullName;
-
if (directoryCounter == 0)
{
break;
}
+ var currentDirectoryParent = new DirectoryInfo(currentDirectoryFullName).Parent;
+
+ Debug.Assert(currentDirectoryParent is not null, $"Should be {directoryCounter.ToString(CultureInfo.InvariantCulture)} levels deeper than {startDirectoryFullName}.");
+
+ currentDirectoryFullName = currentDirectoryParent.FullName;
+
continue;
}
@@ -795,7 +837,7 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI
else
{
// Don't create directory for first level
- newDirectoryInfo = fileSystemInfo as DirectoryInfo;
+ newDirectoryInfo = (DirectoryInfo)fileSystemInfo;
}
directoryCounter++;
diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs
index e702e99f8..6517a4268 100644
--- a/src/Renci.SshNet/SshClient.cs
+++ b/src/Renci.SshNet/SshClient.cs
@@ -1,4 +1,5 @@
-using System;
+#nullable enable
+using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
@@ -27,7 +28,7 @@ public class SshClient : BaseClient
///
private bool _isDisposed;
- private MemoryStream _inputStream;
+ private MemoryStream? _inputStream;
///
/// Gets the list of forwarded ports.
@@ -272,7 +273,7 @@ public SshCommand RunCommand(string commandText)
/// Returns a representation of a object.
///
/// Client is not connected.
- public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes, int bufferSize)
+ public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary? terminalModes, int bufferSize)
{
EnsureSessionIsOpen();
@@ -333,7 +334,7 @@ public Shell CreateShell(Stream input, Stream output, Stream extendedOutput)
/// Returns a representation of a object.
///
/// Client is not connected.
- public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes, int bufferSize)
+ public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary? terminalModes, int bufferSize)
{
/*
* TODO Issue #1224: let shell dispose of input stream when we own the stream!
@@ -442,7 +443,7 @@ public ShellStream CreateShellStream(string terminalName, uint columns, uint row
/// to the drawable area of the window.
///
///
- public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, IDictionary terminalModeValues)
+ public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, IDictionary? terminalModeValues)
{
EnsureSessionIsOpen();