ScpClient.NET.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Renci.SshNet.Channels;
  6. using System.IO;
  7. using Renci.SshNet.Common;
  8. using Renci.SshNet.Messages.Connection;
  9. using System.Text.RegularExpressions;
  10. using System.Threading;
  11. using System.Diagnostics;
  12. namespace Renci.SshNet
  13. {
  14. /// <summary>
  15. /// Provides SCP client functionality.
  16. /// </summary>
  17. public partial class ScpClient
  18. {
  19. /// <summary>
  20. /// Uploads the specified file to the remote host.
  21. /// </summary>
  22. /// <param name="fileInfo">Local file to upload.</param>
  23. /// <param name="filename">Remote host file name.</param>
  24. public void Upload(FileInfo fileInfo, string filename)
  25. {
  26. using (var input = new PipeStream())
  27. using (var channel = this.Session.CreateChannel<ChannelSession>())
  28. {
  29. channel.DataReceived += delegate(object sender, Common.ChannelDataEventArgs e)
  30. {
  31. input.Write(e.Data, 0, e.Data.Length);
  32. input.Flush();
  33. };
  34. channel.Open();
  35. // Send channel command request
  36. channel.SendExecRequest(string.Format("scp -qt {0}", filename));
  37. this.CheckReturnCode(input);
  38. this.InternalUpload(channel, input, fileInfo, filename);
  39. channel.Close();
  40. }
  41. }
  42. /// <summary>
  43. /// Uploads the specified directory to the remote host.
  44. /// </summary>
  45. /// <param name="directoryInfo">Local directory to upload.</param>
  46. /// <param name="filename">Remote host directory name.</param>
  47. public void Upload(DirectoryInfo directoryInfo, string filename)
  48. {
  49. using (var input = new PipeStream())
  50. using (var channel = this.Session.CreateChannel<ChannelSession>())
  51. {
  52. channel.DataReceived += delegate(object sender, Common.ChannelDataEventArgs e)
  53. {
  54. input.Write(e.Data, 0, e.Data.Length);
  55. input.Flush();
  56. };
  57. channel.Open();
  58. // Send channel command request
  59. channel.SendExecRequest(string.Format("scp -qrt {0}", filename));
  60. this.CheckReturnCode(input);
  61. this.InternalUpload(channel, input, directoryInfo, filename);
  62. channel.Close();
  63. }
  64. }
  65. /// <summary>
  66. /// Downloads the specified file from the remote host to local file.
  67. /// </summary>
  68. /// <param name="filename">Remote host file name.</param>
  69. /// <param name="fileInfo">Local file information.</param>
  70. public void Download(string filename, FileInfo fileInfo)
  71. {
  72. using (var input = new PipeStream())
  73. using (var channel = this.Session.CreateChannel<ChannelSession>())
  74. {
  75. channel.DataReceived += delegate(object sender, Common.ChannelDataEventArgs e)
  76. {
  77. input.Write(e.Data, 0, e.Data.Length);
  78. input.Flush();
  79. };
  80. channel.Open();
  81. // Send channel command request
  82. channel.SendExecRequest(string.Format("scp -qpf \"{0}\"", filename));
  83. this.SendConfirmation(channel); // Send reply
  84. this.InternalDownload(channel, input, fileInfo);
  85. channel.Close();
  86. }
  87. }
  88. /// <summary>
  89. /// Downloads the specified directory from the remote host to local directory.
  90. /// </summary>
  91. /// <param name="directoryName">Remote host directory name.</param>
  92. /// <param name="directoryInfo">Local directory information.</param>
  93. public void Download(string directoryName, DirectoryInfo directoryInfo)
  94. {
  95. using (var input = new PipeStream())
  96. using (var channel = this.Session.CreateChannel<ChannelSession>())
  97. {
  98. channel.DataReceived += delegate(object sender, Common.ChannelDataEventArgs e)
  99. {
  100. input.Write(e.Data, 0, e.Data.Length);
  101. input.Flush();
  102. };
  103. channel.Open();
  104. // Send channel command request
  105. channel.SendExecRequest(string.Format("scp -qprf {0}", directoryName));
  106. this.SendConfirmation(channel); // Send reply
  107. this.InternalDownload(channel, input, directoryInfo);
  108. channel.Close();
  109. }
  110. }
  111. private void InternalUpload(ChannelSession channel, Stream input, FileInfo fileInfo, string filename)
  112. {
  113. this.InternalSetTimestamp(channel, input, fileInfo.LastWriteTimeUtc, fileInfo.LastAccessTimeUtc);
  114. using (var source = fileInfo.OpenRead())
  115. {
  116. this.InternalFileUpload(channel, input, source, filename);
  117. }
  118. }
  119. private void InternalUpload(ChannelSession channel, PipeStream input, DirectoryInfo directoryInfo, string directoryName)
  120. {
  121. this.InternalSetTimestamp(channel, input, directoryInfo.LastWriteTimeUtc, directoryInfo.LastAccessTimeUtc);
  122. this.SendData(channel, string.Format("D0755 0 {0}\n", directoryName));
  123. this.CheckReturnCode(input);
  124. // Upload files
  125. var files = directoryInfo.GetFiles();
  126. foreach (var file in files)
  127. {
  128. this.InternalUpload(channel, input, file, file.Name);
  129. }
  130. // Upload directories
  131. var directories = directoryInfo.GetDirectories();
  132. foreach (var directory in directories)
  133. {
  134. this.InternalUpload(channel, input, directory, directory.Name);
  135. }
  136. this.SendData(channel, "E\n");
  137. this.CheckReturnCode(input);
  138. }
  139. private void InternalDownload(ChannelSession channel, Stream input, FileSystemInfo fileSystemInfo)
  140. {
  141. DateTime modifiedTime = DateTime.Now;
  142. DateTime accessedTime = DateTime.Now;
  143. var startDirectoryFullName = fileSystemInfo.FullName;
  144. var currentDirectoryFullName = startDirectoryFullName;
  145. var directoryCounter = 0;
  146. while (true)
  147. {
  148. var message = ReadString(input);
  149. if (message == "E")
  150. {
  151. this.SendConfirmation(channel); // Send reply
  152. directoryCounter--;
  153. currentDirectoryFullName = new DirectoryInfo(currentDirectoryFullName).Parent.FullName;
  154. //if (currentDirectoryFullName == startDirectoryFullName)
  155. if (directoryCounter == 0)
  156. break;
  157. else
  158. continue;
  159. }
  160. var match = _directoryInfoRe.Match(message);
  161. if (match.Success)
  162. {
  163. this.SendConfirmation(channel); // Send reply
  164. // Read directory
  165. var mode = long.Parse(match.Result("${mode}"));
  166. var filename = match.Result("${filename}");
  167. DirectoryInfo newDirectoryInfo;
  168. if (directoryCounter > 0)
  169. {
  170. newDirectoryInfo = Directory.CreateDirectory(string.Format("{0}{1}{2}", currentDirectoryFullName, Path.DirectorySeparatorChar, filename));
  171. newDirectoryInfo.LastAccessTime = accessedTime;
  172. newDirectoryInfo.LastWriteTime = modifiedTime;
  173. }
  174. else
  175. {
  176. // Dont create directory for first level
  177. newDirectoryInfo = fileSystemInfo as DirectoryInfo;
  178. }
  179. directoryCounter++;
  180. currentDirectoryFullName = newDirectoryInfo.FullName;
  181. continue;
  182. }
  183. match = _fileInfoRe.Match(message);
  184. if (match.Success)
  185. {
  186. // Read file
  187. this.SendConfirmation(channel); // Send reply
  188. var mode = match.Result("${mode}");
  189. var length = long.Parse(match.Result("${length}"));
  190. var fileName = match.Result("${filename}");
  191. var fileInfo = fileSystemInfo as FileInfo;
  192. if (fileInfo == null)
  193. fileInfo = new FileInfo(string.Format("{0}{1}{2}", currentDirectoryFullName, Path.DirectorySeparatorChar, fileName));
  194. using (var output = fileInfo.OpenWrite())
  195. {
  196. this.InternalFileDownload(channel, input, output, fileName, length);
  197. }
  198. fileInfo.LastAccessTime = accessedTime;
  199. fileInfo.LastWriteTime = modifiedTime;
  200. if (fileSystemInfo is FileInfo)
  201. break;
  202. continue;
  203. }
  204. match = _timestampRe.Match(message);
  205. if (match.Success)
  206. {
  207. // Read timestamp
  208. this.SendConfirmation(channel); // Send reply
  209. var mtime = long.Parse(match.Result("${mtime}"));
  210. var atime = long.Parse(match.Result("${atime}"));
  211. var zeroTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
  212. modifiedTime = zeroTime.AddSeconds(mtime);
  213. accessedTime = zeroTime.AddSeconds(atime);
  214. continue;
  215. }
  216. this.SendConfirmation(channel, 1, string.Format("\"{0}\" is not valid protocol message.", message));
  217. }
  218. }
  219. partial void SendData(ChannelSession channel, string command)
  220. {
  221. channel.SendData(System.Text.Encoding.Default.GetBytes(command));
  222. }
  223. }
  224. }