From 7945a9526ec41b2975c85179e712b837ea5e986d Mon Sep 17 00:00:00 2001 From: skogaby Date: Wed, 7 Feb 2018 16:03:44 -0600 Subject: [PATCH] Allow writing to stdin for SshCommand execution --- src/Renci.SshNet/SshCommand.cs | 49 +++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs index 37e91da08..288e778d3 100644 --- a/src/Renci.SshNet/SshCommand.cs +++ b/src/Renci.SshNet/SshCommand.cs @@ -195,6 +195,8 @@ public IAsyncResult BeginExecute(AsyncCallback callback) /// /// An optional asynchronous callback, to be called when the command execution is complete. /// A user-provided object that distinguishes this particular asynchronous read request from other requests. + /// A stream to be used as the output stream. + /// A stream to be used as the extended output stream. /// /// An that represents the asynchronous command execution, which could still be pending. /// @@ -205,7 +207,7 @@ public IAsyncResult BeginExecute(AsyncCallback callback) /// Operation has timed out. /// Asynchronous operation is already in progress. /// CommandText property is empty. - public IAsyncResult BeginExecute(AsyncCallback callback, object state) + public IAsyncResult BeginExecute(AsyncCallback callback, object state, Stream stdout = null, Stream stderr = null) { // Prevent from executing BeginExecute before calling EndExecute if (_asyncResult != null && !_asyncResult.EndCalled) @@ -245,8 +247,8 @@ public IAsyncResult BeginExecute(AsyncCallback callback, object state) } // Initialize output streams - OutputStream = new PipeStream(); - ExtendedOutputStream = new PipeStream(); + OutputStream = (stdout == null ? new PipeStream() : stdout); + ExtendedOutputStream = (stderr == null ? new PipeStream() : stderr); _result = null; _error = null; @@ -307,6 +309,9 @@ public string EndExecute(IAsyncResult asyncResult) throw new ArgumentException("EndExecute can only be called once for each asynchronous operation."); } + // always send EOF when closing exec channel + _channel.SendEof(); + // wait for operation to complete (or time out) WaitOnHandle(_asyncResult.AsyncWaitHandle); @@ -514,6 +519,44 @@ private void UnsubscribeFromEventsAndDisposeChannel(IChannel channel) channel.Dispose(); } + /// + /// Sends the data to channel. + /// + /// Data. + public void SendData(byte[] data) + { + SendData(data, 0, data.Length); + } + + /// + /// Sends the data with offset and size to channel. + /// + /// Data. + /// Offset. + /// Size. + public void SendData(byte[] data, int offset, int size) + { + _channel.SendData(data, offset, size); + } + + /// + /// Sends the data to channel. + /// + /// Data. + public void SendData(Stream data) + { + if (data == null) + return; + + byte[] buffer = new byte[2048]; // read in chunks of 2KB + int bytesRead; + + while ((bytesRead = data.Read(buffer, 0, buffer.Length)) > 0) + { + _channel.SendData(buffer, 0, bytesRead); + } + } + #region IDisposable Members private bool _isDisposed;