aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java311
1 files changed, 311 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java
new file mode 100644
index 00000000..b6d47379
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/ssh/ScpFromMessage.java
@@ -0,0 +1,311 @@
+/*
+ * 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
+ *
+ * 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 org.apache.tools.ant.taskdefs.optional.ssh;
+
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.tools.ant.util.FileUtils;
+
+import com.jcraft.jsch.Channel;
+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;
+
+/**
+ * A helper object representing an scp download.
+ */
+public class ScpFromMessage extends AbstractSshMessage {
+
+ private static final int HUNDRED_KILOBYTES = 102400;
+ private static final byte LINE_FEED = 0x0a;
+ private static final int BUFFER_SIZE = 100*1024;
+
+ private String remoteFile;
+ private File localFile;
+ private boolean isRecursive = false;
+ private boolean preserveLastModified = false;
+
+ /**
+ * Constructor for ScpFromMessage
+ * @param session the ssh session to use
+ */
+ public ScpFromMessage(final Session session) {
+ super(session);
+ }
+
+ /**
+ * Constructor for ScpFromMessage
+ * @param verbose if true do verbose logging
+ * @param session the ssh session to use
+ * @since Ant 1.7
+ */
+ public ScpFromMessage(final boolean verbose, final Session session) {
+ super(verbose, session);
+ }
+
+ /**
+ * Constructor for ScpFromMessage.
+ * @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 (-r option to scp)
+ * @since Ant 1.6.2
+ */
+ public ScpFromMessage(final boolean verbose,
+ final Session session,
+ final String aRemoteFile,
+ final File aLocalFile,
+ final boolean recursive) {
+ this(false, session, aRemoteFile, aLocalFile, recursive, false);
+ }
+
+ /**
+ * Constructor for ScpFromMessage.
+ * @param session the Scp session to use
+ * @param aRemoteFile the remote file name
+ * @param aLocalFile the local file
+ * @param recursive if true use recursion (-r option to scp)
+ */
+ public ScpFromMessage(final Session session,
+ final String aRemoteFile,
+ final File aLocalFile,
+ final boolean recursive) {
+ this(false, session, aRemoteFile, aLocalFile, recursive);
+ }
+
+ /**
+ * Constructor for ScpFromMessage.
+ * @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 (-r option to scp)
+ * @param preserveLastModified whether to preserve file
+ * modification times
+ * @since Ant 1.8.0
+ */
+ public ScpFromMessage(final boolean verbose,
+ final Session session,
+ final String aRemoteFile,
+ final File aLocalFile,
+ final boolean recursive,
+ final boolean preserveLastModified) {
+ super(verbose, session);
+ this.remoteFile = aRemoteFile;
+ this.localFile = aLocalFile;
+ this.isRecursive = recursive;
+ this.preserveLastModified = preserveLastModified;
+ }
+
+ /**
+ * Carry out the transfer.
+ * @throws IOException on i/o errors
+ * @throws JSchException on errors detected by scp
+ */
+ public void execute() throws IOException, JSchException {
+ String command = "scp -f ";
+ if (isRecursive) {
+ command += "-r ";
+ }
+ command += remoteFile;
+ final Channel channel = openExecChannel(command);
+ try {
+ // get I/O streams for remote scp
+ final OutputStream out = channel.getOutputStream();
+ final InputStream in = channel.getInputStream();
+
+ channel.connect();
+
+ sendAck(out);
+ startRemoteCpProtocol(in, out, localFile);
+ } finally {
+ if (channel != null) {
+ channel.disconnect();
+ }
+ }
+ log("done\n");
+ }
+
+ protected boolean getPreserveLastModified() {
+ return preserveLastModified;
+ }
+
+ private void startRemoteCpProtocol(final InputStream in,
+ final OutputStream out,
+ final File localFile)
+ throws IOException, JSchException {
+ File startFile = localFile;
+ 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.
+ final ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ while (true) {
+ final int read = in.read();
+ if (read < 0) {
+ return;
+ }
+ if ((byte) read == LINE_FEED) {
+ break;
+ }
+ stream.write(read);
+ }
+ final String serverResponse = stream.toString("UTF-8");
+ if (serverResponse.charAt(0) == 'C') {
+ parseAndFetchFile(serverResponse, startFile, out, in);
+ } else if (serverResponse.charAt(0) == 'D') {
+ startFile = parseAndCreateDirectory(serverResponse,
+ startFile);
+ sendAck(out);
+ } else if (serverResponse.charAt(0) == 'E') {
+ startFile = startFile.getParentFile();
+ sendAck(out);
+ } else if (serverResponse.charAt(0) == '\01'
+ || serverResponse.charAt(0) == '\02') {
+ // this indicates an error.
+ throw new IOException(serverResponse.substring(1));
+ }
+ }
+ }
+
+ private File parseAndCreateDirectory(final String serverResponse,
+ final File localFile) {
+ int start = serverResponse.indexOf(" ");
+ // appears that the next token is not used and it's zero.
+ start = serverResponse.indexOf(" ", start + 1);
+ final String directoryName = serverResponse.substring(start + 1);
+ if (localFile.isDirectory()) {
+ final File dir = new File(localFile, directoryName);
+ dir.mkdir();
+ log("Creating: " + dir);
+ return dir;
+ }
+ return null;
+ }
+
+ private void parseAndFetchFile(final String serverResponse,
+ final File localFile,
+ final OutputStream out,
+ final InputStream in)
+ throws IOException, JSchException {
+ int start = 0;
+ int end = serverResponse.indexOf(" ", start + 1);
+ start = end + 1;
+ end = serverResponse.indexOf(" ", start + 1);
+ final long filesize = Long.parseLong(serverResponse.substring(start, end));
+ final String filename = serverResponse.substring(end + 1);
+ log("Receiving: " + filename + " : " + filesize);
+ final File transferFile = (localFile.isDirectory())
+ ? new File(localFile, filename)
+ : localFile;
+ fetchFile(transferFile, filesize, out, in);
+ waitForAck(in);
+ sendAck(out);
+ }
+
+ private void fetchFile(final File localFile,
+ long filesize,
+ final OutputStream out,
+ final InputStream in)
+ throws IOException, JSchException {
+ final byte[] buf = new byte[BUFFER_SIZE];
+ sendAck(out);
+
+ // read a content of lfile
+ final FileOutputStream fos = new FileOutputStream(localFile);
+ int length;
+ long totalLength = 0;
+ final long startTime = System.currentTimeMillis();
+
+ // only track progress for files larger than 100kb in verbose mode
+ final boolean trackProgress = getVerbose() && filesize > HUNDRED_KILOBYTES;
+ // since filesize keeps on decreasing we have to store the
+ // initial filesize
+ final long initFilesize = filesize;
+ int percentTransmitted = 0;
+
+ try {
+ while (true) {
+ length = in.read(buf, 0,
+ (BUFFER_SIZE < filesize) ? BUFFER_SIZE
+ : (int) filesize);
+ if (length < 0) {
+ throw new EOFException("Unexpected end of stream.");
+ }
+ fos.write(buf, 0, length);
+ filesize -= length;
+ totalLength += length;
+ if (filesize == 0) {
+ break;
+ }
+
+ if (trackProgress) {
+ percentTransmitted = trackProgress(initFilesize,
+ totalLength,
+ percentTransmitted);
+ }
+ }
+ } finally {
+ final long endTime = System.currentTimeMillis();
+ logStats(startTime, endTime, totalLength);
+ fos.flush();
+ fos.close();
+ }
+
+ if (getPreserveLastModified()) {
+ setLastModified(localFile);
+ }
+ }
+
+ private void setLastModified(final File localFile) throws JSchException {
+ SftpATTRS fileAttributes = null;
+ final ChannelSftp channel = openSftpChannel();
+ channel.connect();
+ try {
+ fileAttributes = channel.lstat(remoteDir(remoteFile)
+ + localFile.getName());
+ } catch (final SftpException e) {
+ throw new JSchException("failed to stat remote file", e);
+ }
+ FileUtils.getFileUtils().setFileLastModified(localFile,
+ ((long) fileAttributes
+ .getMTime())
+ * 1000);
+ }
+
+ /**
+ * returns the directory part of the remote file, if any.
+ */
+ private static String remoteDir(final String remoteFile) {
+ int index = remoteFile.lastIndexOf("/");
+ if (index < 0) {
+ index = remoteFile.lastIndexOf("\\");
+ }
+ return index > -1 ? remoteFile.substring(0, index + 1) : "";
+ }
+}