blob: 0ad089963cead24daead18d7c4c5eea0dc451a90 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
*
* https://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 org.apache.tools.ant.taskdefs.optional.ssh;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.apache.tools.ant.util.FileUtils;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.SftpProgressMonitor;
/**
* A helper object representing an scp download.
*/
public class ScpFromMessageBySftp extends ScpFromMessage {
private static final int HUNDRED_KILOBYTES = 102400;
private String remoteFile;
private final File localFile;
@SuppressWarnings("unused")
private boolean isRecursive = false;
@SuppressWarnings("unused")
private boolean verbose = false;
/**
* Constructor for ScpFromMessageBySftp.
* @param verbose if true log extra information
* @param session the Scp session to use
* @param aRemoteFile the remote file name
* @param aLocalFile the local file
* @param recursive if true use recursion
* @since Ant 1.7
*/
public ScpFromMessageBySftp(final boolean verbose,
final Session session,
final String aRemoteFile,
final File aLocalFile,
final boolean recursive) {
this(verbose, session, aRemoteFile, aLocalFile, recursive, false);
}
/**
* Constructor for ScpFromMessageBySftp.
* @param session the Scp session to use
* @param aRemoteFile the remote file name
* @param aLocalFile the local file
* @param recursive if true use recursion
*/
public ScpFromMessageBySftp(final Session session,
final String aRemoteFile,
final File aLocalFile,
final boolean recursive) {
this(false, session, aRemoteFile, aLocalFile, recursive);
}
/**
* Constructor for ScpFromMessageBySftp.
* @param verbose if true log extra information
* @param session the Scp session to use
* @param aRemoteFile the remote file name
* @param aLocalFile the local file
* @param recursive if true use recursion
* @param preserveLastModified whether to preserve file
* modification times
* @since Ant 1.8.0
*/
public ScpFromMessageBySftp(final boolean verbose,
final Session session,
final String aRemoteFile,
final File aLocalFile,
final boolean recursive,
final boolean preserveLastModified) {
super(verbose, session, aRemoteFile, aLocalFile, recursive,
preserveLastModified);
this.verbose = verbose;
this.remoteFile = aRemoteFile;
this.localFile = aLocalFile;
this.isRecursive = recursive;
}
/**
* Carry out the transfer.
* @throws IOException on i/o errors
* @throws JSchException on errors detected by scp
*/
@Override
public void execute() throws IOException, JSchException {
final ChannelSftp channel = openSftpChannel();
try {
channel.connect();
try {
final SftpATTRS attrs = channel.stat(remoteFile);
if (attrs.isDir() && !remoteFile.endsWith("/")) {
remoteFile += "/";
}
} catch (final SftpException ee) {
// Ignored
}
getDir(channel, remoteFile, localFile);
} catch (final SftpException e) {
throw new JSchException("Could not get '" + remoteFile + "' to '"
+ localFile + "' - " + e.toString(), e);
} finally {
if (channel != null) {
channel.disconnect();
}
}
log("done\n");
}
private void getDir(final ChannelSftp channel,
final String remoteFile,
final File localFile) throws SftpException {
String pwd = remoteFile;
if (remoteFile.lastIndexOf('/') != -1) {
if (remoteFile.length() > 1) {
pwd = remoteFile.substring(0, remoteFile.lastIndexOf('/'));
}
}
channel.cd(pwd);
if (!localFile.exists()) {
localFile.mkdirs();
}
@SuppressWarnings("unchecked")
final List<ChannelSftp.LsEntry> files = channel.ls(remoteFile);
for (ChannelSftp.LsEntry le : files) {
final String name = le.getFilename();
if (le.getAttrs().isDir()) {
if (".".equals(name) || "..".equals(name)) {
continue;
}
getDir(channel,
channel.pwd() + "/" + name + "/",
new File(localFile, le.getFilename()));
} else {
getFile(channel, le, localFile);
}
}
channel.cd("..");
}
private void getFile(final ChannelSftp channel,
final ChannelSftp.LsEntry le,
File localFile) throws SftpException {
final String remoteFile = le.getFilename();
if (!localFile.exists()) {
final String path = localFile.getAbsolutePath();
final int i = path.lastIndexOf(File.pathSeparator);
if (i != -1) {
if (path.length() > File.pathSeparator.length()) {
new File(path.substring(0, i)).mkdirs();
}
}
}
if (localFile.isDirectory()) {
localFile = new File(localFile, remoteFile);
}
final long startTime = System.currentTimeMillis();
final long totalLength = le.getAttrs().getSize();
SftpProgressMonitor monitor = null;
final boolean trackProgress = getVerbose() && totalLength > HUNDRED_KILOBYTES;
if (trackProgress) {
monitor = getProgressMonitor();
}
try {
log("Receiving: " + remoteFile + " : " + le.getAttrs().getSize());
channel.get(remoteFile, localFile.getAbsolutePath(), monitor);
} finally {
final long endTime = System.currentTimeMillis();
logStats(startTime, endTime, (int) totalLength);
}
if (getPreserveLastModified()) {
FileUtils.getFileUtils().setFileLastModified(localFile,
((long) le.getAttrs().getMTime()) * 1000);
}
}
}