checking in all the old panacean stuff
This commit is contained in:
388
puttysrc/SMFTP/SFTPClient.cs
Normal file
388
puttysrc/SMFTP/SFTPClient.cs
Normal file
@@ -0,0 +1,388 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
|
||||
namespace SMFTP
|
||||
{
|
||||
/// <remarks>
|
||||
/// Wrapper Managed Class around putty sftp.
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// SFTPClient client = new SFTPClient();
|
||||
/// if(client.Connect("sftp.somedomain.com","user","password","22"))
|
||||
/// bool bFetchedFile = client.CmdExec_Any("get somefile.txt");
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </remarks>
|
||||
public class SFTPClient : IDisposable
|
||||
{
|
||||
#region Private Statics
|
||||
|
||||
/// <summary>
|
||||
/// Used in the all to LoadLibrary * Names here
|
||||
/// * if you change it here * also change DllImports (below)
|
||||
/// </summary>
|
||||
private const string PSFTP_FILENAME = "psftp.dll";
|
||||
|
||||
/// <summary>
|
||||
/// We only want to load the Psftp dll once per process
|
||||
/// </summary>
|
||||
private static bool s_PSFTPDLL_IsLoaded = false;
|
||||
|
||||
/// <summary>
|
||||
/// Responsible for creating an active connection
|
||||
/// </summary>
|
||||
[DllImport("psftp.dll")]
|
||||
private static extern int dllmain(int argc, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPStr)] String[] argv);
|
||||
|
||||
/// <summary>
|
||||
/// Responsible for running a command on an active connection
|
||||
/// </summary>
|
||||
[DllImport("psftp.dll")]
|
||||
private static extern int do_sftp2([MarshalAs(UnmanagedType.LPStr)] string cmdLine);
|
||||
|
||||
/// <summary>
|
||||
/// Responsible for Putty Cleanup
|
||||
/// </summary>
|
||||
[DllImport("psftp.dll")]
|
||||
private static extern void dllmain_cleanup();
|
||||
|
||||
/// <summary>
|
||||
/// Loads the Putty Dll
|
||||
/// </summary>
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr LoadLibrary(String dllname);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Construction / Destruction
|
||||
|
||||
/// <summary>
|
||||
/// Create a SFTClient Object
|
||||
/// </summary>
|
||||
public SFTPClient()
|
||||
{
|
||||
// Extract the Native Dll to the Temp Directory,
|
||||
// if it is not already there...
|
||||
if (!File.Exists(_pstfpTempFileNameNPath))
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(("SMFTP.Components." + PSFTP_FILENAME))))
|
||||
using (BinaryWriter bw = new BinaryWriter(new FileStream(_pstfpTempFileNameNPath, FileMode.Create)))
|
||||
{
|
||||
byte[] buffer = new byte[64 * 1024];
|
||||
int numread = br.Read(buffer, 0, buffer.Length);
|
||||
while (numread > 0)
|
||||
{
|
||||
bw.Write(buffer, 0, numread);
|
||||
numread = br.Read(buffer, 0, buffer.Length);
|
||||
}
|
||||
bw.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
// Load the dll, if it isn't already
|
||||
if (!s_PSFTPDLL_IsLoaded)
|
||||
{
|
||||
IntPtr hDll = LoadLibrary(_pstfpTempFileNameNPath);
|
||||
s_PSFTPDLL_IsLoaded = (hDll != IntPtr.Zero);
|
||||
}
|
||||
if (!s_PSFTPDLL_IsLoaded)
|
||||
throw new Exception(("Failed to load " + _pstfpTempFileNameNPath + ". Something terrible is wrong"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizer
|
||||
/// </summary>
|
||||
~SFTPClient()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Members
|
||||
|
||||
private bool _IsConnected = false;
|
||||
private bool _disposed = false;
|
||||
private readonly string _pstfpTempFileNameNPath = Path.GetTempPath() + PSFTP_FILENAME;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Main Putty Functions
|
||||
|
||||
/// <summary>
|
||||
/// Start a Connection to the specified Host with the specified credentials
|
||||
/// </summary>
|
||||
/// <param name="hostname">url to sftp host</param>
|
||||
/// <param name="username">user credential</param>
|
||||
/// <param name="password">password credential</param>
|
||||
/// <param name="port">port to connect to (default 22)</param>
|
||||
/// <returns>true if connection occured successfully, false otherwise</returns>
|
||||
public bool Connect(string hostname, string username, string password, string port = "22")
|
||||
{
|
||||
if (String.IsNullOrEmpty(hostname) || String.IsNullOrEmpty(username) || String.IsNullOrEmpty(password) || String.IsNullOrEmpty(port))
|
||||
throw new ArgumentException("Empty String not valid for any of the arguments");
|
||||
|
||||
Disconnect();
|
||||
int nResult = dllmain(10, new String[] { Assembly.GetExecutingAssembly().Location, "-l", username, "-pw", password, "-P", port, "-batch", "-y", hostname });
|
||||
if (nResult != 0) // Error occured connecting to host with specified prms
|
||||
return false;
|
||||
|
||||
_IsConnected = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End the active Connection
|
||||
/// </summary>
|
||||
public bool Disconnect()
|
||||
{
|
||||
if (_IsConnected)
|
||||
{
|
||||
dllmain_cleanup();
|
||||
_IsConnected = false;
|
||||
}
|
||||
return !_IsConnected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the specified Command on the Active Connection
|
||||
/// </summary>
|
||||
/// <param name="Command">a Command including optional parameters like "dir *.*" that can be understood by psftp</param>
|
||||
/// <returns>true, if command run successfully, falser otherwise</returns>
|
||||
public bool CmdExec_Any(string Command)
|
||||
{
|
||||
// Perform the Action
|
||||
if (_IsConnected)
|
||||
{
|
||||
bool bPerformedAction = (do_sftp2(Command) == 1);
|
||||
return bPerformedAction;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Command Helpers (Assumes Active Connection)
|
||||
|
||||
/// <summary>
|
||||
/// Set the Working Directory Locally
|
||||
/// </summary>
|
||||
/// <param name="path">path to a local directory</param>
|
||||
/// <param name="bCreateIfNotExists">true to create the local directory, if it doesn't exist, false otherwise</param>
|
||||
/// <returns>true, if successful, false otherwise</returns>
|
||||
public bool CmdExec_LocalDirSet(string path, bool bCreateIfNotExists = false)
|
||||
{
|
||||
if (!_IsConnected)
|
||||
throw new Exception("Not Connected");
|
||||
if(String.IsNullOrEmpty(path))
|
||||
throw new ArgumentException("path can not be empty");
|
||||
|
||||
bool bSuccess = CmdExec_Any("lcd " + path);
|
||||
if (!bSuccess && bCreateIfNotExists)
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
if(Directory.Exists(path))
|
||||
bSuccess = CmdExec_Any("lcd " + path);
|
||||
}
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the Working Directory on the Remote sftp connection
|
||||
/// </summary>
|
||||
/// <param name="path">path to a remote directory</param>
|
||||
/// <returns>true, if successful, false otherwise</returns>
|
||||
public bool CmdExec_RemoteDirSet(string path)
|
||||
{
|
||||
if (!_IsConnected)
|
||||
throw new Exception("Not Connected");
|
||||
if (String.IsNullOrEmpty(path))
|
||||
throw new ArgumentException("path can not be empty");
|
||||
|
||||
// Always make paths absolute * safer *
|
||||
if (path[0] != '/' && path[0] != '\\')
|
||||
path = '/' + path;
|
||||
|
||||
bool bSuccess = CmdExec_Any("cd " + path);
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks for existence of the Directory on the Server
|
||||
/// </summary>
|
||||
/// <param name="path">path to a remote directory</param>
|
||||
/// <returns>true, if remote directory exists, false otherwise</returns>
|
||||
public bool CmdExec_RemoteDirExists(string path)
|
||||
{
|
||||
if (!_IsConnected)
|
||||
throw new Exception("Not Connected");
|
||||
if (String.IsNullOrEmpty(path))
|
||||
throw new ArgumentException("path can not be empty");
|
||||
|
||||
// Always make paths absolute * safer *
|
||||
if (path[0] != '/' && path[0] != '\\')
|
||||
path = '/' + path;
|
||||
|
||||
bool bSuccess = CmdExec_Any("cd /"); // make sure we are at the root dir
|
||||
if (bSuccess)
|
||||
bSuccess = CmdExec_Any("cd " + path);
|
||||
if (bSuccess)
|
||||
bSuccess = CmdExec_Any("cd /"); // back to root dir
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download a Directory at once including all it's files. if bRecursive is set,
|
||||
/// Download all child directories and files
|
||||
/// </summary>
|
||||
/// <param name="bRecursive">If bRecursive is true, recursively fetch files and directories</param>
|
||||
/// <param name="path">path to a remote directory</param>
|
||||
/// <returns>true, if successful, false otherwise</returns>
|
||||
public bool CmdExe_MGetDir(bool bRecursive, string path)
|
||||
{
|
||||
if (!_IsConnected)
|
||||
throw new Exception("Not Connected");
|
||||
if (String.IsNullOrEmpty(path))
|
||||
throw new ArgumentException("path can not be empty");
|
||||
|
||||
// Always make paths absolute * safer *
|
||||
if (path[0] != '/' && path[0] != '\\')
|
||||
path = '/' + path;
|
||||
|
||||
string mgetCmd = bRecursive ? "mget -r " : "mget ";
|
||||
bool bSuccess = CmdExec_Any(mgetCmd + path);
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Download multiple files at once
|
||||
/// <example>
|
||||
/// "*.c" "filename1.txt" "*.sln"
|
||||
/// </example>
|
||||
/// </summary>
|
||||
/// <param name="filenames_or_wildcards">space seperated list of multiple filenames or wildcards</param>
|
||||
/// <returns>true, if successful, false otherwise</returns>
|
||||
public bool CmdExe_MGetFiles(string filenames_or_wildcards)
|
||||
{
|
||||
if (!_IsConnected)
|
||||
throw new Exception("Not Connected");
|
||||
if (String.IsNullOrEmpty(filenames_or_wildcards))
|
||||
throw new ArgumentException("filenames_or_wildcards can not be empty");
|
||||
|
||||
bool bSuccess = CmdExec_Any("mget " + filenames_or_wildcards);
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upload a Directory at once including all it's files. if bRecursive is set,
|
||||
/// Upload all child directories and files
|
||||
/// </summary>
|
||||
/// <param name="bRecursive">If bRecursive is true, recursively put files and directories</param>
|
||||
/// <param name="path">path to a local directory</param>
|
||||
/// <returns>true, if successful, false otherwise</returns>
|
||||
public bool CmdExe_MPutDir(bool bRecursive, string path)
|
||||
{
|
||||
if (!_IsConnected)
|
||||
throw new Exception("Not Connected");
|
||||
if (String.IsNullOrEmpty(path))
|
||||
throw new ArgumentException("path can not be empty");
|
||||
|
||||
string mgetCmd = bRecursive ? "mput -r " : "mget ";
|
||||
bool bSuccess = CmdExec_Any(mgetCmd + path);
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upload multiple files at once
|
||||
/// <example>
|
||||
/// "*.c" "filename1.txt" "*.sln"
|
||||
/// </example>
|
||||
/// </summary>
|
||||
/// <param name="filenames_or_wildcards">space seperated list of multiple filenames or wildcards</param>
|
||||
/// <returns>true, if successful, false otherwise</returns>
|
||||
public bool CmdExe_MPutFiles(string filenames_or_wildcards)
|
||||
{
|
||||
if (!_IsConnected)
|
||||
throw new Exception("Not Connected");
|
||||
if (String.IsNullOrEmpty(filenames_or_wildcards))
|
||||
throw new ArgumentException("filenames_or_wildcards can not be empty");
|
||||
|
||||
bool bSuccess = CmdExec_Any("mput " + filenames_or_wildcards);
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete multiple files at once from the server
|
||||
/// <example>
|
||||
/// "*.c" "filename1.txt" "*.sln"
|
||||
/// </example>
|
||||
/// </summary>
|
||||
/// <param name="filenames_or_wildcards">space seperated list of multiple filenames or wildcards</param>
|
||||
/// <returns>true, if successful, false otherwise</returns>
|
||||
public bool CmdExe_MDelFiles(string filenames_or_wildcards)
|
||||
{
|
||||
if (!_IsConnected)
|
||||
throw new Exception("Not Connected");
|
||||
if (String.IsNullOrEmpty(filenames_or_wildcards))
|
||||
throw new ArgumentException("filenames_or_wildcards can not be empty");
|
||||
|
||||
bool bSuccess = CmdExec_Any("del " + filenames_or_wildcards);
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a Directory from the server. Directory must be empty in order
|
||||
/// to be removed.
|
||||
/// </summary>
|
||||
/// <param name="path">path to a remote directory</param>
|
||||
/// <returns>true, if successful, false otherwise</returns>
|
||||
public bool CmdExe_MDelDir(string path)
|
||||
{
|
||||
if (!_IsConnected)
|
||||
throw new Exception("Not Connected");
|
||||
if (String.IsNullOrEmpty(path))
|
||||
throw new ArgumentException("path can not be empty");
|
||||
|
||||
// Always make paths absolute * safer *
|
||||
if (path[0] != '/' && path[0] != '\\')
|
||||
path = '/' + path;
|
||||
|
||||
bool bSuccess = CmdExec_Any("" + path);
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
||||
// Use SupressFinalize in case a subclass
|
||||
// of this type implements a finalizer
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Free Managed Resources
|
||||
}
|
||||
|
||||
// Free Unmanaged Resources
|
||||
Disconnect();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user