diff --git a/src/Renci.SshNet/Abstractions/StringExtensions.cs b/src/Renci.SshNet/Abstractions/StringExtensions.cs index d62c5684c..58c572213 100644 --- a/src/Renci.SshNet/Abstractions/StringExtensions.cs +++ b/src/Renci.SshNet/Abstractions/StringExtensions.cs @@ -27,7 +27,9 @@ public static string Join(char separator, string?[] value, int startIndex, int c public int IndexOf(char value, StringComparison comparisonType) { - return text.IndexOf(value.ToString(), comparisonType); + return comparisonType == StringComparison.Ordinal + ? text.IndexOf(value) + : text.IndexOf(value.ToString(), comparisonType); } public bool Contains(char value) diff --git a/src/Renci.SshNet/Sftp/SftpSession.cs b/src/Renci.SshNet/Sftp/SftpSession.cs index 041554505..5c2147efc 100644 --- a/src/Renci.SshNet/Sftp/SftpSession.cs +++ b/src/Renci.SshNet/Sftp/SftpSession.cs @@ -102,68 +102,27 @@ internal void SendMessage(SftpMessage sftpMessage) /// public string GetCanonicalPath(string path) { - var fullPath = GetFullRemotePath(path); - - var canonizedPath = string.Empty; - - var realPathFiles = RequestRealPath(fullPath, nullOnError: true); - - if (realPathFiles != null) - { - canonizedPath = realPathFiles[0].Key; - } - - if (!string.IsNullOrEmpty(canonizedPath)) - { - return canonizedPath; - } - - // Check for special cases - if (fullPath.EndsWith("/.", StringComparison.OrdinalIgnoreCase) || - fullPath.EndsWith("/..", StringComparison.OrdinalIgnoreCase) || - fullPath.Equals("/", StringComparison.OrdinalIgnoreCase) || - fullPath.IndexOf('/', StringComparison.OrdinalIgnoreCase) < 0) - { - return fullPath; - } - - var pathParts = fullPath.Split('/'); - - var partialFullPath = string.Join('/', pathParts, 0, pathParts.Length - 1); - - if (string.IsNullOrEmpty(partialFullPath)) - { - partialFullPath = "/"; - } - - realPathFiles = RequestRealPath(partialFullPath, nullOnError: true); - - if (realPathFiles != null) - { - canonizedPath = realPathFiles[0].Key; - } - - if (string.IsNullOrEmpty(canonizedPath)) - { - return fullPath; - } - - var slash = string.Empty; - if (canonizedPath[canonizedPath.Length - 1] != '/') - { - slash = "/"; - } - - return string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", canonizedPath, slash, pathParts[pathParts.Length - 1]); + return GetCanonicalPathCore(path, isAsync: false, CancellationToken.None).GetAwaiter().GetResult(); } /// - public async Task GetCanonicalPathAsync(string path, CancellationToken cancellationToken) + public Task GetCanonicalPathAsync(string path, CancellationToken cancellationToken) { + return GetCanonicalPathCore(path, isAsync: true, cancellationToken); + } + + private async Task GetCanonicalPathCore(string path, bool isAsync, CancellationToken cancellationToken) + { + Debug.Assert(isAsync || cancellationToken == default); + var fullPath = GetFullRemotePath(path); var canonizedPath = string.Empty; - var realPathFiles = await RequestRealPathAsync(fullPath, nullOnError: true, cancellationToken).ConfigureAwait(false); + + var realPathFiles = isAsync + ? await RequestRealPathAsync(fullPath, nullOnError: true, cancellationToken).ConfigureAwait(false) + : RequestRealPath(fullPath, nullOnError: true); + if (realPathFiles != null) { canonizedPath = realPathFiles[0].Key; @@ -178,29 +137,23 @@ public async Task GetCanonicalPathAsync(string path, CancellationToken c if (fullPath.EndsWith("/.", StringComparison.Ordinal) || fullPath.EndsWith("/..", StringComparison.Ordinal) || fullPath.Equals("/", StringComparison.Ordinal) || -#if NET fullPath.IndexOf('/', StringComparison.Ordinal) < 0) -#else - fullPath.IndexOf('/') < 0) -#endif { return fullPath; } var pathParts = fullPath.Split('/'); -#if NET - var partialFullPath = string.Join('/', pathParts); -#else - var partialFullPath = string.Join("/", pathParts); -#endif + var partialFullPath = string.Join('/', pathParts, 0, pathParts.Length - 1); if (string.IsNullOrEmpty(partialFullPath)) { partialFullPath = "/"; } - realPathFiles = await RequestRealPathAsync(partialFullPath, nullOnError: true, cancellationToken).ConfigureAwait(false); + realPathFiles = isAsync + ? await RequestRealPathAsync(partialFullPath, nullOnError: true, cancellationToken).ConfigureAwait(false) + : RequestRealPath(partialFullPath, nullOnError: true); if (realPathFiles != null) { @@ -218,7 +171,7 @@ public async Task GetCanonicalPathAsync(string path, CancellationToken c slash = "/"; } - return canonizedPath + slash + pathParts[pathParts.Length - 1]; + return string.Concat(canonizedPath, slash, pathParts[pathParts.Length - 1]); } internal string GetFullRemotePath(string path)