From 6828536a7fa54a3929ccc40da908315df86b155f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Wed, 10 May 2023 15:06:31 +0200 Subject: [PATCH 1/3] Remove FEATURE_DIRECTORYINFO_ENUMERATEFILES --- .../Abstractions/FileSystemAbstraction.cs | 32 ------- src/Renci.SshNet/Renci.SshNet.csproj | 4 +- src/Renci.SshNet/SftpClient.cs | 88 ++++++++++--------- 3 files changed, 50 insertions(+), 74 deletions(-) delete mode 100644 src/Renci.SshNet/Abstractions/FileSystemAbstraction.cs diff --git a/src/Renci.SshNet/Abstractions/FileSystemAbstraction.cs b/src/Renci.SshNet/Abstractions/FileSystemAbstraction.cs deleted file mode 100644 index 1bce391ed..000000000 --- a/src/Renci.SshNet/Abstractions/FileSystemAbstraction.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace Renci.SshNet.Abstractions -{ - internal class FileSystemAbstraction - { - /// - /// Returns an enumerable collection of file information that matches a search pattern. - /// - /// - /// The search string to match against the names of files. - /// - /// An enumerable collection of files that matches . - /// - /// is null. - /// is null. - /// The path represented by does not exist or is not valid. - public static IEnumerable EnumerateFiles(DirectoryInfo directoryInfo, string searchPattern) - { - if (directoryInfo == null) - throw new ArgumentNullException("directoryInfo"); - -#if FEATURE_DIRECTORYINFO_ENUMERATEFILES - return directoryInfo.EnumerateFiles(searchPattern); -#else - return directoryInfo.GetFiles(searchPattern); -#endif - } - } -} diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 2f39c80ec..21b0128a8 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -5,7 +5,7 @@ false Renci.SshNet ../Renci.SshNet.snk - 6 + 7.3 true net462;netstandard2.0;net6.0;net7.0 @@ -19,6 +19,6 @@ - FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP + FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 2705382ad..788dec23e 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -2074,60 +2074,68 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, var sourceDirectory = new DirectoryInfo(sourcePath); - var sourceFiles = FileSystemAbstraction.EnumerateFiles(sourceDirectory, searchPattern).ToList(); - if (sourceFiles.Count == 0) - return uploadedFiles; - - #region Existing Files at The Destination - - var destFiles = InternalListDirectory(destinationPath, null); - var destDict = new Dictionary(); - foreach (var destFile in destFiles) + using (var sourceFiles = sourceDirectory.EnumerateFiles(searchPattern).GetEnumerator()) { - if (destFile.IsDirectory) - continue; - destDict.Add(destFile.Name, destFile); - } + if(!sourceFiles.MoveNext()) + return uploadedFiles; - #endregion - - #region Upload the difference - - const Flags uploadFlag = Flags.Write | Flags.Truncate | Flags.CreateNewOrOpen; - foreach (var localFile in sourceFiles) - { - var isDifferent = !destDict.ContainsKey(localFile.Name); + #region Existing Files at The Destination - if (!isDifferent) + var destFiles = InternalListDirectory(destinationPath, null); + var destDict = new Dictionary(); + foreach (var destFile in destFiles) { - var 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 (destFile.IsDirectory) + continue; + destDict.Add(destFile.Name, destFile); } - if (isDifferent) + #endregion + + #region Upload the difference + + const Flags uploadFlag = Flags.Write | Flags.Truncate | Flags.CreateNewOrOpen; + do { - var remoteFileName = string.Format(CultureInfo.InvariantCulture, @"{0}/{1}", destinationPath, localFile.Name); - try + var localFile = sourceFiles.Current; + if (localFile == null) + { + continue; + } + + var isDifferent = !destDict.ContainsKey(localFile.Name); + + if (!isDifferent) { - using (var file = File.OpenRead(localFile.FullName)) + var 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 { - InternalUploadFile(file, remoteFileName, uploadFlag, null, null); - } + using (var file = File.OpenRead(localFile.FullName)) + { + InternalUploadFile(file, remoteFileName, uploadFlag, null, null); + } - uploadedFiles.Add(localFile); + uploadedFiles.Add(localFile); - if (asynchResult != null) + if (asynchResult != null) + { + asynchResult.Update(uploadedFiles.Count); + } + } + catch (Exception ex) { - asynchResult.Update(uploadedFiles.Count); + throw new Exception(string.Format("Failed to upload {0} to {1}", localFile.FullName, remoteFileName), ex); } } - catch (Exception ex) - { - throw new Exception(string.Format("Failed to upload {0} to {1}", localFile.FullName, remoteFileName), ex); - } - } + } while (sourceFiles.MoveNext()); } #endregion From 4e8d60b3ce8819c301d931dee16612b5ecfdc2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Wed, 17 May 2023 09:58:28 +0200 Subject: [PATCH 2/3] Fix review --- src/Renci.SshNet/SftpClient.cs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 788dec23e..a15898448 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -2076,8 +2076,10 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, using (var sourceFiles = sourceDirectory.EnumerateFiles(searchPattern).GetEnumerator()) { - if(!sourceFiles.MoveNext()) + if (!sourceFiles.MoveNext()) + { return uploadedFiles; + } #region Existing Files at The Destination @@ -2086,7 +2088,10 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, foreach (var destFile in destFiles) { if (destFile.IsDirectory) + { continue; + } + destDict.Add(destFile.Name, destFile); } @@ -2103,14 +2108,12 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, continue; } - var isDifferent = !destDict.ContainsKey(localFile.Name); - - if (!isDifferent) + var isDifferent = true; + if (destDict.TryGetValue(localFile.Name, out var remoteFile)) { - var 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; + isDifferent = localFile.Length != remoteFile.Length; } if (isDifferent) @@ -2132,10 +2135,11 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, } catch (Exception ex) { - throw new Exception(string.Format("Failed to upload {0} to {1}", localFile.FullName, remoteFileName), ex); + throw new SshException($"Failed to upload {localFile.FullName} to {remoteFileName}", ex); } } - } while (sourceFiles.MoveNext()); + } + while (sourceFiles.MoveNext()); } #endregion From 46b1ac5eae0e22a516f5559de581c70c5c4f3fae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Wed, 17 May 2023 10:07:35 +0200 Subject: [PATCH 3/3] Add exception documentation --- src/Renci.SshNet/SftpClient.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index a15898448..937f4a1a0 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -1996,6 +1996,7 @@ public void SetAttributes(string path, SftpFileAttributes fileAttributes) /// is null. /// is null or contains only whitespace. /// was not found on the remote host. + /// If a problem occurs while copying the file public IEnumerable SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern) { if (sourcePath == null) @@ -2019,6 +2020,7 @@ public IEnumerable SynchronizeDirectories(string sourcePath, string de /// /// is null. /// is null or contains only whitespace. + /// If a problem occurs while copying the file public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state) { if (sourcePath == null)