package com.cattles.util.ssh.jsch; import com.cattles.util.ssh.SSHException; import com.cattles.util.ssh.SSHMonitor; import com.cattles.util.ssh.SSHResult; import com.jcraft.jsch.Channel; import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; import java.io.*; import java.util.List; import static com.cattles.util.ssh.SCPUtil.*; import static com.cattles.util.ssh.SSHResult.makeFailedResult; public class JschSCPFrom implements JschSCPExecutable { public SSHResult execSCP(Session sshSession, String origin, String dest, String option, List<SSHMonitor> monitors) { SSHResult result = new SSHResult("SCP " + option + " " + origin + " " + dest); Channel channel = null; try { String command = "scp -f -r " + option + parseRemoteURL(origin); channel = sshSession.openChannel("exec"); ((ChannelExec) channel).setCommand(command); OutputStream out = channel.getOutputStream(); InputStream in = channel.getInputStream(); channel.connect(); sendAck(out); result.append("Beginning transfer " + origin + "\n"); startRemoteCopy(dest, in, out, result, monitors); result.setSuccess(true); result.append("Transfer complete!\n"); } catch (SSHException e) { makeFailedResult(result, e, "SCP error! probably is remote server response error!\n"); } catch (JSchException e) { makeFailedResult(result, e, "SCP error!\n"); } catch (IOException e) { makeFailedResult(result, e, "SCP error! probably is IO error!\n"); } finally { if (channel != null) { channel.disconnect(); } } return result; } private void startRemoteCopy(String dest, InputStream in, OutputStream out , SSHResult result, List<SSHMonitor> monitors) throws IOException, SSHException { File curFile = new File(dest); while (true) { // C0644 filesize filename - header for a regular file // T time 0 time 0\n - present if perserve time. // D directory - this is the header for a directory. ByteArrayOutputStream stream = new ByteArrayOutputStream(); while (true) { int read = in.read(); if (read < 0) { // throw new SSHException("No response from server!"); return; } if ((byte) read == LINE_FEED) { break; } stream.write(read); } String serverResponse = stream.toString("UTF-8"); char serResp = serverResponse.charAt(0); if (serResp == 'C') { //Transfer file parseAndFetch(serverResponse, curFile, in, out, result, monitors); } else if (serResp == 'D') { //Create directory curFile = parseAndTransDirectory(serverResponse, curFile, result, monitors); sendAck(out); } else if (serResp == 'E') { //End of current direction transferring curFile = curFile.getParentFile(); sendAck(out); } else if (serResp == '\01' || serResp == '\02') { throw new SSHException("Server indicated an error,error code: " + serResp + ",message: " + serverResponse.substring(1)); } } } private File parseAndTransDirectory(String serverResponse, File localFile, SSHResult result, List<SSHMonitor> monitors) throws SSHException, IOException { int start = serverResponse.indexOf(" "); start = serverResponse.indexOf(" ", start + 1); String dirName = serverResponse.substring(start + 1); if (!localFile.isDirectory()) throw new SSHException(localFile.getCanonicalFile() + " is not directory!can't create directory in it!"); File dir = new File(localFile, dirName); dir.mkdir(); String msg = dir.getCanonicalPath() + " is created!\n"; result.append(msg); if (!monitors.isEmpty()) { for (SSHMonitor mon : monitors) { mon.info(msg); } } return dir; } private void parseAndFetch(String serverResponse, File localFile, InputStream in, OutputStream out , SSHResult result, List<SSHMonitor> monitors) throws IOException, SSHException { int end = serverResponse.indexOf(" "); int start = end + 1; end = serverResponse.indexOf(" ", start); long filesize = Long.parseLong(serverResponse.substring(start, end)); String filename = serverResponse.substring(end + 1); File transFile = (localFile.isDirectory()) ? new File(localFile, filename) : localFile; transferFileFromRemote(transFile, filesize, in, out, result, monitors); waitForAck(in); sendAck(out); } private void transferFileFromRemote(File localFile, long fileSize, InputStream in, OutputStream out, SSHResult result, List<SSHMonitor> monitors) throws IOException { byte[] buf = new byte[BUF_SIZE]; sendAck(out); // read a content of lfile FileOutputStream fos = new FileOutputStream(localFile); int length; long transferred = 0; long initFilesize = fileSize; try { while (true) { length = in.read(buf, 0, (BUF_SIZE < fileSize) ? BUF_SIZE : (int) fileSize); if (length < 0) { throw new EOFException("Unexpected end of stream."); } fos.write(buf, 0, length); fileSize -= length; transferred += length; if (fileSize == 0) { break; } if (!monitors.isEmpty() && fileSize > REST_SIZE) { for (SSHMonitor monitor : monitors) { monitor.info(localFile.getCanonicalPath() + " is transferring, progress is " + trackProgress(initFilesize, transferred)); } } if (fileSize > REST_SIZE) { try { Thread.sleep(100); } catch (Exception ee) { } ; } } } finally { fos.flush(); fos.close(); } result.append(localFile.getCanonicalPath() + " transferred successful!\n"); } }