diff --git a/Renci.SshClient/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj b/Renci.SshClient/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj index 16ccc98c..967780ab 100644 --- a/Renci.SshClient/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj +++ b/Renci.SshClient/Renci.SshNet.NET35/Renci.SshNet.NET35.csproj @@ -634,6 +634,9 @@ SftpClient.cs + + SftpClient.NET.cs + Sftp\Flags.cs diff --git a/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj b/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj index 9c5b9a36..4ee65f28 100644 --- a/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj +++ b/Renci.SshClient/Renci.SshNet/Renci.SshNet.csproj @@ -12,10 +12,6 @@ Renci.SshNet v4.0 512 - SAK - SAK - SAK - SAK true @@ -135,6 +131,7 @@ Code + Code diff --git a/Renci.SshClient/Renci.SshNet/Session.cs b/Renci.SshClient/Renci.SshNet/Session.cs index 21daefa6..42aaf9d9 100644 --- a/Renci.SshClient/Renci.SshNet/Session.cs +++ b/Renci.SshClient/Renci.SshNet/Session.cs @@ -183,12 +183,7 @@ namespace Renci.SshNet { get { - return (!this._isDisconnecting - && this._socket != null - && this._socket.Connected - && this._isAuthenticated - && this._messageListenerCompleted != null); - //&& !(this._socket.Poll(10, SelectMode.SelectRead)); + return (!this._isDisconnecting && this._socket != null && this._socket.Connected && this._isAuthenticated && this._messageListenerCompleted != null) && !(this._socket.Poll(10, SelectMode.SelectRead)); } } diff --git a/Renci.SshClient/Renci.SshNet/Sftp/SftpSynchronizeDirectoriesAsyncResult.cs b/Renci.SshClient/Renci.SshNet/Sftp/SftpSynchronizeDirectoriesAsyncResult.cs index 6450ee9c..a1ee9189 100644 --- a/Renci.SshClient/Renci.SshNet/Sftp/SftpSynchronizeDirectoriesAsyncResult.cs +++ b/Renci.SshClient/Renci.SshNet/Sftp/SftpSynchronizeDirectoriesAsyncResult.cs @@ -6,7 +6,10 @@ using Renci.SshNet.Common; using System.IO; namespace Renci.SshNet.Sftp -{ +{ + /// + /// Encapsulates the results of an asynchronous directory synchronization operation. + /// public class SftpSynchronizeDirectoriesAsyncResult : AsyncResult> { /// diff --git a/Renci.SshClient/Renci.SshNet/SftpClient.NET.cs b/Renci.SshClient/Renci.SshNet/SftpClient.NET.cs new file mode 100644 index 00000000..82cac33e --- /dev/null +++ b/Renci.SshClient/Renci.SshNet/SftpClient.NET.cs @@ -0,0 +1,153 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.IO; +using Renci.SshNet.Sftp; +using System.Text; +using Renci.SshNet.Common; +using System.Globalization; +using System.Threading; +using System.Diagnostics.CodeAnalysis; + +namespace Renci.SshNet +{ + /// + /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. + /// + public partial class SftpClient : BaseClient + { + #region SynchronizeDirectories + + public IEnumerable SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern) + { + return InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, null); + } + + public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state) + { + if (sourcePath == null) + throw new ArgumentNullException("sourceDir"); + if (destinationPath.IsNullOrWhiteSpace()) + throw new ArgumentException("destDir"); + + // Ensure that connection is established. + this.EnsureConnection(); + + var asyncResult = new SftpSynchronizeDirectoriesAsyncResult(asyncCallback, state); + + this.ExecuteThread(() => + { + try + { + var result = this.InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asyncResult); + + asyncResult.SetAsCompleted(result, false); + } + catch (Exception exp) + { + asyncResult.SetAsCompleted(exp, false); + } + }); + + return asyncResult; + } + + public IEnumerable EndSynchronizeDirectories(IAsyncResult asyncResult) + { + var ar = asyncResult as SftpSynchronizeDirectoriesAsyncResult; + + if (ar == null || ar.EndInvokeCalled) + throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult."); + + // Wait for operation to complete, then return result or throw exception + return ar.EndInvoke(); + } + + private IEnumerable InternalSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, SftpSynchronizeDirectoriesAsyncResult asynchResult) + { + if (destinationPath.IsNullOrWhiteSpace()) + throw new ArgumentException("destinationPath"); + + if (!Directory.Exists(sourcePath)) + throw new FileNotFoundException(string.Format("Source directory not found: {0}", sourcePath)); + + IList uploadedFiles = new List(); + + DirectoryInfo sourceDirectory = new DirectoryInfo(sourcePath); + +#if SILVERLIGHT + var sourceFiles = sourceDirectory.EnumerateFiles(searchPattern); +#else + var sourceFiles = sourceDirectory.GetFiles(searchPattern); +#endif + + if (sourceFiles == null || sourceFiles.Count() <= 0) + return uploadedFiles; + + try + { + #region Existing Files at The Destination + + var destFiles = InternalListDirectory(destinationPath, null); + Dictionary destDict = new Dictionary(); + foreach (var destFile in destFiles) + { + if (destFile.IsDirectory) + continue; + destDict.Add(destFile.Name, destFile); + } + + #endregion + + #region Upload the difference + + bool isDifferent = false; + Flags uploadFlag = Flags.Write | Flags.Truncate | Flags.CreateNewOrOpen; + foreach (var localFile in sourceFiles) + { + isDifferent = !destDict.ContainsKey(localFile.Name); + + if (!isDifferent) + { + SftpFile temp = destDict[localFile.Name]; + // TODO: Use md5 to detect a difference + //ltang: File exists at the destination => Using filesize to detect the difference + isDifferent = localFile.Length != temp.Length; + } + + if (isDifferent) + { + var remoteFileName = string.Format(CultureInfo.InvariantCulture, @"{0}/{1}", destinationPath, localFile.Name); + try + { + using (var file = File.OpenRead(localFile.FullName)) + { + this.InternalUploadFile(file, remoteFileName, null, uploadFlag); + } + + uploadedFiles.Add(localFile); + + if (asynchResult != null) + { + asynchResult.Update(uploadedFiles.Count); + } + } + catch (Exception ex) + { + throw new Exception(string.Format("Failed to upload {0} to {1}", localFile.FullName, remoteFileName), ex); + } + } + } + + #endregion + } + catch + { + throw; + } + return uploadedFiles; + } + + #endregion + } +} diff --git a/Renci.SshClient/Renci.SshNet/SftpClient.cs b/Renci.SshClient/Renci.SshNet/SftpClient.cs index 1a534627..511612e4 100644 --- a/Renci.SshClient/Renci.SshNet/SftpClient.cs +++ b/Renci.SshClient/Renci.SshNet/SftpClient.cs @@ -346,141 +346,6 @@ namespace Renci.SshNet return ar.EndInvoke(); } - - #region SynchronizeDirectories -#if (!WINDOWS_PHONE) - public IEnumerable SynchronizeDirectories(string sourceDir - , string destDir - , string searchPattern) - { - return InternalSynchronizeDirectories(sourceDir, destDir, searchPattern, null); - } - - public IAsyncResult BeginSynchronizeDirectories(string sourceDir - , string destDir - , string searchPattern, AsyncCallback asyncCallback, object state) - { - if (sourceDir == null) - throw new ArgumentNullException("sourceDir"); - if (destDir.IsNullOrWhiteSpace()) - throw new ArgumentException("destDir"); - - // Ensure that connection is established. - this.EnsureConnection(); - - var asyncResult = new SftpSynchronizeDirectoriesAsyncResult(asyncCallback, state); - - this.ExecuteThread(() => - { - try - { - var result = this.InternalSynchronizeDirectories(sourceDir, destDir, searchPattern, asyncResult); - - asyncResult.SetAsCompleted(result, false); - } - catch (Exception exp) - { - asyncResult.SetAsCompleted(exp, false); - } - }); - - return asyncResult; - } - - public IEnumerable EndSynchronizeDirectories(IAsyncResult asyncResult) - { - var ar = asyncResult as SftpSynchronizeDirectoriesAsyncResult; - - if (ar == null || ar.EndInvokeCalled) - throw new ArgumentException("Either the IAsyncResult object did not come from the corresponding async method on this type, or EndExecute was called multiple times with the same IAsyncResult."); - - // Wait for operation to complete, then return result or throw exception - return ar.EndInvoke(); - } - - private IEnumerable InternalSynchronizeDirectories(string sourceDir, - string destDir, - string searchPattern, - SftpSynchronizeDirectoriesAsyncResult asynchResult) - { - if (destDir.IsNullOrWhiteSpace()) - throw new ArgumentException("destDir"); - if (!Directory.Exists(sourceDir)) - throw new FileNotFoundException(string.Format("Source directory not found: {0}", sourceDir)); - - IList uploadedFiles = new List(); - - DirectoryInfo source = new DirectoryInfo(sourceDir); - -#if (SILVERLIGHT) - var sourceFiles = source.EnumerateFiles(searchPattern); -#else - var sourceFiles = source.GetFiles(searchPattern); -#endif - if (sourceFiles == null || sourceFiles.Count() <= 0) - return uploadedFiles; - - try - { - #region Existing Files at The Destination - var destFiles = InternalListDirectory(destDir, null); - Dictionary destDict = new Dictionary(); - foreach (var destFile in destFiles) - { - if (destFile.IsDirectory) - continue; - destDict.Add(destFile.Name, destFile); - } - #endregion - - #region Upload the difference - string remoteFileName; - bool isDifferent = false; - Flags uploadFlag = Flags.Write | Flags.Truncate | Flags.CreateNewOrOpen; - foreach (var localFile in sourceFiles) - { - isDifferent = !destDict.ContainsKey(localFile.Name); - if (!isDifferent) - { - SftpFile temp = destDict[localFile.Name]; - //ltang: File exists at the destination => Using filesize to detect the difference - isDifferent = localFile.Length != temp.Length; - } - - if (isDifferent) - { - remoteFileName = string.Format(CultureInfo.InvariantCulture, @"{0}/{1}", destDir, localFile.Name); - try - { - using (var file = File.OpenRead(localFile.FullName)) - { - InternalUploadFile(file, remoteFileName, null, uploadFlag); - } - uploadedFiles.Add(localFile); - - if (asynchResult != null) - { - asynchResult.Update(uploadedFiles.Count); - } - } - catch (Exception ex) - { - throw new Exception(string.Format("Failed to upload {0} to {1}", localFile.FullName, remoteFileName), ex); - } - } - } - #endregion - } - catch - { - throw; - } - return uploadedFiles; - } -#endif - #endregion - - /// /// Gets reference to remote file or directory. /// @@ -1415,7 +1280,7 @@ namespace Renci.SshNet if (bytesRead < this.BufferSize) { var data = new byte[bytesRead]; - Buffer.BlockCopy(buffer, 0, data, 0, bytesRead); + Buffer.BlockCopy(buffer, 0, data, 0, bytesRead); using (var wait = new AutoResetEvent(false)) { this._sftpSession.RequestWrite(handle, offset, data, wait);