我目前正在尝试使用Renci SSH.NET将文件复制到使用SFTP的Unix服务器,此外,我想创建一个指向我复制的文件的符号链接。这基本上就是我的代码的样子,请注意变量sftp
是SftpClient
的工作实例:
string symlinkSource = @"/msyerver/SymSource/Test001"; //source to link to, exists
string newPath = @"/msyerver/somedirectory/Test001"; //place where the symlink should be created
sftp.SymbolicLink(symlinkSource, newPath); //link newPath to symlinkSource, works!
sftp.Delete(newPath); //fails with exception!
问题是:如何正确删除符号链接?请注意:我只想删除文件夹Test001
的链接,而不是删除引用的文件夹本身。为什么这不起作用?遗憾的是,SSH.NET没有抛出有意义的异常,我得到的唯一文本是“失败”,由于这内部通过一些“请求”机制工作,我无法调试问题的确切来源。
当我查看异常时,我发现:
Data: {System.Collections.ListDictionaryInternal}
很明显,看起来SSH.NET正试图删除链接文件夹。我想要的是删除符号链接本身,而不是后面的文件夹。
答案 0 :(得分:1)
实际上,SftpClient.Delete
(和SftpClient.DeleteFile
)的实现方式,它们无法删除符号链接。他们首先使用路径调用SftpSession.GetCanonicalPath
,解析链接的内容。所以你实际上是试图删除链接目标而不是链接本身,由于某种原因失败了。
无法使用SSH.NET API删除链接本身。
虽然有一些反思黑客攻击你可以绕过SftpSession.GetCanonicalPath
电话:
public static class SftpClientExtensions
{
public static void DeleteLink(this SftpClient client, string path)
{
Type sftpClientType = client.GetType();
FieldInfo sftpSessionField = sftpClientType.GetField("_sftpSession", BindingFlags.NonPublic | BindingFlags.Instance);
object sftpSession = sftpSessionField.GetValue(client);
Type sftpSessionType = sftpSession.GetType();
MethodInfo requestRemoveMethod = sftpSessionType.GetMethod("RequestRemove", BindingFlags.NonPublic | BindingFlags.Instance);
requestRemoveMethod.Invoke(sftpSession, new object[] { path });
}
}
使用上述扩展方法,您现在可以使用:
sftp.DeleteLink(newPath);
更好的方法是获取SSH.NET源代码的副本并将该方法直接添加到SftpClient
类。并向SSH.NET project提交请求以支持删除链接。
答案 1 :(得分:1)
从列表目录中获取文件项,而不是反射 hack。
SftpFile[] listDirectory = this.sftpClient.ListDirectory(path.Substring(0, Math.Max(0, path.LastIndexOf('/')))).ToArray();
SftpFile sftpFile = listDirectory.FirstOrDefault(f => f.FullName.Equals(path));
sftpFile?.Delete();
考虑全名比较
答案 2 :(得分:0)
此方法删除文件夹中的所有文件,包括符号链接
public void DeleteDirectory(string path)
{
using (var sftp = new SftpClient(ost, Settings.Instance.Deployment_user, Settings.Instance.Deployment_password))
{
sftp.Connect();
foreach (SftpFile file in sftp.ListDirectory(path))
{
if ((file.Name != ".") && (file.Name != ".."))
{
if (file.IsDirectory)
{
DeleteDirectory(file.FullName);
}
else
{
file.Delete();
}
}
}
sftp.DeleteDirectory(path);
sftp.Disconnect();
}
}