From 4cab7e5cf6108898e5b7d434953b51d54817168e Mon Sep 17 00:00:00 2001 From: mus65 Date: Wed, 17 Apr 2024 21:31:26 +0200 Subject: [PATCH] enable nullable on BaseClient and SftpClient (#1339) * enable nullable on BaseClient and SftpClient * SftpClient: use nameof for ArgumentException --- src/Renci.SshNet/BaseClient.cs | 25 ++++++----- src/Renci.SshNet/IBaseClient.cs | 3 +- src/Renci.SshNet/ISftpClient.cs | 25 +++++------ src/Renci.SshNet/SftpClient.cs | 73 ++++++++++++++++++--------------- 4 files changed, 67 insertions(+), 59 deletions(-) diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index 6c721beb..bf728abc 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; @@ -22,7 +23,7 @@ namespace Renci.SshNet private readonly IServiceFactory _serviceFactory; private readonly object _keepAliveLock = new object(); private TimeSpan _keepAliveInterval; - private Timer _keepAliveTimer; + private Timer? _keepAliveTimer; private ConnectionInfo _connectionInfo; private bool _isDisposed; @@ -32,7 +33,7 @@ namespace Renci.SshNet /// /// The current session. /// - internal ISession Session { get; private set; } + internal ISession? Session { get; private set; } /// /// Gets the factory for creating new services. @@ -142,17 +143,17 @@ namespace Renci.SshNet /// /// Occurs when an error occurred. /// - public event EventHandler ErrorOccurred; + public event EventHandler? ErrorOccurred; /// /// Occurs when host key received. /// - public event EventHandler HostKeyReceived; + public event EventHandler? HostKeyReceived; /// /// Occurs when server identification received. /// - public event EventHandler ServerIdentificationReceived; + public event EventHandler? ServerIdentificationReceived; /// /// Initializes a new instance of the class. @@ -193,7 +194,7 @@ namespace Renci.SshNet throw new ArgumentNullException(nameof(serviceFactory)); } - ConnectionInfo = connectionInfo; + _connectionInfo = connectionInfo; _ownsConnectionInfo = ownsConnectionInfo; _serviceFactory = serviceFactory; _keepAliveInterval = Timeout.InfiniteTimeSpan; @@ -391,17 +392,17 @@ namespace Renci.SshNet { } - private void Session_ErrorOccured(object sender, ExceptionEventArgs e) + private void Session_ErrorOccured(object? sender, ExceptionEventArgs e) { ErrorOccurred?.Invoke(this, e); } - private void Session_HostKeyReceived(object sender, HostKeyEventArgs e) + private void Session_HostKeyReceived(object? sender, HostKeyEventArgs e) { HostKeyReceived?.Invoke(this, e); } - private void Session_ServerIdentificationReceived(object sender, SshIdentificationEventArgs e) + private void Session_ServerIdentificationReceived(object? sender, SshIdentificationEventArgs e) { ServerIdentificationReceived?.Invoke(this, e); } @@ -432,14 +433,12 @@ namespace Renci.SshNet Disconnect(); - if (_ownsConnectionInfo && _connectionInfo is not null) + if (_ownsConnectionInfo) { if (_connectionInfo is IDisposable connectionInfoDisposable) { connectionInfoDisposable.Dispose(); } - - _connectionInfo = null; } _isDisposed = true; diff --git a/src/Renci.SshNet/IBaseClient.cs b/src/Renci.SshNet/IBaseClient.cs index c42df342..9feab44c 100644 --- a/src/Renci.SshNet/IBaseClient.cs +++ b/src/Renci.SshNet/IBaseClient.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index 48e9dce8..133488fd 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using System.IO; using System.Text; @@ -192,7 +193,7 @@ namespace Renci.SshNet /// /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. /// - IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback asyncCallback); + IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback? asyncCallback); /// /// Begins an asynchronous file downloading into the stream. @@ -211,7 +212,7 @@ namespace Renci.SshNet /// /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. /// - IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback asyncCallback, object state, Action downloadCallback = null); + IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback? asyncCallback, object? state, Action? downloadCallback = null); /// /// Begins an asynchronous operation of retrieving list of files in remote directory. @@ -224,7 +225,7 @@ namespace Renci.SshNet /// An that references the asynchronous operation. /// /// The method was called after the client was disposed. - IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback, object state, Action listCallback = null); + IAsyncResult BeginListDirectory(string path, AsyncCallback? asyncCallback, object? state, Action? listCallback = null); /// /// Begins the synchronize directories. @@ -240,7 +241,7 @@ namespace Renci.SshNet /// is . /// is or contains only whitespace. /// If a problem occurs while copying the file. - IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state); + IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback? asyncCallback, object? state); /// /// Begins an asynchronous uploading the stream into remote file. @@ -289,7 +290,7 @@ namespace Renci.SshNet /// If the remote file already exists, it is overwritten and truncated. /// /// - IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback asyncCallback); + IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback? asyncCallback); /// /// Begins an asynchronous uploading the stream into remote file. @@ -316,7 +317,7 @@ namespace Renci.SshNet /// If the remote file already exists, it is overwritten and truncated. /// /// - IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback asyncCallback, object state, Action uploadCallback = null); + IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback? asyncCallback, object? state, Action? uploadCallback = null); /// /// Begins an asynchronous uploading the stream into remote file. @@ -343,7 +344,7 @@ namespace Renci.SshNet /// . /// /// - IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, AsyncCallback asyncCallback, object state, Action uploadCallback = null); + IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, AsyncCallback? asyncCallback, object? state, Action? uploadCallback = null); /// /// Changes remote directory to path. @@ -522,7 +523,7 @@ namespace Renci.SshNet /// /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. /// - void DownloadFile(string path, Stream output, Action downloadCallback = null); + void DownloadFile(string path, Stream output, Action? downloadCallback = null); /// /// Ends an asynchronous file downloading into the stream. @@ -698,7 +699,7 @@ namespace Renci.SshNet /// Permission to list the contents of the directory was denied by the remote host. -or- A SSH command was denied by the server. /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - IEnumerable ListDirectory(string path, Action listCallback = null); + IEnumerable ListDirectory(string path, Action? listCallback = null); /// /// Asynchronously enumerates the files in remote directory. @@ -1004,7 +1005,7 @@ namespace Renci.SshNet /// /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. /// - void UploadFile(Stream input, string path, Action uploadCallback = null); + void UploadFile(Stream input, string path, Action? uploadCallback = null); /// /// Uploads stream into remote file. @@ -1022,7 +1023,7 @@ namespace Renci.SshNet /// /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. /// - void UploadFile(Stream input, string path, bool canOverride, Action uploadCallback = null); + void UploadFile(Stream input, string path, bool canOverride, Action? uploadCallback = null); /// /// Writes the specified byte array to the specified file, and closes the file. diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 16f15ada..4f458b67 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -26,7 +27,7 @@ namespace Renci.SshNet /// Holds the instance that is used to communicate to the /// SFTP server. /// - private ISftpSession _sftpSession; + private ISftpSession? _sftpSession; /// /// Holds the operation timeout. @@ -170,7 +171,7 @@ namespace Renci.SshNet /// /// The current SFTP session. /// - internal ISftpSession SftpSession + internal ISftpSession? SftpSession { get { return _sftpSession; } } @@ -369,7 +370,7 @@ namespace Renci.SshNet if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentException("path"); + throw new ArgumentException(nameof(path)); } if (_sftpSession is null) @@ -398,7 +399,7 @@ namespace Renci.SshNet if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentException("path"); + throw new ArgumentException(nameof(path)); } if (_sftpSession is null) @@ -429,7 +430,7 @@ namespace Renci.SshNet if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentException("path"); + throw new ArgumentException(nameof(path)); } if (_sftpSession is null) @@ -556,12 +557,12 @@ namespace Renci.SshNet if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentException("path"); + throw new ArgumentException(nameof(path)); } if (string.IsNullOrWhiteSpace(linkPath)) { - throw new ArgumentException("linkPath"); + throw new ArgumentException(nameof(linkPath)); } if (_sftpSession is null) @@ -589,7 +590,7 @@ namespace Renci.SshNet /// Permission to list the contents of the directory was denied by the remote host. -or- A SSH command was denied by the server. /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - public IEnumerable ListDirectory(string path, Action listCallback = null) + public IEnumerable ListDirectory(string path, Action? listCallback = null) { CheckDisposed(); @@ -666,7 +667,7 @@ namespace Renci.SshNet /// An that references the asynchronous operation. /// /// The method was called after the client was disposed. - public IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback, object state, Action listCallback = null) + public IAsyncResult BeginListDirectory(string path, AsyncCallback? asyncCallback, object? state, Action? listCallback = null) { CheckDisposed(); @@ -758,7 +759,7 @@ namespace Renci.SshNet if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentException("path"); + throw new ArgumentException(nameof(path)); } if (_sftpSession is null) @@ -814,7 +815,7 @@ namespace Renci.SshNet /// /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. /// - public void DownloadFile(string path, Stream output, Action downloadCallback = null) + public void DownloadFile(string path, Stream output, Action? downloadCallback = null) { CheckDisposed(); @@ -861,7 +862,7 @@ namespace Renci.SshNet /// /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. /// - public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback asyncCallback) + public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback? asyncCallback) { return BeginDownloadFile(path, output, asyncCallback, state: null); } @@ -883,13 +884,13 @@ namespace Renci.SshNet /// /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. /// - public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback asyncCallback, object state, Action downloadCallback = null) + public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback? asyncCallback, object? state, Action? downloadCallback = null) { CheckDisposed(); if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentException("path"); + throw new ArgumentException(nameof(path)); } if (output is null) @@ -951,7 +952,7 @@ namespace Renci.SshNet /// /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. /// - public void UploadFile(Stream input, string path, Action uploadCallback = null) + public void UploadFile(Stream input, string path, Action? uploadCallback = null) { UploadFile(input, path, canOverride: true, uploadCallback); } @@ -972,7 +973,7 @@ namespace Renci.SshNet /// /// Method calls made by this method to , may under certain conditions result in exceptions thrown by the stream. /// - public void UploadFile(Stream input, string path, bool canOverride, Action uploadCallback = null) + public void UploadFile(Stream input, string path, bool canOverride, Action? uploadCallback = null) { CheckDisposed(); @@ -1040,7 +1041,7 @@ namespace Renci.SshNet /// If the remote file already exists, it is overwritten and truncated. /// /// - public IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback asyncCallback) + public IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback? asyncCallback) { return BeginUploadFile(input, path, canOverride: true, asyncCallback, state: null); } @@ -1070,7 +1071,7 @@ namespace Renci.SshNet /// If the remote file already exists, it is overwritten and truncated. /// /// - public IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback asyncCallback, object state, Action uploadCallback = null) + public IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback? asyncCallback, object? state, Action? uploadCallback = null) { return BeginUploadFile(input, path, canOverride: true, asyncCallback, state, uploadCallback); } @@ -1100,7 +1101,7 @@ namespace Renci.SshNet /// . /// /// - public IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, AsyncCallback asyncCallback, object state, Action uploadCallback = null) + public IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, AsyncCallback? asyncCallback, object? state, Action? uploadCallback = null) { CheckDisposed(); @@ -1111,7 +1112,7 @@ namespace Renci.SshNet if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentException("path"); + throw new ArgumentException(nameof(path)); } var flags = Flags.Write | Flags.Truncate; @@ -1718,9 +1719,10 @@ namespace Renci.SshNet using (var stream = new StreamReader(OpenRead(path), encoding)) { - while (!stream.EndOfStream) + string? line; + while ((line = stream.ReadLine()) != null) { - lines.Add(stream.ReadLine()); + lines.Add(line); } } @@ -2105,7 +2107,7 @@ namespace Renci.SshNet if (string.IsNullOrWhiteSpace(destinationPath)) { - throw new ArgumentException("destinationPath"); + throw new ArgumentException(nameof(destinationPath)); } return InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asynchResult: null); @@ -2122,10 +2124,10 @@ namespace Renci.SshNet /// /// An that represents the asynchronous directory synchronization. /// - /// is . + /// or is . /// is or contains only whitespace. /// If a problem occurs while copying the file. - public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state) + public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback? asyncCallback, object? state) { if (sourcePath is null) { @@ -2134,7 +2136,12 @@ namespace Renci.SshNet if (string.IsNullOrWhiteSpace(destinationPath)) { - throw new ArgumentException("destDir"); + throw new ArgumentException(nameof(destinationPath)); + } + + if (searchPattern is null) + { + throw new ArgumentNullException(nameof(searchPattern)); } var asyncResult = new SftpSynchronizeDirectoriesAsyncResult(asyncCallback, state); @@ -2176,7 +2183,7 @@ namespace Renci.SshNet return ar.EndInvoke(); } - private List InternalSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, SftpSynchronizeDirectoriesAsyncResult asynchResult) + private List InternalSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, SftpSynchronizeDirectoriesAsyncResult? asynchResult) { if (!Directory.Exists(sourcePath)) { @@ -2271,7 +2278,7 @@ namespace Renci.SshNet /// /// is . /// Client not connected. - private List InternalListDirectory(string path, SftpListDirectoryAsyncResult asyncResult, Action listCallback) + private List InternalListDirectory(string path, SftpListDirectoryAsyncResult? asyncResult, Action? listCallback) { if (path is null) { @@ -2338,7 +2345,7 @@ namespace Renci.SshNet /// is . /// is or contains whitespace. /// Client not connected. - private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncResult asyncResult, Action downloadCallback) + private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncResult? asyncResult, Action? downloadCallback) { if (output is null) { @@ -2347,7 +2354,7 @@ namespace Renci.SshNet if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentException("path"); + throw new ArgumentException(nameof(path)); } if (_sftpSession is null) @@ -2404,7 +2411,7 @@ namespace Renci.SshNet /// is . /// is or contains whitespace. /// Client not connected. - private void InternalUploadFile(Stream input, string path, Flags flags, SftpUploadAsyncResult asyncResult, Action uploadCallback) + private void InternalUploadFile(Stream input, string path, Flags flags, SftpUploadAsyncResult? asyncResult, Action? uploadCallback) { if (input is null) { @@ -2413,7 +2420,7 @@ namespace Renci.SshNet if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentException("path"); + throw new ArgumentException(nameof(path)); } if (_sftpSession is null)