1 package fr.jayasoft.ivy.repository.ssh; 2 3 import java.io.BufferedInputStream ; 4 import java.io.BufferedOutputStream ; 5 import java.io.File ; 6 import java.io.FileInputStream ; 7 import java.io.FileOutputStream ; 8 import java.io.IOException ; 9 import java.io.InputStream ; 10 import java.io.OutputStream ; 11 12 import com.jcraft.jsch.ChannelExec; 13 import com.jcraft.jsch.JSchException; 14 import com.jcraft.jsch.Session; 15 import com.jcraft.jsch.Channel; 16 17 28 29 public class Scp { 30 Session session; 31 32 public class FileInfo { 33 private String filename; 34 private long length; 35 private long lastModified; 36 39 public void setFilename(String filename) { 40 this.filename = filename; 41 } 42 45 public String getFilename() { 46 return filename; 47 } 48 51 public void setLength(long length) { 52 this.length = length; 53 } 54 57 public long getLength() { 58 return length; 59 } 60 63 public void setLastModified(long lastModified) { 64 this.lastModified = lastModified; 65 } 66 69 public long getLastModified() { 70 return lastModified; 71 } 72 } 73 74 public Scp(Session session) { 75 if (session == null) 76 throw new IllegalArgumentException ("Cannot accept null argument!"); 77 this.session = session; 78 } 79 80 private void readResponse(InputStream is) throws IOException , RemoteScpException { 81 int c = is.read(); 82 83 if (c == 0) 84 return; 85 86 if (c == -1) 87 throw new RemoteScpException("Remote scp terminated unexpectedly."); 88 89 if ((c != 1) && (c != 2)) 90 throw new RemoteScpException("Remote scp sent illegal error code."); 91 92 if (c == 2) 93 throw new RemoteScpException("Remote scp terminated with error."); 94 95 String err = receiveLine(is); 96 throw new RemoteScpException("Remote scp terminated with error (" + err + ")."); 97 } 98 99 private String receiveLine(InputStream is) throws IOException ,RemoteScpException { 100 StringBuffer sb = new StringBuffer (30); 101 102 while (true) { 103 107 108 if (sb.length() > 8192) 109 throw new RemoteScpException("Remote scp sent a too long line"); 110 111 int c = is.read(); 112 113 if (c < 0) 114 throw new RemoteScpException("Remote scp terminated unexpectedly."); 115 116 if (c == '\n') 117 break; 118 119 sb.append((char) c); 120 121 } 122 return sb.toString(); 123 } 124 125 private void parseCLine(String line, FileInfo fileInfo) throws RemoteScpException { 126 127 128 long len; 129 130 if (line.length() < 8) 131 throw new RemoteScpException( 132 "Malformed C line sent by remote SCP binary, line too short."); 133 134 if ((line.charAt(4) != ' ') || (line.charAt(5) == ' ')) 135 throw new RemoteScpException("Malformed C line sent by remote SCP binary."); 136 137 int length_name_sep = line.indexOf(' ', 5); 138 139 if (length_name_sep == -1) 140 throw new RemoteScpException("Malformed C line sent by remote SCP binary."); 141 142 String length_substring = line.substring(5, length_name_sep); 143 String name_substring = line.substring(length_name_sep + 1); 144 145 if ((length_substring.length() <= 0) || (name_substring.length() <= 0)) 146 throw new RemoteScpException("Malformed C line sent by remote SCP binary."); 147 148 if ((6 + length_substring.length() + name_substring.length()) != line 149 .length()) 150 throw new RemoteScpException("Malformed C line sent by remote SCP binary."); 151 152 try { 153 len = Long.parseLong(length_substring); 154 } catch (NumberFormatException e) { 155 throw new RemoteScpException( 156 "Malformed C line sent by remote SCP binary, cannot parse file length."); 157 } 158 159 if (len < 0) 160 throw new RemoteScpException( 161 "Malformed C line sent by remote SCP binary, illegal file length."); 162 163 fileInfo.setLength(len); 164 fileInfo.setFilename(name_substring); 165 } 166 167 private void parseTLine(String line, FileInfo fileInfo) throws RemoteScpException { 168 169 170 long modtime; 171 long first_msec; 172 long atime; 173 long second_msec; 174 175 if (line.length() < 8) 176 throw new RemoteScpException( 177 "Malformed T line sent by remote SCP binary, line too short."); 178 179 int first_msec_begin = line.indexOf(" ")+1; 180 if(first_msec_begin == 0 || first_msec_begin >= line.length()) 181 throw new RemoteScpException( 182 "Malformed T line sent by remote SCP binary, line not enough data."); 183 184 int atime_begin = line.indexOf(" ",first_msec_begin+1)+1; 185 if(atime_begin == 0 || atime_begin >= line.length()) 186 throw new RemoteScpException( 187 "Malformed T line sent by remote SCP binary, line not enough data."); 188 189 int second_msec_begin = line.indexOf(" ",atime_begin+1)+1; 190 if(second_msec_begin == 0 || second_msec_begin >= line.length()) 191 throw new RemoteScpException( 192 "Malformed T line sent by remote SCP binary, line not enough data."); 193 194 try { 195 modtime = Long.parseLong(line.substring(0,first_msec_begin-1)); 196 first_msec = Long.parseLong(line.substring(first_msec_begin,atime_begin-1)); 197 atime = Long.parseLong(line.substring(atime_begin,second_msec_begin-1)); 198 second_msec = Long.parseLong(line.substring(second_msec_begin)); 199 } catch (NumberFormatException e) { 200 throw new RemoteScpException( 201 "Malformed C line sent by remote SCP binary, cannot parse file length."); 202 } 203 204 if (modtime < 0 || first_msec < 0 || atime < 0 || second_msec < 0) 205 throw new RemoteScpException( 206 "Malformed C line sent by remote SCP binary, illegal file length."); 207 208 fileInfo.setLastModified(modtime); 209 } 210 211 private void sendBytes(Channel channel, byte[] data, String fileName, 212 String mode) throws IOException ,RemoteScpException { 213 OutputStream os = channel.getOutputStream(); 214 InputStream is = new BufferedInputStream (channel.getInputStream(), 512); 215 216 try { 217 if(channel.isConnected()) 218 channel.start(); 219 else 220 channel.connect(); 221 } catch (JSchException e1) { 222 throw (IOException ) new IOException ("Channel connection problems").initCause(e1); 223 } 224 225 readResponse(is); 226 227 String cline = "C" + mode + " " + data.length + " " + fileName + "\n"; 228 229 os.write(cline.getBytes()); 230 os.flush(); 231 232 readResponse(is); 233 234 os.write(data, 0, data.length); 235 os.write(0); 236 os.flush(); 237 238 readResponse(is); 239 240 os.write("E\n".getBytes()); 241 os.flush(); 242 } 243 244 private void sendFile(Channel channel, String localFile, String remoteName, String mode) 245 throws IOException , RemoteScpException { 246 byte[] buffer = new byte[8192]; 247 248 OutputStream os = new BufferedOutputStream (channel.getOutputStream(), 40000); 249 InputStream is = new BufferedInputStream (channel.getInputStream(), 512); 250 251 try { 252 if(channel.isConnected()) 253 channel.start(); 254 else 255 channel.connect(); 256 } catch (JSchException e1) { 257 throw (IOException ) new IOException ("Channel connection problems").initCause(e1); 258 } 259 260 readResponse(is); 261 262 File f = new File (localFile); 263 long remain = f.length(); 264 265 String cline = "C" + mode + " " + remain + " " + remoteName + "\n"; 266 267 os.write(cline.getBytes()); 268 os.flush(); 269 270 readResponse(is); 271 272 FileInputStream fis = null; 273 274 try { 275 fis = new FileInputStream (f); 276 277 while (remain > 0) { 278 int trans; 279 if (remain > buffer.length) 280 trans = buffer.length; 281 else 282 trans = (int) remain; 283 284 if (fis.read(buffer, 0, trans) != trans) 285 throw new IOException ( 286 "Cannot read enough from local file " 287 + localFile); 288 289 os.write(buffer, 0, trans); 290 291 remain -= trans; 292 } 293 294 fis.close(); 295 } catch (IOException e) { 296 if (fis != null) { 297 fis.close(); 298 } 299 throw (e); 300 } 301 302 os.write(0); 303 os.flush(); 304 305 readResponse(is); 306 307 os.write("E\n".getBytes()); 308 os.flush(); 309 } 310 311 320 private FileInfo receiveStream(Channel channel, String file, OutputStream targetStream) 321 throws IOException ,RemoteScpException { 322 byte[] buffer = new byte[8192]; 323 324 OutputStream os = channel.getOutputStream(); 325 InputStream is = channel.getInputStream(); 326 try { 327 if(channel.isConnected()) 328 channel.start(); 329 else 330 channel.connect(); 331 } catch (JSchException e1) { 332 throw (IOException ) new IOException ("Channel connection problems").initCause(e1); 333 } 334 os.write(0x0); 335 os.flush(); 336 337 FileInfo fileInfo = new FileInfo(); 338 339 while (true) { 340 int c = is.read(); 341 if (c < 0) 342 throw new RemoteScpException("Remote scp terminated unexpectedly."); 343 344 String line = receiveLine(is); 345 346 if (c == 'T') { 347 parseTLine(line,fileInfo); 348 os.write(0x0); 349 os.flush(); 350 continue; 351 } 352 if ((c == 1) || (c == 2)) 353 throw new RemoteScpException("Remote SCP error: " + line); 354 355 if (c == 'C') { 356 parseCLine(line,fileInfo); 357 break; 358 } 359 throw new RemoteScpException("Remote SCP error: " + ((char) c) + line); 360 } 361 if(targetStream != null) { 362 363 os.write(0x0); 364 os.flush(); 365 366 try { 367 long remain = fileInfo.getLength(); 368 369 while (remain > 0) { 370 int trans; 371 if (remain > buffer.length) 372 trans = buffer.length; 373 else 374 trans = (int) remain; 375 376 int this_time_received = is.read(buffer, 0, trans); 377 378 if (this_time_received < 0) { 379 throw new IOException ( 380 "Remote scp terminated connection unexpectedly"); 381 } 382 383 targetStream.write(buffer, 0, this_time_received); 384 385 remain -= this_time_received; 386 } 387 388 targetStream.close(); 389 } catch (IOException e) { 390 if (targetStream != null) 391 targetStream.close(); 392 393 throw (e); 394 } 395 396 readResponse(is); 397 398 os.write(0x0); 399 os.flush(); 400 } 401 return fileInfo; 402 } 403 404 414 public void put(String localFile, String remoteTargetDirectory, String remoteName) 415 throws IOException , RemoteScpException { 416 put(localFile, remoteTargetDirectory, remoteName, "0600"); 417 } 418 419 429 430 public void put(byte[] data, String remoteFileName, String remoteTargetDirectory) 431 throws IOException ,RemoteScpException { 432 put(data, remoteFileName, remoteTargetDirectory, "0600"); 433 } 434 435 447 public void put(byte[] data, String remoteFileName, String remoteTargetDirectory, String mode) 448 throws IOException ,RemoteScpException { 449 ChannelExec channel = null; 450 451 if ((remoteFileName == null) || (mode == null)) 452 throw new IllegalArgumentException ("Null argument."); 453 454 if (mode.length() != 4) 455 throw new IllegalArgumentException ("Invalid mode."); 456 457 for (int i = 0; i < mode.length(); i++) 458 if (Character.isDigit(mode.charAt(i)) == false) 459 throw new IllegalArgumentException ("Invalid mode."); 460 461 String cmd = "scp -t "; 462 if(remoteTargetDirectory != null && remoteTargetDirectory.length() > 0) { 463 cmd = cmd + "-d " + remoteTargetDirectory; 464 } 465 466 try { 467 channel = getExecChannel(); 468 channel.setCommand(cmd); 469 sendBytes(channel, data, remoteFileName, mode); 470 } catch (JSchException e) { 472 if (channel != null) 473 channel.disconnect(); 474 throw (IOException ) new IOException ("Error during SCP transfer."+e.getMessage()) 475 .initCause(e); 476 } 477 } 478 479 483 private ChannelExec getExecChannel() throws JSchException { 484 ChannelExec channel; 485 channel = (ChannelExec)session.openChannel("exec"); 486 return channel; 487 } 488 489 500 public void put(String localFile, String remoteTargetDir, String remoteTargetName, String mode) 501 throws IOException ,RemoteScpException { 502 ChannelExec channel = null; 503 504 if ((localFile == null) || (remoteTargetName == null) || (mode == null)) 505 throw new IllegalArgumentException ("Null argument."); 506 507 if (mode.length() != 4) 508 throw new IllegalArgumentException ("Invalid mode."); 509 510 for (int i = 0; i < mode.length(); i++) 511 if (Character.isDigit(mode.charAt(i)) == false) 512 throw new IllegalArgumentException ("Invalid mode."); 513 514 String cmd = "scp -t "; 515 if(remoteTargetDir != null && remoteTargetDir.length() > 0) { 516 cmd = cmd + "-d " + remoteTargetDir; 517 } 518 519 try { 520 channel = getExecChannel(); 521 channel.setCommand(cmd); 522 sendFile(channel, localFile, remoteTargetName, mode); 523 channel.disconnect(); 524 } catch (JSchException e) { 525 if (channel != null) 526 channel.disconnect(); 527 throw (IOException ) new IOException ("Error during SCP transfer."+e.getMessage()) 528 .initCause(e); 529 } 530 } 531 532 539 public void get(String remoteFile, String localTarget) throws IOException ,RemoteScpException { 540 File f = new File (localTarget); 541 FileOutputStream fop = new FileOutputStream (f); 542 get(remoteFile,fop); 543 } 544 545 552 public void get(String remoteFile, OutputStream localTarget) throws IOException ,RemoteScpException { 553 ChannelExec channel = null; 554 555 if ((remoteFile == null) || (localTarget == null)) 556 throw new IllegalArgumentException ("Null argument."); 557 558 String cmd = "scp -p -f "+ remoteFile; 559 560 try { 561 channel = getExecChannel(); 562 channel.setCommand(cmd); 563 receiveStream(channel, remoteFile, localTarget); 564 channel.disconnect(); 565 } catch (JSchException e) { 566 if (channel != null) 567 channel.disconnect(); 568 throw (IOException ) new IOException ("Error during SCP transfer."+e.getMessage()) 569 .initCause(e); 570 } 571 } 572 573 580 public FileInfo getFileinfo(String remoteFile) throws IOException ,RemoteScpException { 581 ChannelExec channel = null; 582 FileInfo fileInfo = null; 583 584 if (remoteFile == null) 585 throw new IllegalArgumentException ("Null argument."); 586 587 String cmd = "scp -p -f \""+remoteFile+"\""; 588 589 try { 590 channel = getExecChannel(); 591 channel.setCommand(cmd); 592 fileInfo = receiveStream(channel, remoteFile, null); 593 channel.disconnect(); 594 } catch (JSchException e) { 595 throw (IOException ) new IOException ("Error during SCP transfer."+e.getMessage()) 596 .initCause(e); 597 } finally { 598 if (channel != null) 599 channel.disconnect(); 600 } 601 return fileInfo; 602 } 603 } 604 | Popular Tags |