Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/Renci.SshNet/Abstractions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
85 changes: 19 additions & 66 deletions src/Renci.SshNet/Sftp/SftpSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,68 +102,27 @@ internal void SendMessage(SftpMessage sftpMessage)
/// <inheritdoc/>
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();
}

/// <inheritdoc/>
public async Task<string> GetCanonicalPathAsync(string path, CancellationToken cancellationToken)
public Task<string> GetCanonicalPathAsync(string path, CancellationToken cancellationToken)
{
return GetCanonicalPathCore(path, isAsync: true, cancellationToken);
}

private async Task<string> 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;
Expand All @@ -178,29 +137,23 @@ public async Task<string> 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);
Comment thread
Rob-Hague marked this conversation as resolved.
Resolved

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)
{
Expand All @@ -218,7 +171,7 @@ public async Task<string> 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)
Expand Down