Added CreateDirectoryAsync to SftpClient (#1505)

* Added CreateDirectoryAsync to SftpClient

* Use CreateDirectoryAsync for async test

---------

Co-authored-by: Rob Hague <rob.hague00@gmail.com>
This commit is contained in:
Ryan Esteves
2024-09-25 15:50:27 -04:00
committed by GitHub
parent 737c3e5f9d
commit ce867d6640
6 changed files with 90 additions and 5 deletions
+13
View File
@@ -429,6 +429,19 @@ namespace Renci.SshNet
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
void CreateDirectory(string path);
/// <summary>
/// Asynchronously requests to create a remote directory specified by path.
/// </summary>
/// <param name="path">Directory path to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous create directory operation.</returns>
/// <exception cref="ArgumentException"><paramref name="path"/> is <see langword="null"/> or contains only whitespace characters.</exception>
/// <exception cref="SshConnectionException">Client is not connected.</exception>
/// <exception cref="SftpPermissionDeniedException">Permission to create 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 CreateDirectoryAsync(string path, CancellationToken cancellationToken = default);
/// <summary>
/// Creates or opens a file for writing UTF-8 encoded text.
/// </summary>
+8
View File
@@ -162,6 +162,14 @@ namespace Renci.SshNet.Sftp
/// <param name="path">The path.</param>
void RequestMkDir(string path);
/// <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>
Task RequestMkDirAsync(string path, CancellationToken cancellationToken = default);
/// <summary>
/// Performs a <c>SSH_FXP_OPEN</c> request.
/// </summary>
+38
View File
@@ -1544,6 +1544,44 @@ 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>
public async Task RequestMkDirAsync(string path, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
#if NET || NETSTANDARD2_1_OR_GREATER
await using (cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false))
#else
using (cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false))
#endif // NET || NETSTANDARD2_1_OR_GREATER
{
SendRequest(new SftpMkDirRequest(ProtocolVersion,
NextRequestId,
path,
_encoding,
response =>
{
if (response.StatusCode == StatusCodes.Ok)
{
_ = tcs.TrySetResult(true);
}
else
{
tcs.TrySetException(GetSftpException(response));
}
}));
_ = await tcs.Task.ConfigureAwait(false);
}
}
/// <summary>
/// Performs SSH_FXP_RMDIR request.
/// </summary>
+26
View File
@@ -373,6 +373,32 @@ namespace Renci.SshNet
_sftpSession.RequestMkDir(fullPath);
}
/// <summary>
/// Asynchronously requests to create a remote directory specified by path.
/// </summary>
/// <param name="path">Directory path to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous create directory operation.</returns>
/// <exception cref="ArgumentException"><paramref name="path"/> is <see langword="null"/> or contains only whitespace characters.</exception>
/// <exception cref="SshConnectionException">Client is not connected.</exception>
/// <exception cref="SftpPermissionDeniedException">Permission to create 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 CreateDirectoryAsync(string path, CancellationToken cancellationToken = default)
{
CheckDisposed();
ThrowHelper.ThrowIfNullOrWhiteSpace(path);
if (_sftpSession is null)
{
throw new SshConnectionException("Client not connected.");
}
var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false);
await _sftpSession.RequestMkDirAsync(fullPath, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Deletes remote directory specified by path.
/// </summary>
@@ -239,15 +239,15 @@ namespace Renci.SshNet.IntegrationTests.OldIntegrationTests
Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet");
sftp.CreateDirectory("test1");
await sftp.CreateDirectoryAsync("test1", CancellationToken.None).ConfigureAwait(false);
await sftp.ChangeDirectoryAsync("test1", CancellationToken.None).ConfigureAwait(false);
Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet/test1");
sftp.CreateDirectory("test1_1");
sftp.CreateDirectory("test1_2");
sftp.CreateDirectory("test1_3");
await sftp.CreateDirectoryAsync("test1_1", CancellationToken.None).ConfigureAwait(false);
await sftp.CreateDirectoryAsync("test1_2", CancellationToken.None).ConfigureAwait(false);
await sftp.CreateDirectoryAsync("test1_3", CancellationToken.None).ConfigureAwait(false);
var files = sftp.ListDirectory(".");
@@ -60,7 +60,7 @@ namespace Renci.SshNet.IntegrationTests
var testContent = "file content";
// Create new directory and check if it exists
_sftpClient.CreateDirectory(testDirectory);
await _sftpClient.CreateDirectoryAsync(testDirectory, CancellationToken.None).ConfigureAwait(false);
Assert.IsTrue(await _sftpClient.ExistsAsync(testDirectory));
// Upload file and check if it exists