Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build/build.proj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
<OutputDirectory>Renci.SshNet\bin\$(Configuration)\netstandard2.0</OutputDirectory>
<Moniker>netstandard2.0</Moniker>
</TargetFrameworkModern>
<TargetFrameworkModern Include=".NETStandard 2.1">
<OutputDirectory>Renci.SshNet\bin\$(Configuration)\netstandard2.1</OutputDirectory>
<Moniker>netstandard2.1</Moniker>
</TargetFrameworkModern>
<TargetFrameworkModern Include=".NET 6.0">
<OutputDirectory>Renci.SshNet\bin\$(Configuration)\net6.0</OutputDirectory>
<Moniker>net6.0</Moniker>
Expand Down
3 changes: 3 additions & 0 deletions build/nuget/SSH.NET.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
<group targetFramework="net462" />
<group targetFramework="netstandard2.0">
<dependency id="SshNet.Security.Cryptography" version="[1.3.0]" />
</group>
<group targetFramework="netstandard2.1">
<dependency id="SshNet.Security.Cryptography" version="[1.3.0]" />
</group>
<group targetFramework="net6.0">
<dependency id="SshNet.Security.Cryptography" version="[1.3.0]" />
Expand Down
12 changes: 7 additions & 5 deletions src/Renci.SshNet/ISftpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public interface ISftpClient : IBaseClient, IDisposable
/// SSH_FXP_DATA protocol fields.
/// </para>
/// <para>
/// The size of the each indivual SSH_FXP_DATA message is limited to the
/// The size of the each individual SSH_FXP_DATA message is limited to the
/// local maximum packet size of the channel, which is set to <c>64 KB</c>
/// for SSH.NET. However, the peer can limit this even further.
/// </para>
Expand Down Expand Up @@ -698,21 +698,23 @@ public interface ISftpClient : IBaseClient, IDisposable
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
IEnumerable<ISftpFile> ListDirectory(string path, Action<int> listCallback = null);

#if FEATURE_ASYNC_ENUMERABLE
/// <summary>
/// Asynchronously retrieves list of files in remote directory.
/// Asynchronously enumerates the files in remote directory.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
/// <returns>
/// A <see cref="Task{IEnumerable}"/> that represents the asynchronous list operation.
/// The task result contains an enumerable collection of <see cref="SftpFile"/> for the files in the directory specified by <paramref name="path" />.
/// An <see cref="IAsyncEnumerable{SftpFile}"/> that represents the asynchronous enumeration operation.
/// The enumeration contains an async stream of <see cref="SftpFile"/> for the files in the directory specified by <paramref name="path" />.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="path" /> is <b>null</b>.</exception>
/// <exception cref="SshConnectionException">Client is not connected.</exception>
/// <exception cref="SftpPermissionDeniedException">Permission to list the contents of the directory was denied by the remote host. <para>-or-</para> A SSH command was denied by the server.</exception>
/// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the remote host.</exception>
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
Task<IEnumerable<ISftpFile>> ListDirectoryAsync(string path, CancellationToken cancellationToken);
IAsyncEnumerable<ISftpFile> ListDirectoryAsync(string path, CancellationToken cancellationToken);
#endif //FEATURE_ASYNC_ENUMERABLE

