net.schmizz.sshj.xfer.scp.SCPDownloadClient Maven / Gradle / Ivy
/*
* Copyright (C)2009 - SSHJ Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.schmizz.sshj.xfer.scp;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.xfer.LocalDestFile;
import net.schmizz.sshj.xfer.TransferListener;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** Support for downloading files over a connected link using SCP. */
public class SCPDownloadClient extends AbstractSCPClient {
private boolean recursiveMode = true;
SCPDownloadClient(SCPEngine engine) {
super(engine);
}
SCPDownloadClient(SCPEngine engine, int bandwidthLimit) {
super(engine, bandwidthLimit);
}
/** Download a file from {@code sourcePath} on the connected host to {@code targetPath} locally. */
public synchronized int copy(String sourcePath, LocalDestFile targetFile) throws IOException {
return copy(sourcePath, targetFile, ScpCommandLine.EscapeMode.NoEscape);
}
public synchronized int copy(String sourcePath, LocalDestFile targetFile, ScpCommandLine.EscapeMode escapeMode)
throws IOException {
engine.cleanSlate();
try {
startCopy(sourcePath, targetFile, escapeMode);
} finally {
engine.exit();
}
return engine.getExitStatus();
}
public boolean getRecursiveMode() {
return recursiveMode;
}
public void setRecursiveMode(boolean recursive) {
this.recursiveMode = recursive;
}
private void startCopy(String sourcePath, LocalDestFile targetFile, ScpCommandLine.EscapeMode escapeMode)
throws IOException {
ScpCommandLine commandLine = ScpCommandLine.with(ScpCommandLine.Arg.SOURCE)
.and(ScpCommandLine.Arg.QUIET)
.and(ScpCommandLine.Arg.PRESERVE_TIMES)
.and(ScpCommandLine.Arg.RECURSIVE, recursiveMode)
.and(ScpCommandLine.Arg.LIMIT, String.valueOf(bandwidthLimit), (bandwidthLimit > 0));
commandLine.withPath(sourcePath, escapeMode);
engine.execSCPWith(commandLine);
engine.signal("Start status OK");
String msg = engine.readMessage();
do {
process(engine.getTransferListener(), null, msg, targetFile);
} while (!(msg = engine.readMessage()).isEmpty());
}
private long parseLong(String longString, String valType)
throws SCPException {
try {
return Long.parseLong(longString);
} catch (NumberFormatException nfe) {
throw new SCPException("Could not parse " + valType + " from `" + longString + "`", nfe);
}
}
/* e.g. "C0644" -> 0644; "D0755" -> 0755 */
private int parsePermissions(String cmd)
throws SCPException {
if (cmd.length() != 5) {
throw new SCPException("Could not parse permissions from `" + cmd + "`");
}
return Integer.parseInt(cmd.substring(1), 8);
}
private boolean process(TransferListener listener, String bufferedTMsg, String msg, LocalDestFile f)
throws IOException {
if (msg.length() < 1) {
throw new SCPException("Could not parse message `" + msg + "`");
}
switch (msg.charAt(0)) {
case 'T':
engine.signal("ACK: T");
process(listener, msg, engine.readMessage(), f);
break;
case 'C':
processFile(listener, msg, bufferedTMsg, f);
break;
case 'D':
processDirectory(listener, msg, bufferedTMsg, f);
break;
case 'E':
return true;
case (char) 1:
case (char) 2:
throw new SCPRemoteException("Remote SCP command returned error: " + msg.substring(1), msg.substring(1));
default:
final String err = "Unrecognized message: `" + msg + "`";
engine.sendMessage((char) 2 + err);
throw new SCPException(err);
}
return false;
}
private void processDirectory(TransferListener listener, String dMsg, String tMsg, LocalDestFile f)
throws IOException {
final List dMsgParts = tokenize(dMsg, 3, true); // D 0
final long length = parseLong(dMsgParts.get(1), "dir length");
final String dirname = dMsgParts.get(2);
if (length != 0) {
throw new IOException("Remote SCP command sent strange directory length: " + length);
}
final TransferListener dirListener = listener.directory(dirname);
{
f = f.getTargetDirectory(dirname);
engine.signal("ACK: D");
do {
} while (!process(dirListener, null, engine.readMessage(), f));
setAttributes(f, parsePermissions(dMsgParts.get(0)), tMsg);
engine.signal("ACK: E");
}
}
private void processFile(TransferListener listener, String cMsg, String tMsg, LocalDestFile f)
throws IOException {
final List cMsgParts = tokenize(cMsg, 3, true); // C
final long length = parseLong(cMsgParts.get(1), "length");
final String filename = cMsgParts.get(2);
{
f = f.getTargetFile(filename);
engine.signal("Remote can start transfer");
final OutputStream dest = f.getOutputStream();
try {
engine.transferFromRemote(listener.file(filename, length), dest, length);
} finally {
IOUtils.closeQuietly(dest);
}
engine.check("Remote agrees transfer done");
setAttributes(f, parsePermissions(cMsgParts.get(0)), tMsg);
engine.signal("Transfer done");
}
}
private void setAttributes(LocalDestFile f, int perms, String tMsg)
throws IOException {
f.setPermissions(perms);
if (tMsg != null) {
List tMsgParts = tokenize(tMsg, 4, false); // e.g. T 0 0
f.setLastModifiedTime(parseLong(tMsgParts.get(0).substring(1), "last modified time"));
f.setLastAccessedTime(parseLong(tMsgParts.get(2), "last access time"));
}
}
private static List tokenize(String msg, int totalParts, boolean consolidateTail)
throws IOException {
List parts = Arrays.asList(msg.split(" "));
if (parts.size() < totalParts || (!consolidateTail && parts.size() != totalParts)) {
throw new IOException("Could not parse message received from remote SCP: " + msg);
}
if (consolidateTail && totalParts < parts.size()) {
final StringBuilder sb = new StringBuilder(parts.get(totalParts - 1));
for (int i = totalParts; i < parts.size(); i++) {
sb.append(" ").append(parts.get(i));
}
parts = new ArrayList(parts.subList(0, totalParts - 1));
parts.add(sb.toString());
}
return parts;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy