1

我目前正在尝试使用 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 正在尝试删除链接的文件夹。我想要的是删除符号链接本身,而不是后面的文件夹。

4

3 回答 3

1

而不是反射黑客,从列表目录中获取文件项。

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();

考虑全名比较

于 2021-03-16T17:42:16.497 回答
1

此方法删除文件夹中的所有文件,包括符号链接

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();
        }
    }
于 2019-04-15T21:58:08.150 回答
1

事实上,SftpClient.Delete(and 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 项目提交请求以支持删除链接。

于 2016-05-19T06:36:41.123 回答