/// <summary>
/// Opens a <see cref="SftpFileStream"/> on the specified path with read/write access.
Expand Down
12 changes: 8 additions & 4 deletions src/Renci.SshNet/Renci.SshNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AssemblyName>Renci.SshNet</AssemblyName>
<AssemblyOriginatorKeyFile>../Renci.SshNet.snk</AssemblyOriginatorKeyFile>
<LangVersion>7.3</LangVersion>
<LangVersion>latest</LangVersion>
<SignAssembly>true</SignAssembly>
<TargetFrameworks>net462;netstandard2.0;net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net462;netstandard2.0;netstandard2.1;net6.0;net7.0</TargetFrameworks>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net462' ">
<DefineConstants>FEATURE_BINARY_SERIALIZATION;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_DNS_SYNC;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160</DefineConstants>
</PropertyGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' ">
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' ">
<PackageReference Include="SshNet.Security.Cryptography" Version="[1.3.0]" />
</ItemGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' ">
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' ">
<DefineConstants>FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.1' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' ">
<DefineConstants>$(DefineConstants);FEATURE_ASYNC_ENUMERABLE</DefineConstants>
</PropertyGroup>
</Project>
24 changes: 13 additions & 11 deletions src/Renci.SshNet/SftpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
using Renci.SshNet.Common;
using Renci.SshNet.Sftp;
using System.Threading.Tasks;
#if FEATURE_ASYNC_ENUMERABLE
using System.Runtime.CompilerServices;
#endif

namespace Renci.SshNet
{
Expand Down Expand Up @@ -91,7 +94,7 @@ public TimeSpan OperationTimeout
/// SSH_FXP_DATA protocol fields.
/// </para>
/// <para>
/// The size of the each indivual SSH_FXP_DATA message is limited to the
/// The size of the each individual SSH_FXP_DATA message is limited to the
/// local maximum packet size of the channel, which is set to <c>64 KB</c>
/// for SSH.NET. However, the peer can limit this even further.
/// </para>
Expand Down Expand Up @@ -530,32 +533,33 @@ public IEnumerable<ISftpFile> ListDirectory(string path, Action<int> listCallbac
return InternalListDirectory(path, listCallback);
}

#if FEATURE_ASYNC_ENUMERABLE
/// <summary>
/// Asynchronously retrieves list of files in remote directory.
/// Asynchronously enumerates the files in remote directory.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
/// <returns>
/// A <see cref="Task{IEnumerable}"/> that represents the asynchronous list operation.
/// The task result contains an enumerable collection of <see cref="SftpFile"/> for the files in the directory specified by <paramref name="path" />.
/// An <see cref="IAsyncEnumerable{SftpFile}"/> that represents the asynchronous enumeration operation.
/// The enumeration contains an async stream of <see cref="SftpFile"/> for the files in the directory specified by <paramref name="path" />.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="path" /> is <b>null</b>.</exception>
/// <exception cref="SshConnectionException">Client is not connected.</exception>
/// <exception cref="SftpPermissionDeniedException">Permission to list the contents of the directory was denied by the remote host. <para>-or-</para> A SSH command was denied by the server.</exception>
/// <exception cref="SshException">A SSH error where <see cref="Exception.Message" /> is the message from the remote host.</exception>
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
public async Task<IEnumerable<ISftpFile>> ListDirectoryAsync(string path, CancellationToken cancellationToken)
public async IAsyncEnumerable<ISftpFile> ListDirectoryAsync(string path, [EnumeratorCancellation] CancellationToken cancellationToken)
{
base.CheckDisposed();
if (path == null)
throw new ArgumentNullException("path");
throw new ArgumentNullException(nameof(path));
if (_sftpSession == null)
throw new SshConnectionException("Client not connected.");

cancellationToken.ThrowIfCancellationRequested();

var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false);

var result = new List<SftpFile>();
var handle = await _sftpSession.RequestOpenDirAsync(fullPath, cancellationToken).ConfigureAwait(false);
try
{
Expand All @@ -573,18 +577,16 @@ public async Task<IEnumerable<ISftpFile>> ListDirectoryAsync(string path, Cancel

foreach (var file in files)
{
result.Add(new SftpFile(_sftpSession, basePath + file.Key, file.Value));
yield return new SftpFile(_sftpSession, basePath + file.Key, file.Value);
}
}

}
finally
{
await _sftpSession.RequestCloseAsync(handle, cancellationToken).ConfigureAwait(false);
}

return result;
}
#endif //FEATURE_ASYNC_ENUMERABLE

/// <summary>
/// Begins an asynchronous operation of retrieving list of files in remote directory.
Expand Down