<PackageReference Include="SSH.NET" Version="2016.0.0-beta2" />

ScpClient

public class ScpClient : BaseClient
Provides SCP client functionality.
using Renci.SshNet.Channels; using Renci.SshNet.Common; using System; using System.IO; using System.Text; using System.Text.RegularExpressions; namespace Renci.SshNet { public class ScpClient : BaseClient { private static readonly Regex FileInfoRe = new Regex("C(?<mode>\\d{4}) (?<length>\\d+) (?<filename>.+)"); private static char[] _byteToChar; private static readonly Regex DirectoryInfoRe = new Regex("D(?<mode>\\d{4}) (?<length>\\d+) (?<filename>.+)"); private static readonly Regex TimestampRe = new Regex("T(?<mtime>\\d+) 0 (?<atime>\\d+) 0"); public TimeSpan OperationTimeout { get; set; } public uint BufferSize { get; set; } public event EventHandler<ScpDownloadEventArgs> Downloading; public event EventHandler<ScpUploadEventArgs> Uploading; public ScpClient(ConnectionInfo connectionInfo) : this(connectionInfo, false) { } public ScpClient(string host, int port, string username, string password) : this(new PasswordConnectionInfo(host, port, username, password), true) { } public ScpClient(string host, string username, string password) : this(host, ConnectionInfo.DefaultPort, username, password) { } public ScpClient(string host, int port, string username, params PrivateKeyFile[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) { } public ScpClient(string host, string username, params PrivateKeyFile[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } private ScpClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo) : this(connectionInfo, ownsConnectionInfo, new ServiceFactory()) { } internal ScpClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) : base(connectionInfo, ownsConnectionInfo, serviceFactory) { OperationTimeout = Renci.SshNet.Session.InfiniteTimeSpan; BufferSize = 16384; if (_byteToChar == null) { _byteToChar = new char[128]; char c = ''; for (int i = 0; i < 128; i++) { char[] byteToChar = _byteToChar; int num = i; char num2 = c; c = (char)(num2 + 1); byteToChar[num] = num2; } } } public void Upload(Stream source, string path) { PipeStream input = base.ServiceFactory.CreatePipeStream(); try { using (IChannelSession channelSession = base.Session.CreateChannelSession()) { channelSession.DataReceived += delegate(object sender, ChannelDataEventArgs e) { input.Write(e.Data, 0, e.Data.Length); }; channelSession.Open(); int num = path.LastIndexOfAny(new char[2] { '\\', '/' }); if (num != -1) { string arg = path.Substring(0, num); string text = path.Substring(num + 1); channelSession.SendExecRequest($"""{arg}"""); CheckReturnCode(input); path = text; } InternalUpload(channelSession, input, source, path); channelSession.Close(); } } finally { if (input != null) ((IDisposable)input).Dispose(); } } public void Download(string filename, Stream destination) { if (filename.IsNullOrWhiteSpace()) throw new ArgumentException("filename"); if (destination == null) throw new ArgumentNullException("destination"); PipeStream input = base.ServiceFactory.CreatePipeStream(); try { using (IChannelSession channelSession = base.Session.CreateChannelSession()) { channelSession.DataReceived += delegate(object sender, ChannelDataEventArgs e) { input.Write(e.Data, 0, e.Data.Length); }; channelSession.Open(); channelSession.SendExecRequest($"""{filename}"""); SendConfirmation(channelSession); string text = ReadString(input); Match match = FileInfoRe.Match(text); if (match.Success) { SendConfirmation(channelSession); match.Result("${mode}"); long length = long.Parse(match.Result("${length}")); string filename2 = match.Result("${filename}"); InternalDownload(channelSession, input, destination, filename2, length); } else SendConfirmation(channelSession, 1, $"""{text}"""); channelSession.Close(); } } finally { if (input != null) ((IDisposable)input).Dispose(); } } private void InternalSetTimestamp(IChannelSession channel, Stream input, DateTime lastWriteTime, DateTime lastAccessime) { DateTime d = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); TimeSpan timeSpan = lastWriteTime - d; long num = (long)timeSpan.TotalSeconds; timeSpan = lastAccessime - d; long num2 = (long)timeSpan.TotalSeconds; SendData(channel, $"""{num}""{num2}"""); CheckReturnCode(input); } private void InternalUpload(IChannelSession channel, Stream input, Stream source, string filename) { long length = source.Length; SendData(channel, $"""{length}""{Path.GetFileName(filename)}"""); CheckReturnCode(input); byte[] array = new byte[BufferSize]; int num = source.Read(array, 0, array.Length); long num2 = 0; while (num > 0) { SendData(channel, array, num); num2 += num; RaiseUploadingEvent(filename, length, num2); num = source.Read(array, 0, array.Length); } SendConfirmation(channel); CheckReturnCode(input); } private void InternalDownload(IChannel channel, Stream input, Stream output, string filename, long length) { byte[] buffer = new byte[Math.Min(length, BufferSize)]; long num = length; do { int num2 = input.Read(buffer, 0, (int)Math.Min(num, BufferSize)); output.Write(buffer, 0, num2); RaiseDownloadingEvent(filename, length, length - num); num -= num2; } while (num > 0); output.Flush(); RaiseDownloadingEvent(filename, length, length - num); SendConfirmation(channel); CheckReturnCode(input); } private void RaiseDownloadingEvent(string filename, long size, long downloaded) { if (this.Downloading != null) this.Downloading(this, new ScpDownloadEventArgs(filename, size, downloaded)); } private void RaiseUploadingEvent(string filename, long size, long uploaded) { if (this.Uploading != null) this.Uploading(this, new ScpUploadEventArgs(filename, size, uploaded)); } private void SendConfirmation(IChannel channel) { SendData(channel, new byte[1]); } private void SendConfirmation(IChannel channel, byte errorCode, string message) { SendData(channel, new byte[1] { errorCode }); SendData(channel, $"{message}"""); } private static void CheckReturnCode(Stream input) { if (ReadByte(input) > 0) throw new ScpException(ReadString(input)); } private static void SendData(IChannel channel, string command) { channel.SendData(SshData.Utf8.GetBytes(command)); } private static void SendData(IChannel channel, byte[] buffer, int length) { channel.SendData(buffer, 0, length); } private static void SendData(IChannel channel, byte[] buffer) { channel.SendData(buffer); } private static int ReadByte(Stream stream) { int num = stream.ReadByte(); if (num == -1) throw new SshException("Stream has been closed."); return num; } private static string ReadString(Stream stream) { bool flag = false; StringBuilder stringBuilder = new StringBuilder(); int num = ReadByte(stream); if (num == 1 || num == 2) { flag = true; num = ReadByte(stream); } for (char c = _byteToChar[num]; c != '\n'; c = _byteToChar[num]) { stringBuilder.Append(c); num = ReadByte(stream); } if (flag) throw new ScpException(stringBuilder.ToString()); return stringBuilder.ToString(); } public void Upload(FileInfo fileInfo, string path) { if (fileInfo == null) throw new ArgumentNullException("fileInfo"); if (string.IsNullOrEmpty(path)) throw new ArgumentException("path"); PipeStream input = base.ServiceFactory.CreatePipeStream(); try { using (IChannelSession channelSession = base.Session.CreateChannelSession()) { channelSession.DataReceived += delegate(object sender, ChannelDataEventArgs e) { input.Write(e.Data, 0, e.Data.Length); }; channelSession.Open(); if (!channelSession.SendExecRequest($"""{path}""")) throw new SshException("Secure copy execution request was rejected by the server. Please consult the server logs."); CheckReturnCode(input); InternalUpload(channelSession, input, fileInfo, fileInfo.Name); channelSession.Close(); } } finally { if (input != null) ((IDisposable)input).Dispose(); } } public void Upload(DirectoryInfo directoryInfo, string path) { if (directoryInfo == null) throw new ArgumentNullException("directoryInfo"); if (string.IsNullOrEmpty(path)) throw new ArgumentException("path"); PipeStream input = base.ServiceFactory.CreatePipeStream(); try { using (IChannelSession channelSession = base.Session.CreateChannelSession()) { channelSession.DataReceived += delegate(object sender, ChannelDataEventArgs e) { input.Write(e.Data, 0, e.Data.Length); }; channelSession.Open(); channelSession.SendExecRequest($"""{path}"""); CheckReturnCode(input); InternalSetTimestamp(channelSession, input, directoryInfo.LastWriteTimeUtc, directoryInfo.LastAccessTimeUtc); SendData(channelSession, $"""{Path.GetFileName(path)}"""); CheckReturnCode(input); InternalUpload(channelSession, input, directoryInfo); SendData(channelSession, "E\n"); CheckReturnCode(input); channelSession.Close(); } } finally { if (input != null) ((IDisposable)input).Dispose(); } } public void Download(string filename, FileInfo fileInfo) { if (string.IsNullOrEmpty(filename)) throw new ArgumentException("filename"); if (fileInfo == null) throw new ArgumentNullException("fileInfo"); PipeStream input = base.ServiceFactory.CreatePipeStream(); try { using (IChannelSession channelSession = base.Session.CreateChannelSession()) { channelSession.DataReceived += delegate(object sender, ChannelDataEventArgs e) { input.Write(e.Data, 0, e.Data.Length); }; channelSession.Open(); channelSession.SendExecRequest($"""{filename}"""); SendConfirmation(channelSession); InternalDownload(channelSession, input, fileInfo); channelSession.Close(); } } finally { if (input != null) ((IDisposable)input).Dispose(); } } public void Download(string directoryName, DirectoryInfo directoryInfo) { if (string.IsNullOrEmpty(directoryName)) throw new ArgumentException("directoryName"); if (directoryInfo == null) throw new ArgumentNullException("directoryInfo"); PipeStream input = base.ServiceFactory.CreatePipeStream(); try { using (IChannelSession channelSession = base.Session.CreateChannelSession()) { channelSession.DataReceived += delegate(object sender, ChannelDataEventArgs e) { input.Write(e.Data, 0, e.Data.Length); }; channelSession.Open(); channelSession.SendExecRequest($"""{directoryName}"""); SendConfirmation(channelSession); InternalDownload(channelSession, input, directoryInfo); channelSession.Close(); } } finally { if (input != null) ((IDisposable)input).Dispose(); } } private void InternalUpload(IChannelSession channel, Stream input, FileInfo fileInfo, string filename) { InternalSetTimestamp(channel, input, fileInfo.LastWriteTimeUtc, fileInfo.LastAccessTimeUtc); using (FileStream source = fileInfo.OpenRead()) InternalUpload(channel, input, source, filename); } private void InternalUpload(IChannelSession channel, Stream input, DirectoryInfo directoryInfo) { FileInfo[] files = directoryInfo.GetFiles(); foreach (FileInfo fileInfo in files) { InternalUpload(channel, input, fileInfo, fileInfo.Name); } DirectoryInfo[] directories = directoryInfo.GetDirectories(); foreach (DirectoryInfo directoryInfo2 in directories) { InternalSetTimestamp(channel, input, directoryInfo.LastWriteTimeUtc, directoryInfo.LastAccessTimeUtc); SendData(channel, $"""{directoryInfo2.Name}"""); CheckReturnCode(input); InternalUpload(channel, input, directoryInfo2); SendData(channel, "E\n"); CheckReturnCode(input); } } private void InternalDownload(IChannelSession channel, Stream input, FileSystemInfo fileSystemInfo) { DateTime lastWriteTime = DateTime.Now; DateTime lastAccessTime = DateTime.Now; string fullName = fileSystemInfo.FullName; int num = 0; while (true) { string text = ReadString(input); if (text == "E") { SendConfirmation(channel); num--; fullName = new DirectoryInfo(fullName).Parent.FullName; if (num == 0) break; } else { Match match = DirectoryInfoRe.Match(text); if (match.Success) { SendConfirmation(channel); long.Parse(match.Result("${mode}")); string arg = match.Result("${filename}"); DirectoryInfo directoryInfo; if (num > 0) { directoryInfo = Directory.CreateDirectory($"{fullName}{Path.DirectorySeparatorChar}{arg}"); directoryInfo.LastAccessTime = lastAccessTime; directoryInfo.LastWriteTime = lastWriteTime; } else directoryInfo = (fileSystemInfo as DirectoryInfo); num++; fullName = directoryInfo.FullName; } else { match = FileInfoRe.Match(text); if (match.Success) { SendConfirmation(channel); match.Result("${mode}"); long length = long.Parse(match.Result("${length}")); string text2 = match.Result("${filename}"); FileInfo fileInfo = fileSystemInfo as FileInfo; if (fileInfo == null) fileInfo = new FileInfo($"{fullName}{Path.DirectorySeparatorChar}{text2}"); using (FileStream output = fileInfo.OpenWrite()) InternalDownload(channel, input, output, text2, length); fileInfo.LastAccessTime = lastAccessTime; fileInfo.LastWriteTime = lastWriteTime; if (num == 0) break; } else { match = TimestampRe.Match(text); if (match.Success) { SendConfirmation(channel); long num2 = long.Parse(match.Result("${mtime}")); long num3 = long.Parse(match.Result("${atime}")); DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); lastWriteTime = dateTime.AddSeconds((double)num2); lastAccessTime = dateTime.AddSeconds((double)num3); } else SendConfirmation(channel, 1, $"""{text}"""); } } } } } } }