1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.optional.ssh;
  18. import com.jcraft.jsch.Channel;
  19. import com.jcraft.jsch.Session;
  20. import com.jcraft.jsch.JSchException;
  21. import java.io.File;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.io.FileInputStream;
  25. import java.io.OutputStream;
  26. import java.util.List;
  27. import java.util.Iterator;
  28. public class ScpToMessage extends AbstractSshMessage {
  29. private final int BUFFER_SIZE = 1024;
  30. private File localFile;
  31. private String remotePath;
  32. private List directoryList;
  33. /**
  34. * @since Ant 1.6.2
  35. */
  36. public ScpToMessage(boolean verbose,
  37. Session session,
  38. File aLocalFile,
  39. String aRemotePath) {
  40. this(verbose, session, aRemotePath);
  41. this.localFile = aLocalFile;
  42. }
  43. /**
  44. * @since Ant 1.6.2
  45. */
  46. public ScpToMessage(boolean verbose,
  47. Session session,
  48. List aDirectoryList,
  49. String aRemotePath) {
  50. this(verbose, session, aRemotePath);
  51. this.directoryList = aDirectoryList;
  52. }
  53. /**
  54. * @since Ant 1.6.2
  55. */
  56. private ScpToMessage(boolean verbose,
  57. Session session,
  58. String aRemotePath) {
  59. super(verbose, session);
  60. this.remotePath = aRemotePath;
  61. }
  62. public ScpToMessage(Session session,
  63. File aLocalFile,
  64. String aRemotePath) {
  65. this(false, session, aLocalFile, aRemotePath);
  66. }
  67. public ScpToMessage(Session session,
  68. List aDirectoryList,
  69. String aRemotePath) {
  70. this(false, session, aDirectoryList, aRemotePath);
  71. }
  72. public void execute() throws IOException, JSchException {
  73. if (directoryList != null) {
  74. doMultipleTransfer();
  75. }
  76. if (localFile != null) {
  77. doSingleTransfer();
  78. }
  79. log("done.\n");
  80. }
  81. private void doSingleTransfer() throws IOException, JSchException {
  82. String cmd = "scp -t " + remotePath;
  83. Channel channel = openExecChannel(cmd);
  84. try {
  85. OutputStream out = channel.getOutputStream();
  86. InputStream in = channel.getInputStream();
  87. channel.connect();
  88. waitForAck(in);
  89. sendFileToRemote(localFile, in, out);
  90. } finally {
  91. if (channel != null) {
  92. channel.disconnect();
  93. }
  94. }
  95. }
  96. private void doMultipleTransfer() throws IOException, JSchException {
  97. Channel channel = openExecChannel("scp -d -t " + remotePath);
  98. try {
  99. OutputStream out = channel.getOutputStream();
  100. InputStream in = channel.getInputStream();
  101. channel.connect();
  102. waitForAck(in);
  103. for (Iterator i = directoryList.iterator(); i.hasNext();) {
  104. Directory current = (Directory) i.next();
  105. sendDirectory(current, in, out);
  106. }
  107. } finally {
  108. if (channel != null) {
  109. channel.disconnect();
  110. }
  111. }
  112. }
  113. private void sendDirectory(Directory current,
  114. InputStream in,
  115. OutputStream out) throws IOException {
  116. for (Iterator fileIt = current.filesIterator(); fileIt.hasNext();) {
  117. sendFileToRemote((File) fileIt.next(), in, out);
  118. }
  119. for (Iterator dirIt = current.directoryIterator(); dirIt.hasNext();) {
  120. Directory dir = (Directory) dirIt.next();
  121. sendDirectoryToRemote(dir, in, out);
  122. }
  123. }
  124. private void sendDirectoryToRemote(Directory directory,
  125. InputStream in,
  126. OutputStream out) throws IOException {
  127. String command = "D0755 0 ";
  128. command += directory.getDirectory().getName();
  129. command += "\n";
  130. out.write(command.getBytes());
  131. out.flush();
  132. waitForAck(in);
  133. sendDirectory(directory, in, out);
  134. out.write("E\n".getBytes());
  135. waitForAck(in);
  136. }
  137. private void sendFileToRemote(File localFile,
  138. InputStream in,
  139. OutputStream out) throws IOException {
  140. // send "C0644 filesize filename", where filename should not include '/'
  141. int filesize = (int) localFile.length();
  142. String command = "C0644 " + filesize + " ";
  143. command += localFile.getName();
  144. command += "\n";
  145. out.write(command.getBytes());
  146. out.flush();
  147. waitForAck(in);
  148. // send a content of lfile
  149. FileInputStream fis = new FileInputStream(localFile);
  150. byte[] buf = new byte[BUFFER_SIZE];
  151. long startTime = System.currentTimeMillis();
  152. int totalLength = 0;
  153. // only track progress for files larger than 100kb in verbose mode
  154. boolean trackProgress = getVerbose() && filesize > 102400;
  155. // since filesize keeps on decreasing we have to store the
  156. // initial filesize
  157. int initFilesize = filesize;
  158. int percentTransmitted = 0;
  159. try {
  160. log("Sending: " + localFile.getName() + " : " + localFile.length());
  161. while (true) {
  162. int len = fis.read(buf, 0, buf.length);
  163. if (len <= 0) {
  164. break;
  165. }
  166. out.write(buf, 0, len);
  167. totalLength += len;
  168. if (trackProgress) {
  169. percentTransmitted = trackProgress(initFilesize,
  170. totalLength,
  171. percentTransmitted);
  172. }
  173. }
  174. out.flush();
  175. sendAck(out);
  176. waitForAck(in);
  177. } finally {
  178. long endTime = System.currentTimeMillis();
  179. logStats(startTime, endTime, totalLength);
  180. fis.close();
  181. }
  182. }
  183. public File getLocalFile() {
  184. return localFile;
  185. }
  186. public String getRemotePath() {
  187. return remotePath;
  188. }
  189. }