Mercurial > 510Connectbot
diff src/ch/ethz/ssh2/SCPClient.java @ 273:91a31873c42a ganymed
start conversion from trilead to ganymed
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Fri, 18 Jul 2014 11:21:46 -0700 |
parents | |
children | 9ae4ed7bb523 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ch/ethz/ssh2/SCPClient.java Fri Jul 18 11:21:46 2014 -0700 @@ -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 <code>SCPClient</code> 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. + * <p/> + * This scp client is thread safe - you can download (and upload) different sets + * of files concurrently without any troubles. The <code>SCPClient</code> is + * actually mapping every request to a distinct {@link ch.ethz.ssh2.Session}. + * + * @author Christian Plattner, plattner@inf.ethz.ch + * @version $Id: SCPClient.java 85 2014-04-07 14:05:09Z 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 <code>null</code> 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 new IOException("This charset is not supported", e); + } + charsetName = charset; + } + + /** + * The currently used charset for filename encoding/decoding. + * + * @return The name of the charset (<code>null</code> 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