001/* 002 * Copyright (c) 2009-2012 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: crawl $' 006 * '$Date: 2012-11-26 22:19:36 +0000 (Mon, 26 Nov 2012) $' 007 * '$Revision: 31113 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.sdm.spa.actors.transport; 031 032import java.io.ByteArrayOutputStream; 033import java.io.File; 034import java.util.Vector; 035 036import org.apache.commons.logging.Log; 037import org.apache.commons.logging.LogFactory; 038import org.kepler.ssh.ExecException; 039import org.kepler.ssh.SftpExec; 040import org.kepler.ssh.SshException; 041import org.sdm.spa.actors.transport.vo.ConnectionDetails; 042 043/** 044 * This class copies files/directories from one machine to another using the 045 * sftp protocol. It uses the <code>SftpExec</code> to copy file/directory from 046 * local machine to a remote machine or vice-versa. Copy between remote machines 047 * is achieved using sftp batch mode. 048 * <P> 049 * Copy operation will overwrite existing files by default. Copy between local 050 * host and remote host does not used the sftp command and hence would ignore 051 * the variables cmdLineOptions, protocolPathSrc, forcedCleanup, and timeout. 052 * <P> 053 * Class expect sftp to be available on standard path on the destination 054 * machine. On source machine, if sftp is not on standard path and if the 055 * variable protocolPathSrc is not set, the class attempts to search in the most 056 * common locations - user's home directory, /usr/bin, /bin, and /usr/local/bin 057 * 058 * @author Chandrika Sivaramakrishnan 059 * 060 */ 061 062/** 063 * SFTP provides functionality to copy files, regular expressions, 064 * directories(with dir: option). It does not provide list of file/dir/regular 065 * expression. To achieve that we loop through list of files and execute sftp 066 * copy for each statement.\ 067 * 068 * @author 069 * 070 */ 071 072public class SftpCopier extends FileCopierBase { 073 074 // private variables 075 private static final Log log = LogFactory 076 .getLog(SftpCopier.class.getName()); 077 private static final boolean isDebugging = log.isDebugEnabled(); 078 079 // public/protected methods 080 /* 081 * Uses the <code>SftpExec</code> class to copy files from a remote host to 082 * the local machine. 083 * 084 * @see 085 * org.sdm.spa.actors.transport.FileCopier#copyFrom(org.sdm.spa.actors.transport 086 * .vo.ConnectionDetails, java.lang.String, java.lang.String, boolean) 087 */ 088 089 // Anusua Change - STARTS 090 @Override 091 protected CopyResult copyFrom(ConnectionDetails srcDetails, String srcFile, 092 String destFile, boolean recursive) throws ExecException { 093 094 if (isDebugging) { 095 log.debug("sftp copy from"); 096 } 097 098 StringBuffer warn = new StringBuffer(100); 099 boolean warn_flag = false; 100 101 SftpExec sftpObject = new SftpExec(srcDetails.getUser(), srcDetails 102 .getHost(), srcDetails.getPort()); 103 sftpObject.setTimeout(getTimeout(), false, false); 104 File destFileObj = new File(destFile); 105 106 try { 107 108 // Transfer of multiple files to directory level 109 if (srcFile.contains(",")) { 110 String[] srcFile_list = srcFile.split(","); 111 for (int i = 0; i < srcFile_list.length; i++) { 112 if ((srcFile_list[i].trim()).startsWith("/")) { 113 sftpObject.copyFrom(srcFile_list[i].trim(), 114 destFileObj, recursive); 115 } else { 116 warn.append(srcFile_list[i] + " "); 117 if (!warn_flag) 118 warn_flag = true; 119 } 120 } 121 } else { // single file specified 122 if ((srcFile.trim()).startsWith("/")) { 123 sftpObject.copyFrom(srcFile.trim(), destFileObj, recursive); 124 } else { 125 warn.append(srcFile + " "); 126 if (!warn_flag) 127 warn_flag = true; 128 } 129 sftpObject.copyFrom(srcFile.trim(), destFileObj, recursive); 130 } 131 132 if (warn_flag) { 133 warn 134 .append(" does not contain full path to the source file. Please provide full path. "); 135 return new CopyResult(1, warn.toString(), ""); // sftp returns 136 // without 137 // exception in 138 // case 139 } 140 return new CopyResult(); // sftp returns without exception in case 141 // of 142 // success 143 } catch (ExecException e) { 144 return new CopyResult(1, e.getMessage(), ""); 145 } 146 147 } 148 149 /* 150 * Uses <code>SftpExec</code> to copy files from a local host to remote 151 * machine 152 * 153 * @see org.sdm.spa.actors.transport.FileCopier#copyTo(java.lang.String, 154 * org.sdm.spa.actors.transport.vo.ConnectionDetails, java.lang.String, 155 * boolean) 156 */ 157 @Override 158 protected CopyResult copyTo(String srcFile, ConnectionDetails destDetails, 159 String destFile, boolean recursive) throws ExecException { 160 161 StringBuffer warn = new StringBuffer(100); 162 boolean warn_flag = false; 163 boolean isWindows = false; 164 if (isDebugging) { 165 log.debug("sftp copy to"); 166 } 167 SftpExec sftpObject = new SftpExec(destDetails.getUser(), destDetails 168 .getHost(), destDetails.getPort()); 169 sftpObject.setTimeout(getTimeout(), false, false); 170 String osname = (System.getProperty("os.name")).toLowerCase(); 171 String userhome = (System.getProperty("user.home")).toLowerCase(); 172 if (osname.equalsIgnoreCase("windows")) { 173 isWindows = true; 174 } 175 File destFileObj = new File(destFile); 176 File srcFileObj = null; 177 178 try { 179 // Transfer of multiple files to directory level 180 if (srcFile.contains(",")) { 181 String[] srcFile_list = srcFile.split(","); 182 for (int i = 0; i < srcFile_list.length; i++) { 183 //Chandrika - Assume that file has full path. 184 //Parent class would have fixed the local relative paths 185 //before calling copyTo. Do not enclose filename in "" to escape spaces. 186 //sftpObject handles it. 187 srcFile_list[i] = srcFile_list[i].trim() ; 188 srcFileObj = new File(srcFile_list[i]); 189 // if (srcFileObj.exists()) 190 sftpObject.copyTo(srcFileObj, destFile, recursive); 191 // else{ 192 // warn_flag = true; 193 // warn.append("Source file " + srcFile_list[i] + 194 // " does not exist!\n"); 195 // } 196 } 197 } else { 198 // Anand: Adding else to handle single file transfer 199 srcFileObj = new File(srcFile); 200 // if (srcFileObj.exists()) 201 sftpObject.copyTo(srcFileObj, destFile, recursive); 202 // else{ 203 // warn_flag = true; 204 // warn.append("Source file " + srcFile + " does not exist!\n"); 205 // } 206 } 207 if (warn_flag) 208 return new CopyResult(1, warn.toString(), ""); 209 else 210 return new CopyResult(); 211 } catch (ExecException e) { 212 return new CopyResult(1, e.getMessage(), ""); 213 } 214 } 215 216 /* 217 * Copies files between two remote machines using the sftp command. Stores 218 * the sequence of mkdir and put command in a file on source machine and 219 * runs the sftp command in batch mode. The command file is deleted at the 220 * end of transaction 221 * 222 * @see 223 * org.sdm.spa.actors.transport.FileCopier#copyRemote(org.sdm.spa.actors 224 * .transport.vo.ConnectionDetails, java.lang.String, 225 * org.sdm.spa.actors.transport.vo.ConnectionDetails, java.lang.String, 226 * boolean) 227 */ 228 @Override 229 protected CopyResult copyRemote(ConnectionDetails srcDetails, 230 String srcFile, ConnectionDetails destDetails, String destFile, 231 boolean recursive) throws ExecException { 232 if (isDebugging) 233 log.debug("remote sftp copy"); 234 ByteArrayOutputStream cmdStdout = new ByteArrayOutputStream(); 235 ByteArrayOutputStream cmdStderr = new ByteArrayOutputStream(); 236 String cmdWithPath = null; 237 int exitCode = 0; 238 String cmdFile = "keplercmd_" + System.currentTimeMillis() + ".cmd"; 239 SftpExec sshObjectSrc = null; 240 SftpExec sshObjectDest = null; 241 String remoteHostStr = ""; 242 boolean warn_flag = false; 243 StringBuffer warn = new StringBuffer(100); 244 245 sshObjectSrc = new SftpExec(srcDetails.getUser(), srcDetails.getHost(), 246 srcDetails.getPort()); 247 sshObjectDest = new SftpExec(destDetails.getUser(), destDetails 248 .getHost(), destDetails.getPort()); 249 // SSH Session initialization 250 if (srcDetails.isConnectionOrigin()) { 251 // Connenct to source by ssh 252 sshObjectSrc.setTimeout(timeout, false, false); 253 sshObjectSrc.setForcedCleanUp(forcedCleanup); 254 sshObjectSrc.setPseudoTerminal(true); 255 remoteHostStr = destDetails.toString(); 256 } else { 257 sshObjectDest.setTimeout(timeout, false, false); 258 sshObjectDest.setForcedCleanUp(forcedCleanup); 259 sshObjectDest.setPseudoTerminal(true); 260 remoteHostStr = srcDetails.toString(); 261 } 262 263 String[] srcFile_list = srcFile.split(","); 264 265 try { 266 // Transfer of multiple files to directory level 267 if (srcFile.contains(",")) { 268 // for each file in the list 269 for (int index = 0; index < srcFile_list.length; index++) { 270 cmdFile = "keplercmd_" + System.currentTimeMillis() 271 + ".cmd"; 272 // cmdFile = "keplercmd_" + System.currentTimeMillis() + 273 // ".cmd"; 274 // Anand: The file name contains regular expression - what 275 // about +, ? 276 if (srcFile_list[index].contains("*")) { 277 // if file name is a wildcard 278 cmdWithPath = buildSftpWildcardBatch(srcDetails, 279 srcFile_list[index].trim(), destDetails, 280 destFile.trim(), recursive, sshObjectSrc, 281 cmdFile); 282 } else { 283 // if file name is a regular file/directory 284 cmdWithPath = buildSftpCommand(srcDetails, 285 srcFile_list[index].trim(), destDetails, 286 destFile.trim(), recursive, sshObjectSrc, 287 cmdFile); 288 } 289 System.out.println("***************Rmote command : " 290 + cmdWithPath); 291 292 // Anand: Executing each file from the list separately is 293 // inefficient 294 // This may have been used to process each file separately, 295 // and continue 296 // copying even in case of failure of one of the files. 297 if (srcDetails.isConnectionOrigin()) 298 exitCode = sshObjectSrc.executeCmd(cmdWithPath, 299 cmdStdout, cmdStderr, remoteHostStr); 300 else 301 exitCode = sshObjectDest.executeCmd(cmdWithPath, 302 cmdStdout, cmdStderr, remoteHostStr); 303 if (exitCode > 0) { 304 warn_flag = true; 305 warn.append("Could not copy " + srcFile_list[index] 306 + ".\n"); 307 } 308 309 log.debug("exit code=" + exitCode); 310 log.error("Stdout: " + cmdStdout); 311 log.error("Error stream out: " + cmdStderr); 312 String fileDeleteMsg = ""; 313 try { 314 boolean success = false; 315 if (srcDetails.isConnectionOrigin()) 316 success = sshObjectSrc.deleteFile(cmdFile, false, 317 false); 318 else 319 success = sshObjectDest.deleteFile(cmdFile, false, 320 false); 321 322 if (success) { 323 log.debug("deleted the sftp command file " 324 + cmdFile + " created for file copy"); 325 } 326 if (!success) { 327 log.warn("Unable to delete the sftp command file " 328 + cmdFile + " created for file copy"); 329 warn 330 .append("Unable to delete the sftp command file " 331 + cmdFile 332 + " created for file copy\n"); 333 } 334 } catch (ExecException e) { 335 log.warn("Unable to delete the sftp command file " 336 + cmdFile + " created for file copy : " 337 + e.toString()); 338 } 339 } 340 } else { // single file source file is a remote file/dir/wildcard 341 if (srcFile.contains("*")) { 342 cmdWithPath = buildSftpWildcardBatch(srcDetails, srcFile, 343 destDetails, destFile, recursive, sshObjectSrc, 344 cmdFile); 345 } else { 346 cmdWithPath = buildSftpCommand(srcDetails, srcFile, 347 destDetails, destFile, recursive, sshObjectSrc, 348 cmdFile); 349 } 350 // cmdWithPath = cmd + "\""; 351 System.out.println("***************Rmote command : " 352 + cmdWithPath); 353 if (srcDetails.isConnectionOrigin()) 354 exitCode = sshObjectSrc.executeCmd(cmdWithPath, cmdStdout, 355 cmdStderr, remoteHostStr); 356 else 357 exitCode = sshObjectDest.executeCmd(cmdWithPath, cmdStdout, 358 cmdStderr, remoteHostStr); 359 360 String fileDeleteMsg = ""; 361 try { 362 boolean success = false; 363 if (srcDetails.isConnectionOrigin()) 364 success = sshObjectSrc 365 .deleteFile(cmdFile, false, false); 366 else 367 success = sshObjectDest.deleteFile(cmdFile, false, 368 false); 369 370 if (success) { 371 log.debug("deleted the sftp command file " + cmdFile 372 + " created for file copy"); 373 } 374 if (!success) { 375 log.warn("Unable to delete the sftp command file " 376 + cmdFile + " created for file copy"); 377 warn.append("Unable to delete the sftp command file " 378 + cmdFile + " created for file copy\n"); 379 } 380 } catch (ExecException e) { 381 log.warn("Unable to delete the sftp command file " 382 + cmdFile + " created for file copy : " 383 + e.toString()); 384 } 385 } 386 if (warn_flag) 387 return new CopyResult(1, warn.toString(), ""); 388 389 String message = cmdStdout.toString(); 390 return new CopyResult(exitCode, message, ""); 391 } catch (Exception e) { 392 e.printStackTrace(); 393 return new CopyResult(1, e.getMessage(), ""); 394 } 395 } 396 397 /** 398 * Anand: Create a command for remote to remote SFTP copy. This function 399 * does not copy the command file to remote directory. It just creates echo 400 * statement to copy the command file and the command. command format : bash 401 * -c 'export PATH=/usr/bin:/bin:/usr/local/bin:~:.:$PATH; echo -e 402 * "put <sourcefile destinationfile>" \n "put <sourcefile destinationfile>" 403 * > batchfile; sftp -o "batchmode no" -b <batchfile> -oPort=22 404 * gs3dev@130.20.107.80' The batch file contains series of put/get commands 405 * to be executed of sftp prompt. 406 * 407 * @param srcDetails 408 * - Source connection details 409 * @param srcFile 410 * - Source file name 411 * @param destDetails 412 * - Destination connection details 413 * @param destFile 414 * - destination file name 415 * @param recursive 416 * - true/false for directory 417 * @param sshObject 418 * - used to connect to remote machine to get file list matching 419 * wildcard 420 * @param cmdFile 421 * - batch file name 422 * @return String - command which is to be run to copy files 423 * @throws Exception 424 */ 425 public String buildSftpWildcardBatch(ConnectionDetails srcDetails, 426 String srcFile, ConnectionDetails destDetails, String destFile, 427 boolean recursive, SftpExec sshObject, String cmdFile) 428 throws Exception { 429 430 StringBuffer warn = new StringBuffer(100); 431 StringBuffer sftp_cmd = new StringBuffer(150); 432 String cmdWithPath; 433 Vector<String> fileList = null; 434 try { 435 System.out.println("***********WIld card detected :fname::" 436 + srcFile); 437 if (srcFile.contains("//")) 438 fileList = sshObject.getWildcardFileListing(srcFile, "\\"); 439 else 440 fileList = sshObject.getWildcardFileListing(srcFile, "/"); 441 442 if (null != fileList) { 443 sftp_cmd.append("echo -e \""); 444 // loop for all the files in the list 445 for (String curFile : fileList) { 446 if (srcDetails.isConnectionOrigin()) 447 sftp_cmd.append("put "); 448 else 449 sftp_cmd.append("get "); 450 sftp_cmd.append("\\\""); 451 sftp_cmd.append(curFile.trim()); 452 sftp_cmd.append("\\\""); 453 sftp_cmd.append(" "); 454 sftp_cmd.append("\\\""); 455 sftp_cmd.append(destFile); 456 sftp_cmd.append("\\\""); 457 sftp_cmd.append("\\n"); 458 } 459 } else { 460 warn.append("No files found for wildcard patter " + srcFile); 461 } 462 sftp_cmd.append("\" > "); 463 sftp_cmd.append(cmdFile); 464 sftp_cmd.append("; "); 465 466 if (isDebugging) { 467 log.debug("protocolpath=" + protocolPathSrc); 468 } 469 470 sftp_cmd.append(protocolPathSrc); 471 sftp_cmd.append("sftp -o \"batchmode no\" -b "); 472 sftp_cmd.append(cmdFile); 473 sftp_cmd.append(" "); 474 475 if (srcDetails.isConnectionOrigin()) { 476 if (destDetails.getPort() != -1) { 477 sftp_cmd.append(" -oPort="); 478 sftp_cmd.append(destDetails.getPort()); 479 sftp_cmd.append(" "); 480 } 481 sftp_cmd.append(cmdLineOptions); 482 sftp_cmd.append(" "); 483 sftp_cmd.append(destDetails.getUser()); 484 sftp_cmd.append("@"); 485 sftp_cmd.append(destDetails.getHost()); 486 487 if (protocolPathSrc.equals("")) { 488 cmdWithPath = getCmdWithDefaultPath(sftp_cmd); 489 } else { 490 cmdWithPath = "bash -c '" + sftp_cmd.toString() + " '"; 491 } 492 } else { 493 if (srcDetails.getPort() != -1) { 494 sftp_cmd.append(" -oPort="); 495 sftp_cmd.append(srcDetails.getPort()); 496 sftp_cmd.append(" "); 497 } 498 499 sftp_cmd.append(cmdLineOptions); 500 sftp_cmd.append(" "); 501 sftp_cmd.append(srcDetails.getUser()); 502 sftp_cmd.append("@"); 503 sftp_cmd.append(srcDetails.getHost()); 504 505 if (protocolPathSrc.equals("")) { 506 cmdWithPath = getCmdWithDefaultPath(sftp_cmd); 507 } else { 508 cmdWithPath = "bash -c '" + sftp_cmd.toString() + " '"; 509 } 510 } 511 512 if (isDebugging) 513 log.debug("remote copy cmd=" + cmdWithPath); 514 515 return cmdWithPath; 516 } catch (Exception e) { 517 e.printStackTrace(); 518 throw e; 519 } 520 } 521 522 /** 523 * Anand: Create a batch file for a file or directory and give that to sftp 524 * to perform copy This function creates batch file, and builds sftp copy 525 * command and returns it to calling function. 526 * 527 * @param srcDetails 528 * - Source connection details 529 * @param srcFile 530 * - Source file name 531 * @param destDetails 532 * - Destination connection details 533 * @param destFile 534 * - destination file name 535 * @param recursive 536 * - true/false for directory 537 * @param sshObject 538 * - used to connect to remote machine to get file list matching 539 * wildcard 540 * @param cmdFile 541 * - batch file name 542 * @return String : command which is to be run to copy files 543 * @throws Exception 544 */ 545 public String buildSftpCommand(ConnectionDetails srcDetails, 546 String srcFile, ConnectionDetails destDetails, String destFile, 547 boolean recursive, SftpExec sshObject, String cmdFile) 548 throws Exception { 549 550 StringBuffer sftp_cmd = new StringBuffer(); 551 String cmdWithPath = null; 552 sftp_cmd.append("echo -e \""); 553 if (srcDetails.isConnectionOrigin()) { 554 srcFile = srcFile.trim(); 555 // checks if the file is regular 556 if (sshObject.isRegularOrLinkFile(srcFile.trim())) { 557 sftp_cmd.append("put "); 558 sftp_cmd.append("\\\""); 559 sftp_cmd.append(srcFile); 560 sftp_cmd.append("\\\""); 561 sftp_cmd.append(" "); 562 sftp_cmd.append("\\\""); 563 sftp_cmd.append(destFile); 564 sftp_cmd.append("\\\""); 565 } else { 566 if (recursive) { 567 // TODO Anand: funtions getRecursiveCopyCmd does not handle 568 // spaces in file names 569 sftp_cmd.append(sshObject.getRecursiveCopyCmd(srcFile, 570 destFile, true)); 571 } else { 572 // print error 573 throw new SshException( 574 "Unable to determine file type of source file " 575 + srcFile + "\n"); 576 } 577 } 578 } else { 579 if (sshObject.isRegularOrLinkFile(srcFile.trim())) { 580 sftp_cmd.append("get "); 581 sftp_cmd.append("\\\""); 582 sftp_cmd.append(srcFile); 583 sftp_cmd.append("\\\""); 584 sftp_cmd.append(" "); 585 sftp_cmd.append("\\\""); 586 sftp_cmd.append(destFile); 587 sftp_cmd.append("\\\""); 588 } else { 589 if (recursive) { 590 // TODO Anand: funtions getRecursiveCopyCmd does not handle 591 // spaces in file names 592 sftp_cmd.append(sshObject.getRecursiveCopyCmd(srcFile, 593 destFile, false)); 594 } else { 595 // print error 596 throw new SshException( 597 "Unable to determine file type of source file " 598 + srcFile + "\n"); 599 } 600 } 601 } 602 // sftp_cmd.append("this is \\\"my\\\" string"); 603 sftp_cmd.append("\" >> "); 604 sftp_cmd.append(cmdFile); 605 sftp_cmd.append("; "); 606 607 if (isDebugging) { 608 log.debug("protocolpath=" + protocolPathSrc); 609 } 610 611 sftp_cmd.append(protocolPathSrc); 612 sftp_cmd.append("sftp -o \"batchmode no\" -b "); 613 sftp_cmd.append(cmdFile); 614 sftp_cmd.append(" "); 615 616 if (srcDetails.isConnectionOrigin()) { 617 if (destDetails.getPort() != -1) { 618 sftp_cmd.append(" -oPort="); 619 sftp_cmd.append(destDetails.getPort()); 620 sftp_cmd.append(" "); 621 } 622 sftp_cmd.append(cmdLineOptions); 623 sftp_cmd.append(" "); 624 sftp_cmd.append(destDetails.getUser()); 625 sftp_cmd.append("@"); 626 sftp_cmd.append(destDetails.getHost()); 627 628 if (protocolPathSrc.equals("")) { 629 cmdWithPath = getCmdWithDefaultPath(sftp_cmd); 630 } else { 631 cmdWithPath = "bash -c '" + sftp_cmd.toString() + " '"; 632 } 633 } else { 634 if (srcDetails.getPort() != -1) { 635 sftp_cmd.append(" -oPort="); 636 sftp_cmd.append(srcDetails.getPort()); 637 sftp_cmd.append(" "); 638 } 639 640 sftp_cmd.append(cmdLineOptions); 641 sftp_cmd.append(" "); 642 sftp_cmd.append(srcDetails.getUser()); 643 sftp_cmd.append("@"); 644 sftp_cmd.append(srcDetails.getHost()); 645 646 if (protocolPathSrc.equals("")) { 647 cmdWithPath = getCmdWithDefaultPath(sftp_cmd); 648 } else { 649 cmdWithPath = "bash -c '" + sftp_cmd.toString() + " '"; 650 } 651 } 652 653 if (isDebugging) 654 log.debug("remote copy cmd=" + cmdWithPath); 655 return cmdWithPath; 656 657 } 658 659 @Override 660 protected int getDefaultPort() { 661 return 22; 662 } 663 664}