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)