|
|
@@ -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)
|