mirror of
https://github.com/sshnet/SSH.NET.git
synced 2026-09-10 01:05:42 +00:00
ScpClient: allow disabling the -d flag (#1751)
* ScpClient: allow disabling the -d flag fixes #1746 * Apply suggestion from @Rob-Hague --------- Co-authored-by: Rob Hague <rob.hague00@gmail.com>
This commit is contained in:
@@ -121,6 +121,25 @@ namespace Renci.SshNet
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the "-d" flag should be passed to the scp process on the server
|
||||
/// when uploading files. Defaults to <see langword="true"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The "-d" flag is an undocumented flag that ensures that the target is actually a directory. However,
|
||||
/// some scp implementations (like Cisco) do not support this flag and will fail.
|
||||
/// You can set this to <see langword="false"/> to work around this.
|
||||
/// </remarks>
|
||||
public bool UseDirectoryFlag { get; set; } = true;
|
||||
|
||||
private string EnsureIsDirectoryArg
|
||||
{
|
||||
get
|
||||
{
|
||||
return UseDirectoryFlag ? "-d" : string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when downloading file.
|
||||
/// </summary>
|
||||
@@ -258,9 +277,9 @@ namespace Renci.SshNet
|
||||
channel.Closed += (sender, e) => input.Dispose();
|
||||
channel.Open();
|
||||
|
||||
// Pass only the directory part of the path to the server, and use the (hidden) -d option to signal
|
||||
// Pass only the directory part of the path to the server, and optionally use the (hidden) -d option to signal
|
||||
// that we expect the target to be a directory.
|
||||
if (!channel.SendExecRequest(string.Format("scp -t -d {0}", _remotePathTransformation.Transform(posixPath.Directory))))
|
||||
if (!channel.SendExecRequest($"scp -t {EnsureIsDirectoryArg} {_remotePathTransformation.Transform(posixPath.Directory)}"))
|
||||
{
|
||||
throw SecureExecutionRequestRejectedException();
|
||||
}
|
||||
@@ -301,9 +320,9 @@ namespace Renci.SshNet
|
||||
channel.Closed += (sender, e) => input.Dispose();
|
||||
channel.Open();
|
||||
|
||||
// Pass only the directory part of the path to the server, and use the (hidden) -d option to signal
|
||||
// Pass only the directory part of the path to the server, and optionally use the (hidden) -d option to signal
|
||||
// that we expect the target to be a directory.
|
||||
if (!channel.SendExecRequest($"scp -t -d {_remotePathTransformation.Transform(posixPath.Directory)}"))
|
||||
if (!channel.SendExecRequest($"scp -t {EnsureIsDirectoryArg} {_remotePathTransformation.Transform(posixPath.Directory)}"))
|
||||
{
|
||||
throw SecureExecutionRequestRejectedException();
|
||||
}
|
||||
@@ -352,7 +371,7 @@ namespace Renci.SshNet
|
||||
// -r copy directories recursively
|
||||
// -d expect path to be a directory
|
||||
// -t copy to remote
|
||||
if (!channel.SendExecRequest($"scp -r -p -d -t {_remotePathTransformation.Transform(path)}"))
|
||||
if (!channel.SendExecRequest($"scp -r -p {EnsureIsDirectoryArg} -t {_remotePathTransformation.Transform(path)}"))
|
||||
{
|
||||
throw SecureExecutionRequestRejectedException();
|
||||
}
|
||||
|
||||
@@ -2098,5 +2098,64 @@ namespace Renci.SshNet.IntegrationTests
|
||||
|
||||
return path1 + "/" + path2;
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task UploadWithUseDirectoryFlagFalse()
|
||||
{
|
||||
string remoteDirectory = "/home/sshnet/usedirectoryflagfalsetest";
|
||||
|
||||
// remote cleanup
|
||||
using (var sftpClient = new SftpClient(_connectionInfoFactory.Create()))
|
||||
{
|
||||
await sftpClient.ConnectAsync(CancellationToken.None);
|
||||
|
||||
if (await sftpClient.ExistsAsync(remoteDirectory))
|
||||
{
|
||||
await sftpClient.DeleteDirectoryAsync(remoteDirectory);
|
||||
}
|
||||
|
||||
await sftpClient.CreateDirectoryAsync(remoteDirectory);
|
||||
}
|
||||
|
||||
using (var client = new ScpClient(_connectionInfoFactory.Create()))
|
||||
{
|
||||
client.UseDirectoryFlag = false;
|
||||
|
||||
await client.ConnectAsync(CancellationToken.None);
|
||||
int tempFileSize = 1024;
|
||||
string tempFilePath = CreateTempFile(tempFileSize);
|
||||
MemoryStream downloadedStream = new();
|
||||
|
||||
// FileInfo overload
|
||||
client.Upload(new FileInfo(tempFilePath), $"{remoteDirectory}/file1");
|
||||
client.Download($"{remoteDirectory}/file1", downloadedStream);
|
||||
Assert.AreEqual(tempFileSize, downloadedStream.Length);
|
||||
|
||||
// Stream overload
|
||||
downloadedStream = new();
|
||||
using (Stream stream = File.OpenRead(tempFilePath))
|
||||
{
|
||||
client.Upload(stream, $"{remoteDirectory}/file2");
|
||||
client.Download($"{remoteDirectory}/file2", downloadedStream);
|
||||
Assert.AreEqual(tempFileSize, downloadedStream.Length);
|
||||
}
|
||||
|
||||
// DirectoryInfo overload
|
||||
downloadedStream = new();
|
||||
string tempDir = Path.Combine(Path.GetTempPath(), "SSH.NET_UploadWithUseDirectoryFlagFalseTest");
|
||||
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, true);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(tempDir);
|
||||
File.Move(tempFilePath, $"{tempDir}/file3");
|
||||
|
||||
client.Upload(new DirectoryInfo(tempDir), remoteDirectory);
|
||||
client.Download($"{remoteDirectory}/file3", downloadedStream);
|
||||
Assert.AreEqual(tempFileSize, downloadedStream.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user