Skip to content

Commit

Permalink
Enable get and delete symlinks
Browse files Browse the repository at this point in the history
  • Loading branch information
Fernando Bedoya Ortecho committed Aug 24, 2023
1 parent de4b777 commit 241fe98
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 1 deletion.
39 changes: 39 additions & 0 deletions src/Renci.SshNet/ISftpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,18 @@ public interface ISftpClient : IBaseClient, IDisposable
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
void DeleteFile(string path);

/// <summary>
/// Deletes remote symbolic link specified by path.
/// </summary>
/// <param name="path">File to be deleted path.</param>
/// <exception cref="ArgumentException"><paramref name="path"/> is <b>null</b> or contains only whitespace characters.</exception>
/// <exception cref="SshConnectionException">Client is not connected.</exception>
/// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</exception>
/// <exception cref="SftpPermissionDeniedException">Permission to delete the file was denied by the remote host. <para>-or-</para> A SSH command was denied by the server.</exception>
/// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the remote host.</exception>
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
void DeleteSymbolicLink(string path);

/// <summary>
/// Asynchronously deletes remote file specified by path.
/// </summary>
Expand Down Expand Up @@ -580,6 +592,20 @@ public interface ISftpClient : IBaseClient, IDisposable
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
bool Exists(string path);

/// <summary>
/// Checks whether symbolic link exists;
/// </summary>
/// <param name="path">The path.</param>
/// <returns>
/// <c>true</c> if directory or file exists; otherwise <c>false</c>.
/// </returns>
/// <exception cref="ArgumentException"><paramref name="path"/> is <b>null</b> or contains only whitespace characters.</exception>
/// <exception cref="SshConnectionException">Client is not connected.</exception>
/// <exception cref="SftpPermissionDeniedException">Permission to perform the operation was denied by the remote host. <para>-or-</para> A SSH command was denied by the server.</exception>
/// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the remote host.</exception>
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
bool SymbolicLinkExists(string path);

/// <summary>
/// Gets reference to remote file or directory.
/// </summary>
Expand All @@ -593,6 +619,19 @@ public interface ISftpClient : IBaseClient, IDisposable
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
ISftpFile Get(string path);

/// <summary>
/// Gets reference to remote symbolic link.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>
/// A reference to <see cref="ISftpFile"/> file object.
/// </returns>
/// <exception cref="SshConnectionException">Client is not connected.</exception>
/// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</exception>
/// <exception cref="ArgumentNullException"><paramref name="path" /> is <b>null</b>.</exception>
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
ISftpFile GetSymbolicLink(string path);

/// <summary>
/// Gets the <see cref="SftpFileAttributes"/> of the file on the path.
/// </summary>
Expand Down
1 change: 0 additions & 1 deletion src/Renci.SshNet/Sftp/SftpSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ public string GetCanonicalPath(string path, bool getRealPath = true)
public async Task<string> GetCanonicalPathAsync(string path, CancellationToken cancellationToken)
{
var fullPath = GetFullRemotePath(path);

var canonizedPath = string.Empty;
var realPathFiles = await RequestRealPathAsync(fullPath, nullOnError: true, cancellationToken).ConfigureAwait(false);
if (realPathFiles != null)
Expand Down
85 changes: 85 additions & 0 deletions src/Renci.SshNet/SftpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,38 @@ public ISftpFile Get(string path)
return new SftpFile(_sftpSession, fullPath, attributes);
}

/// <summary>
/// Gets reference to remote symbolic link.
/// </summary>
/// <param name="path">The path.</param>
/// <returns>
/// A reference to <see cref="ISftpFile"/> file object.
/// </returns>
/// <exception cref="SshConnectionException">Client is not connected.</exception>
/// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</exception>
/// <exception cref="ArgumentNullException"><paramref name="path" /> is <b>null</b>.</exception>
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
public ISftpFile GetSymbolicLink(string path)
{
CheckDisposed();

if (path is null)
{
throw new ArgumentNullException(nameof(path));
}

if (_sftpSession is null)
{
throw new SshConnectionException("Client not connected.");
}

var fullPath = _sftpSession.GetCanonicalPath(path, false);

var attributes = _sftpSession.RequestLStat(fullPath);

return new SftpFile(_sftpSession, fullPath, attributes);
}

/// <summary>
/// Checks whether file or directory exists;
/// </summary>
Expand Down Expand Up @@ -793,6 +825,45 @@ public bool Exists(string path)
}
}

/// <summary>
/// Checks whether symbolic link exists;
/// </summary>
/// <param name="path">The path.</param>
/// <returns>
/// <c>true</c> if directory or file exists; otherwise <c>false</c>.
/// </returns>
/// <exception cref="ArgumentException"><paramref name="path"/> is <b>null</b> or contains only whitespace characters.</exception>
/// <exception cref="SshConnectionException">Client is not connected.</exception>
/// <exception cref="SftpPermissionDeniedException">Permission to perform the operation was denied by the remote host. <para>-or-</para> A SSH command was denied by the server.</exception>
/// <exception cref="SshException">A SSH error where <see cref="Exception.Message"/> is the message from the remote host.</exception>
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
public bool SymbolicLinkExists(string path)
{
CheckDisposed();

if (path.IsNullOrWhiteSpace())
{
throw new ArgumentException("path");
}

if (_sftpSession is null)
{
throw new SshConnectionException("Client not connected.");
}

var fullPath = _sftpSession.GetCanonicalPath(path, false);

try
{
_ = _sftpSession.RequestLStat(fullPath);
return true;
}
catch (SftpPathNotFoundException)
{
return false;
}
}

/// <summary>
/// Downloads remote file specified by the path into the stream.
/// </summary>
Expand Down Expand Up @@ -1479,6 +1550,20 @@ public void Delete(string path)
file.Delete();
}

/// <summary>
/// Deletes the specified symbolic link.
/// </summary>
/// <param name="path">The name of the file or directory to be deleted. Wildcard characters are not supported.</param>
/// <exception cref="ArgumentNullException"><paramref name="path"/> is <b>null</b>.</exception>
/// <exception cref="SshConnectionException">Client is not connected.</exception>
/// <exception cref="SftpPathNotFoundException"><paramref name="path"/> was not found on the remote host.</exception>
/// <exception cref="ObjectDisposedException">The method was called after the client was disposed.</exception>
public void DeleteSymbolicLink(string path)
{
var symLink = GetSymbolicLink(path);
symLink.Delete();
}

/// <summary>
/// Returns the date and time the specified file or directory was last accessed.
/// </summary>
Expand Down

0 comments on commit 241fe98

Please sign in to comment.