All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sshtools.scp.ScpClientIO Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2003-2016 SSHTOOLS Limited. All Rights Reserved.
 *
 * For product documentation visit https://www.sshtools.com/
 *
 * This file is part of J2SSH Maverick.
 *
 * J2SSH Maverick is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * J2SSH Maverick is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with J2SSH Maverick.  If not, see .
 */
package com.sshtools.scp;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import com.sshtools.sftp.FileTransferProgress;
import com.sshtools.ssh.ChannelOpenException;
import com.sshtools.ssh.SshClient;
import com.sshtools.ssh.SshException;
import com.sshtools.ssh.SshIOException;
import com.sshtools.ssh.SshSession;

/**
 * 

* Implements the IO of a Secure Copy (SCP) client. This has no dependencies * upon Files. *

* * @author Lee David Painter */ public class ScpClientIO { protected SshClient ssh; boolean first = true; /** *

* Creates an SCP client. *

* * @param ssh * a connected SshClient */ public ScpClientIO(SshClient ssh) { this.ssh = ssh; } /** *

* Uploads a java.io.InputStream to a remote server as a file. * You must supply the correct number of bytes that will be * written. *

* * @param in * stream providing file * @param length * number of bytes that will be written * @param localFile * local file name * @param remoteFile * remote file name * * @throws IOException * on any error */ public void put(InputStream in, long length, String localFile, String remoteFile) throws SshException, ChannelOpenException { put(in, length, localFile, remoteFile, null); } /** *

* Uploads a java.io.InputStream to a remote server as a file. * You must supply the correct number of bytes that will be * written. *

* * @param in * stream providing file * @param length * number of bytes that will be written * @param localFile * local file name * @param remoteFile * remote file name * @param progress * a file transfer progress implementation * * @throws IOException * on any error */ public void put(InputStream in, long length, String localFile, String remoteFile, FileTransferProgress progress) throws SshException, ChannelOpenException { ScpEngineIO scp = new ScpEngineIO("scp -t " /* + (verbose ? "-v " : "") */ + remoteFile, ssh.openSessionChannel()); try { scp.waitForResponse(); if (progress != null) { progress.started(length, remoteFile); } scp.writeStreamToRemote(in, length, localFile, progress); if (progress != null) progress.completed(); scp.close(); } catch (IOException ex) { scp.close(); throw new SshException(ex, SshException.CHANNEL_FAILURE); } } /** *

* Gets a remote file as a java.io.InputStream. *

* * @param remoteFile * remote file name * @return ScpInputStream * * @throws IOException * on any error */ public InputStream get(String remoteFile) throws SshException, ChannelOpenException { return get(remoteFile, null); } /** *

* Gets a remote file as a java.io.InputStream. *

* * @param remoteFile * remote file name * @param progress * a file transfer progress implementation. * @return ScpInputStream * * @throws IOException * on any error */ public InputStream get(String remoteFile, FileTransferProgress progress) throws SshException, ChannelOpenException { ScpEngineIO scp = new ScpEngineIO("scp " + "-f " /* + (verbose ? "-v " : "") */ + remoteFile, ssh.openSessionChannel()); try { return scp.readStreamFromRemote(remoteFile, progress); } catch (IOException ex) { scp.close(); throw new SshException(ex, SshException.CHANNEL_FAILURE); } } /** *

* Implements an SCP engine. *

*/ public class ScpEngineIO { protected byte[] buffer = new byte[16384]; protected String cmd; protected SshSession session; protected OutputStream out; protected InputStream in; /** *

* Contruct the channel with the specified scp command. *

* * @param cmd * the scp command * @param session * the session to scp over */ protected ScpEngineIO(String cmd, SshSession session) throws SshException { try { this.session = session; this.cmd = cmd; this.in = session.getInputStream(); this.out = session.getOutputStream(); if (!session.executeCommand(cmd)) { session.close(); throw new SshException("Failed to execute the command " + cmd, SshException.CHANNEL_FAILURE); } } catch (SshIOException ex) { throw ex.getRealException(); } } /** * Close the SCP engine and underlying session. * * @throws SshException */ public void close() throws SshException { try { session.getOutputStream().close(); } catch (IOException ex) { throw new SshException(ex); } // This helps some Cisco routers operate correctly.. otherwise they // moan about disconnection errors!! try { Thread.sleep(500); } catch (Throwable t) { } session.close(); } /** *

* Write a stream as a file to the remote server. You * must supply the correct number of bytes that will be * written. *

* * @param in * stream * @param length * number of bytes to write * @param localName * local file name * * @throws IOException * if an IO error occurs */ protected void writeStreamToRemote(InputStream in, long length, String localName, FileTransferProgress progress) throws IOException { String cmd = "C0644 " + length + " " + localName + "\n"; out.write(cmd.getBytes()); waitForResponse(); writeCompleteFile(in, length, progress); writeOk(); waitForResponse(); } /** * Open an InputStream. * * @param remoteFile * @param progress * @return ScpInputStream * @throws IOException */ protected InputStream readStreamFromRemote(String remoteFile, FileTransferProgress progress) throws IOException { String cmd; String[] cmdParts = new String[3]; writeOk(); while (true) { try { cmd = readString(); } catch (EOFException e) { return null; } catch (SshIOException e2) { return null; } char cmdChar = cmd.charAt(0); switch (cmdChar) { case 'E': writeOk(); return null; case 'T': continue; case 'D': throw new IOException( "Directories cannot be copied to a stream"); case 'C': parseCommand(cmd, cmdParts); long len = Long.parseLong(cmdParts[1]); writeOk(); if (progress != null) { progress.started(len, remoteFile); } return new ScpInputStream(len, in, this, progress, remoteFile) /* * , 16 * 1024) */ ; default: writeError("Unexpected cmd: " + cmd); throw new IOException("SCP unexpected cmd: " + cmd); } } } /** * Parse an SCP command * * @param cmd * @param cmdParts * @throws IOException */ protected void parseCommand(String cmd, String[] cmdParts) throws IOException { int l; int r; l = cmd.indexOf(' '); r = cmd.indexOf(' ', l + 1); // a command must have the following format // "commandtype source dest", and therefore must have 2 spaces if ((l == -1) || (r == -1)) { writeError("Syntax error in cmd"); throw new IOException("Syntax error in cmd"); } // extract command cmdParts[0] = cmd.substring(1, l); // extract source cmdParts[1] = cmd.substring(l + 1, r); // extract destination cmdParts[2] = cmd.substring(r + 1); } /** * read the inputstream until come to an end of line character '\n', and * return the bytes read as a string * * @return String * @throws IOException */ protected String readString() throws IOException { int ch; int i = 0; while (((ch = in.read()) != ('\n')) && (ch >= 0)) { buffer[i++] = (byte) ch; } if (ch == -1) { throw new EOFException("Unexpected EOF"); } if (buffer[0] == (byte) '\n') { throw new IOException("Unexpected "); } // skip first character if it equals '\02' or '\01' if ((buffer[0] == (byte) '\02') || (buffer[0] == (byte) '\01')) { String msg = new String(buffer, 1, i - 1); if (buffer[0] == (byte) '\02') { throw new IOException(msg); } throw new IOException("SCP returned an unexpected error: " + msg); } return new String(buffer, 0, i); } public void waitForResponse() throws IOException { int r = in.read(); if (first) { while (r > 0 && r != (byte) '\02') { r = in.read(); } first = false; } if (r == 0) { // All is well, no error return; } if (r == -1) { throw new EOFException("SCP returned unexpected EOF"); } String msg = readString(); if (r == (byte) '\02') { throw new IOException(msg); } throw new IOException("SCP returned an unexpected error: " + msg); } protected void writeOk() throws IOException { out.write(0); } protected void writeError(String reason) throws IOException { out.write(1); out.write(reason.getBytes()); } protected void writeCompleteFile(InputStream in, long size, FileTransferProgress progress) throws IOException { long count = 0; int read; try { // write in blocks of buffer.length size while (count < size) { read = in .read(buffer, 0, (int) (((size - count) < buffer.length) ? (size - count) : buffer.length)); if (read == -1) { throw new EOFException("SCP received an unexpected EOF"); } count += read; out.write(buffer, 0, read); if (progress != null) { if (progress.isCancelled()) throw new SshIOException(new SshException( "SCP transfer was cancelled by user", SshException.SCP_TRANSFER_CANCELLED)); progress.progressed(count); } } } finally { in.close(); } } protected void readCompleteFile(OutputStream out, long size, FileTransferProgress progress) throws IOException { long count = 0; int read; try { // read in blocks of buffer.length size while (count < size) { read = in .read(buffer, 0, (int) (((size - count) < buffer.length) ? (size - count) : buffer.length)); if (read == -1) { throw new EOFException("SCP received an unexpected EOF"); } count += read; out.write(buffer, 0, read); if (progress != null) { if (progress.isCancelled()) throw new SshIOException(new SshException( "SCP transfer was cancelled by user", SshException.SCP_TRANSFER_CANCELLED)); progress.progressed(count); } } } finally { out.close(); } } } static class ScpInputStream extends InputStream { long length; InputStream in; long count; ScpEngineIO engine; FileTransferProgress progress; String remoteFile; ScpInputStream(long length, InputStream in, ScpEngineIO engine, FileTransferProgress progress, String remoteFile) { this.length = length; this.in = in; this.engine = engine; this.progress = progress; this.remoteFile = remoteFile; } public int read() throws IOException { if (count == length) { return -1; } if (count >= length) { throw new EOFException("End of file."); } int r = in.read(); if (r == -1) { throw new EOFException("Unexpected EOF."); } count++; if (count == length) { engine.waitForResponse(); engine.writeOk(); if (progress != null) progress.completed(); } if (progress != null) { if (progress.isCancelled()) throw new SshIOException(new SshException( "SCP transfer was cancelled by user", SshException.SCP_TRANSFER_CANCELLED)); progress.progressed(count); } return r; } public int available() throws IOException { if (count == length) return -1; return (int) (length - count); } public long getFileSize() { return length; } public int read(byte[] buf, int off, int len) throws IOException { if (count >= length) { return -1; } int r = in.read(buf, off, (int) (length - count > len ? len : length - count)); if (r == -1) { throw new EOFException("Unexpected EOF."); } count += r; if (count >= length) { engine.waitForResponse(); engine.writeOk(); if (progress != null) progress.completed(); } if (progress != null) { if (progress.isCancelled()) throw new SshIOException(new SshException( "SCP transfer was cancelled by user", SshException.SCP_TRANSFER_CANCELLED)); progress.progressed(count); } return r; } public void close() throws IOException { try { engine.close(); } catch (SshException ex) { throw new SshIOException(ex); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy