From f68742b25f19026c1fa63be32df0c2c3ca92b4ab Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Tue, 10 Jan 2012 14:24:22 -0800 Subject: ganymed-ssh2-build251beta1 Change-Id: I20dff4875333580185596fbef32a7edf4718017a Signed-off-by: Mike Lockwood --- src/main/java/ch/ethz/ssh2/SCPClient.java | 232 ++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 src/main/java/ch/ethz/ssh2/SCPClient.java (limited to 'src/main/java/ch/ethz/ssh2/SCPClient.java') diff --git a/src/main/java/ch/ethz/ssh2/SCPClient.java b/src/main/java/ch/ethz/ssh2/SCPClient.java new file mode 100644 index 0000000..e1a1bdb --- /dev/null +++ b/src/main/java/ch/ethz/ssh2/SCPClient.java @@ -0,0 +1,232 @@ +package ch.ethz.ssh2; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; + +/** + * A very basic SCPClient that can be used to copy files from/to + * the SSH-2 server. On the server side, the "scp" program must be in the PATH. + *

+ * This scp client is thread safe - you can download (and upload) different sets + * of files concurrently without any troubles. The SCPClient is + * actually mapping every request to a distinct {@link ch.ethz.ssh2.Session}. + * + * @author Christian Plattner, plattner@inf.ethz.ch + * @version $Id: SCPClient.java 32 2011-05-28 21:56:21Z dkocher@sudo.ch $ + */ + +public class SCPClient +{ + Connection conn; + + String charsetName = null; + + /** + * Set the charset used to convert between Java Unicode Strings and byte encodings + * used by the server for paths and file names. + * + * @param charset the name of the charset to be used or null to use the platform's + * default encoding. + * @throws IOException + * @see #getCharset() + */ + public void setCharset(String charset) throws IOException + { + if (charset == null) + { + charsetName = charset; + return; + } + + try + { + Charset.forName(charset); + } + catch (UnsupportedCharsetException e) + { + throw (IOException) new IOException("This charset is not supported").initCause(e); + } + charsetName = charset; + } + + /** + * The currently used charset for filename encoding/decoding. + * + * @return The name of the charset (null if the platform's default charset is being used) + * @see #setCharset(String) + */ + public String getCharset() + { + return charsetName; + } + + public class LenNamePair + { + public long length; + String filename; + } + + public SCPClient(Connection conn) + { + if (conn == null) + throw new IllegalArgumentException("Cannot accept null argument!"); + this.conn = conn; + } + + protected void readResponse(InputStream is) throws IOException + { + int c = is.read(); + + if (c == 0) + return; + + if (c == -1) + throw new IOException("Remote scp terminated unexpectedly."); + + if ((c != 1) && (c != 2)) + throw new IOException("Remote scp sent illegal error code."); + + if (c == 2) + throw new IOException("Remote scp terminated with error."); + + String err = receiveLine(is); + throw new IOException("Remote scp terminated with error (" + err + ")."); + } + + protected String receiveLine(InputStream is) throws IOException + { + StringBuilder sb = new StringBuilder(30); + + while (true) + { + /* This is a random limit - if your path names are longer, then adjust it */ + + if (sb.length() > 8192) + throw new IOException("Remote scp sent a too long line"); + + int c = is.read(); + + if (c < 0) + throw new IOException("Remote scp terminated unexpectedly."); + + if (c == '\n') + break; + + sb.append((char) c); + + } + return sb.toString(); + } + + protected LenNamePair parseCLine(String line) throws IOException + { + /* Minimum line: "xxxx y z" ---> 8 chars */ + + if (line.length() < 8) + throw new IOException("Malformed C line sent by remote SCP binary, line too short."); + + if ((line.charAt(4) != ' ') || (line.charAt(5) == ' ')) + throw new IOException("Malformed C line sent by remote SCP binary."); + + int length_name_sep = line.indexOf(' ', 5); + + if (length_name_sep == -1) + throw new IOException("Malformed C line sent by remote SCP binary."); + + String length_substring = line.substring(5, length_name_sep); + String name_substring = line.substring(length_name_sep + 1); + + if ((length_substring.length() <= 0) || (name_substring.length() <= 0)) + throw new IOException("Malformed C line sent by remote SCP binary."); + + if ((6 + length_substring.length() + name_substring.length()) != line.length()) + throw new IOException("Malformed C line sent by remote SCP binary."); + + final long len; + try + { + len = Long.parseLong(length_substring); + } + catch (NumberFormatException e) + { + throw new IOException("Malformed C line sent by remote SCP binary, cannot parse file length."); + } + + if (len < 0) + throw new IOException("Malformed C line sent by remote SCP binary, illegal file length."); + + LenNamePair lnp = new LenNamePair(); + lnp.length = len; + lnp.filename = name_substring; + + return lnp; + } + + /** + * The session for opened for this SCP transfer must be closed using + * SCPOutputStream#close + * + * @param remoteFile + * @param length The size of the file to send + * @param remoteTargetDirectory + * @param mode + * @return + * @throws IOException + */ + public SCPOutputStream put(final String remoteFile, long length, String remoteTargetDirectory, String mode) + throws IOException + { + Session sess = null; + + if (null == remoteFile) + throw new IllegalArgumentException("Null argument."); + if (null == remoteTargetDirectory) + remoteTargetDirectory = ""; + if (null == mode) + mode = "0600"; + if (mode.length() != 4) + throw new IllegalArgumentException("Invalid mode."); + + for (int i = 0; i < mode.length(); i++) + if (Character.isDigit(mode.charAt(i)) == false) + throw new IllegalArgumentException("Invalid mode."); + + remoteTargetDirectory = (remoteTargetDirectory.length() > 0) ? remoteTargetDirectory : "."; + + String cmd = "scp -t -d \"" + remoteTargetDirectory + "\""; + + sess = conn.openSession(); + sess.execCommand(cmd, charsetName); + + return new SCPOutputStream(this, sess, remoteFile, length, mode); + } + + /** + * The session for opened for this SCP transfer must be closed using + * SCPInputStream#close + * + * @param remoteFile + * @return + * @throws IOException + */ + public SCPInputStream get(final String remoteFile) throws IOException + { + Session sess = null; + + if (null == remoteFile) + throw new IllegalArgumentException("Null argument."); + + if (remoteFile.length() == 0) + throw new IllegalArgumentException("Cannot accept empty filename."); + + String cmd = "scp -f"; + cmd += (" \"" + remoteFile + "\""); + + sess = conn.openSession(); + sess.execCommand(cmd, charsetName); + + return new SCPInputStream(this, sess); + } +} \ No newline at end of file -- cgit v1.2.3