1 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */ 2 /* 3 Copyright (c) 2002-2015 ymnk, JCraft,Inc. All rights reserved. 4 5 Redistribution and use in source and binary forms, with or without 6 modification, are permitted provided that the following conditions are met: 7 8 1. Redistributions of source code must retain the above copyright notice, 9 this list of conditions and the following disclaimer. 10 11 2. Redistributions in binary form must reproduce the above copyright 12 notice, this list of conditions and the following disclaimer in 13 the documentation and/or other materials provided with the distribution. 14 15 3. The names of the authors may not be used to endorse or promote products 16 derived from this software without specific prior written permission. 17 18 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, 19 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, 21 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, 22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 24 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 package com.jcraft.jsch; 31 32 import java.io.*; 33 34 import java.util.Vector; 35 36 public class ChannelSftp extends ChannelSession{ 37 38 static private final int LOCAL_MAXIMUM_PACKET_SIZE=32*1024; 39 static private final int LOCAL_WINDOW_SIZE_MAX=(64*LOCAL_MAXIMUM_PACKET_SIZE); 40 41 private static final byte SSH_FXP_INIT= 1; 42 private static final byte SSH_FXP_VERSION= 2; 43 private static final byte SSH_FXP_OPEN= 3; 44 private static final byte SSH_FXP_CLOSE= 4; 45 private static final byte SSH_FXP_READ= 5; 46 private static final byte SSH_FXP_WRITE= 6; 47 private static final byte SSH_FXP_LSTAT= 7; 48 private static final byte SSH_FXP_FSTAT= 8; 49 private static final byte SSH_FXP_SETSTAT= 9; 50 private static final byte SSH_FXP_FSETSTAT= 10; 51 private static final byte SSH_FXP_OPENDIR= 11; 52 private static final byte SSH_FXP_READDIR= 12; 53 private static final byte SSH_FXP_REMOVE= 13; 54 private static final byte SSH_FXP_MKDIR= 14; 55 private static final byte SSH_FXP_RMDIR= 15; 56 private static final byte SSH_FXP_REALPATH= 16; 57 private static final byte SSH_FXP_STAT= 17; 58 private static final byte SSH_FXP_RENAME= 18; 59 private static final byte SSH_FXP_READLINK= 19; 60 private static final byte SSH_FXP_SYMLINK= 20; 61 private static final byte SSH_FXP_STATUS= 101; 62 private static final byte SSH_FXP_HANDLE= 102; 63 private static final byte SSH_FXP_DATA= 103; 64 private static final byte SSH_FXP_NAME= 104; 65 private static final byte SSH_FXP_ATTRS= 105; 66 private static final byte SSH_FXP_EXTENDED= (byte)200; 67 private static final byte SSH_FXP_EXTENDED_REPLY= (byte)201; 68 69 // pflags 70 private static final int SSH_FXF_READ= 0x00000001; 71 private static final int SSH_FXF_WRITE= 0x00000002; 72 private static final int SSH_FXF_APPEND= 0x00000004; 73 private static final int SSH_FXF_CREAT= 0x00000008; 74 private static final int SSH_FXF_TRUNC= 0x00000010; 75 private static final int SSH_FXF_EXCL= 0x00000020; 76 77 private static final int SSH_FILEXFER_ATTR_SIZE= 0x00000001; 78 private static final int SSH_FILEXFER_ATTR_UIDGID= 0x00000002; 79 private static final int SSH_FILEXFER_ATTR_PERMISSIONS= 0x00000004; 80 private static final int SSH_FILEXFER_ATTR_ACMODTIME= 0x00000008; 81 private static final int SSH_FILEXFER_ATTR_EXTENDED= 0x80000000; 82 83 public static final int SSH_FX_OK= 0; 84 public static final int SSH_FX_EOF= 1; 85 public static final int SSH_FX_NO_SUCH_FILE= 2; 86 public static final int SSH_FX_PERMISSION_DENIED= 3; 87 public static final int SSH_FX_FAILURE= 4; 88 public static final int SSH_FX_BAD_MESSAGE= 5; 89 public static final int SSH_FX_NO_CONNECTION= 6; 90 public static final int SSH_FX_CONNECTION_LOST= 7; 91 public static final int SSH_FX_OP_UNSUPPORTED= 8; 92 /* 93 SSH_FX_OK 94 Indicates successful completion of the operation. 95 SSH_FX_EOF 96 indicates end-of-file condition; for SSH_FX_READ it means that no 97 more data is available in the file, and for SSH_FX_READDIR it 98 indicates that no more files are contained in the directory. 99 SSH_FX_NO_SUCH_FILE 100 is returned when a reference is made to a file which should exist 101 but doesn't. 102 SSH_FX_PERMISSION_DENIED 103 is returned when the authenticated user does not have sufficient 104 permissions to perform the operation. 105 SSH_FX_FAILURE 106 is a generic catch-all error message; it should be returned if an 107 error occurs for which there is no more specific error code 108 defined. 109 SSH_FX_BAD_MESSAGE 110 may be returned if a badly formatted packet or protocol 111 incompatibility is detected. 112 SSH_FX_NO_CONNECTION 113 is a pseudo-error which indicates that the client has no 114 connection to the server (it can only be generated locally by the 115 client, and MUST NOT be returned by servers). 116 SSH_FX_CONNECTION_LOST 117 is a pseudo-error which indicates that the connection to the 118 server has been lost (it can only be generated locally by the 119 client, and MUST NOT be returned by servers). 120 SSH_FX_OP_UNSUPPORTED 121 indicates that an attempt was made to perform an operation which 122 is not supported for the server (it may be generated locally by 123 the client if e.g. the version number exchange indicates that a 124 required feature is not supported by the server, or it may be 125 returned by the server if the server does not implement an 126 operation). 127 */ 128 private static final int MAX_MSG_LENGTH = 256* 1024; 129 130 public static final int OVERWRITE=0; 131 public static final int RESUME=1; 132 public static final int APPEND=2; 133 134 private boolean interactive=false; 135 private int seq=1; 136 private int[] ackid=new int[1]; 137 138 private Buffer buf; 139 private Packet packet; 140 141 // The followings will be used in file uploading. 142 private Buffer obuf; 143 private Packet opacket; 144 145 private int client_version=3; 146 private int server_version=3; 147 private String version=String.valueOf(client_version); 148 149 private java.util.Hashtable extensions=null; 150 private InputStream io_in=null; 151 152 private boolean extension_posix_rename = false; 153 private boolean extension_statvfs = false; 154 // private boolean extension_fstatvfs = false; 155 private boolean extension_hardlink = false; 156 157 /* 158 10. Changes from previous protocol versions 159 The SSH File Transfer Protocol has changed over time, before it's 160 standardization. The following is a description of the incompatible 161 changes between different versions. 162 10.1 Changes between versions 3 and 2 163 o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added. 164 o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were added. 165 o The SSH_FXP_STATUS message was changed to include fields `error 166 message' and `language tag'. 167 10.2 Changes between versions 2 and 1 168 o The SSH_FXP_RENAME message was added. 169 10.3 Changes between versions 1 and 0 170 o Implementation changes, no actual protocol changes. 171 */ 172 173 private static final String file_separator=java.io.File.separator; 174 private static final char file_separatorc=java.io.File.separatorChar; 175 private static boolean fs_is_bs=(byte)java.io.File.separatorChar == '\\'; 176 177 private String cwd; 178 private String home; 179 private String lcwd; 180 181 private static final String UTF8="UTF-8"; 182 private String fEncoding=UTF8; 183 private boolean fEncoding_is_utf8=true; 184 185 private RequestQueue rq = new RequestQueue(16); 186 187 /** 188 * Specify how many requests may be sent at any one time. 189 * Increasing this value may slightly improve file transfer speed but will 190 * increase memory usage. The default is 16 requests. 191 * 192 * @param bulk_requests how many requests may be outstanding at any one time. 193 */ setBulkRequests(int bulk_requests)194 public void setBulkRequests(int bulk_requests) throws JSchException { 195 if(bulk_requests>0) 196 rq = new RequestQueue(bulk_requests); 197 else 198 throw new JSchException("setBulkRequests: "+ 199 bulk_requests+" must be greater than 0."); 200 } 201 202 /** 203 * This method will return the value how many requests may be 204 * sent at any one time. 205 * 206 * @return how many requests may be sent at any one time. 207 */ getBulkRequests()208 public int getBulkRequests(){ 209 return rq.size(); 210 } 211 ChannelSftp()212 public ChannelSftp(){ 213 super(); 214 setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX); 215 setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX); 216 setLocalPacketSize(LOCAL_MAXIMUM_PACKET_SIZE); 217 } 218 init()219 void init(){ 220 } 221 start()222 public void start() throws JSchException{ 223 try{ 224 225 PipedOutputStream pos=new PipedOutputStream(); 226 io.setOutputStream(pos); 227 PipedInputStream pis=new MyPipedInputStream(pos, rmpsize); 228 io.setInputStream(pis); 229 230 io_in=io.in; 231 232 if(io_in==null){ 233 throw new JSchException("channel is down"); 234 } 235 236 Request request=new RequestSftp(); 237 request.request(getSession(), this); 238 239 /* 240 System.err.println("lmpsize: "+lmpsize); 241 System.err.println("lwsize: "+lwsize); 242 System.err.println("rmpsize: "+rmpsize); 243 System.err.println("rwsize: "+rwsize); 244 */ 245 246 buf=new Buffer(lmpsize); 247 packet=new Packet(buf); 248 249 obuf=new Buffer(rmpsize); 250 opacket=new Packet(obuf); 251 252 int i=0; 253 int length; 254 int type; 255 byte[] str; 256 257 // send SSH_FXP_INIT 258 sendINIT(); 259 260 // receive SSH_FXP_VERSION 261 Header header=new Header(); 262 header=header(buf, header); 263 length=header.length; 264 if(length > MAX_MSG_LENGTH){ 265 throw new SftpException(SSH_FX_FAILURE, 266 "Received message is too long: " + length); 267 } 268 type=header.type; // 2 -> SSH_FXP_VERSION 269 server_version=header.rid; 270 //System.err.println("SFTP protocol server-version="+server_version); 271 extensions=new java.util.Hashtable(); 272 if(length>0){ 273 // extension data 274 fill(buf, length); 275 byte[] extension_name=null; 276 byte[] extension_data=null; 277 while(length>0){ 278 extension_name=buf.getString(); 279 length-=(4+extension_name.length); 280 extension_data=buf.getString(); 281 length-=(4+extension_data.length); 282 extensions.put(Util.byte2str(extension_name), 283 Util.byte2str(extension_data)); 284 } 285 } 286 287 if(extensions.get("posix-rename@openssh.com")!=null && 288 extensions.get("posix-rename@openssh.com").equals("1")){ 289 extension_posix_rename = true; 290 } 291 292 if(extensions.get("statvfs@openssh.com")!=null && 293 extensions.get("statvfs@openssh.com").equals("2")){ 294 extension_statvfs = true; 295 } 296 297 /* 298 if(extensions.get("fstatvfs@openssh.com")!=null && 299 extensions.get("fstatvfs@openssh.com").equals("2")){ 300 extension_fstatvfs = true; 301 } 302 */ 303 304 if(extensions.get("hardlink@openssh.com")!=null && 305 extensions.get("hardlink@openssh.com").equals("1")){ 306 extension_hardlink = true; 307 } 308 309 lcwd=new File(".").getCanonicalPath(); 310 } 311 catch(Exception e){ 312 //System.err.println(e); 313 if(e instanceof JSchException) throw (JSchException)e; 314 if(e instanceof Throwable) 315 throw new JSchException(e.toString(), (Throwable)e); 316 throw new JSchException(e.toString()); 317 } 318 } 319 quit()320 public void quit(){ disconnect();} exit()321 public void exit(){ disconnect();} lcd(String path)322 public void lcd(String path) throws SftpException{ 323 path=localAbsolutePath(path); 324 if((new File(path)).isDirectory()){ 325 try{ 326 path=(new File(path)).getCanonicalPath(); 327 } 328 catch(Exception e){} 329 lcwd=path; 330 return; 331 } 332 throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such directory"); 333 } 334 cd(String path)335 public void cd(String path) throws SftpException{ 336 try{ 337 ((MyPipedInputStream)io_in).updateReadSide(); 338 339 path=remoteAbsolutePath(path); 340 path=isUnique(path); 341 342 byte[] str=_realpath(path); 343 SftpATTRS attr=_stat(str); 344 345 if((attr.getFlags()&SftpATTRS.SSH_FILEXFER_ATTR_PERMISSIONS)==0){ 346 throw new SftpException(SSH_FX_FAILURE, 347 "Can't change directory: "+path); 348 } 349 if(!attr.isDir()){ 350 throw new SftpException(SSH_FX_FAILURE, 351 "Can't change directory: "+path); 352 } 353 354 setCwd(Util.byte2str(str, fEncoding)); 355 } 356 catch(Exception e){ 357 if(e instanceof SftpException) throw (SftpException)e; 358 if(e instanceof Throwable) 359 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 360 throw new SftpException(SSH_FX_FAILURE, ""); 361 } 362 } 363 put(String src, String dst)364 public void put(String src, String dst) throws SftpException{ 365 put(src, dst, null, OVERWRITE); 366 } put(String src, String dst, int mode)367 public void put(String src, String dst, int mode) throws SftpException{ 368 put(src, dst, null, mode); 369 } put(String src, String dst, SftpProgressMonitor monitor)370 public void put(String src, String dst, 371 SftpProgressMonitor monitor) throws SftpException{ 372 put(src, dst, monitor, OVERWRITE); 373 } 374 375 /** 376 * Sends data from <code>src</code> file to <code>dst</code> file. 377 * The <code>mode</code> should be <code>OVERWRITE</code>, 378 * <code>RESUME</code> or <code>APPEND</code>. 379 * 380 * @param src source file 381 * @param dst destination file 382 * @param monitor progress monitor 383 * @param mode how data should be added to dst 384 */ put(String src, String dst, SftpProgressMonitor monitor, int mode)385 public void put(String src, String dst, 386 SftpProgressMonitor monitor, int mode) throws SftpException{ 387 388 try{ 389 ((MyPipedInputStream)io_in).updateReadSide(); 390 391 src=localAbsolutePath(src); 392 dst=remoteAbsolutePath(dst); 393 394 Vector v=glob_remote(dst); 395 int vsize=v.size(); 396 if(vsize!=1){ 397 if(vsize==0){ 398 if(isPattern(dst)) 399 throw new SftpException(SSH_FX_FAILURE, dst); 400 else 401 dst=Util.unquote(dst); 402 } 403 throw new SftpException(SSH_FX_FAILURE, v.toString()); 404 } 405 else{ 406 dst=(String)(v.elementAt(0)); 407 } 408 409 boolean isRemoteDir=isRemoteDir(dst); 410 411 v=glob_local(src); 412 vsize=v.size(); 413 414 StringBuffer dstsb=null; 415 if(isRemoteDir){ 416 if(!dst.endsWith("/")){ 417 dst+="/"; 418 } 419 dstsb=new StringBuffer(dst); 420 } 421 else if(vsize>1){ 422 throw new SftpException(SSH_FX_FAILURE, 423 "Copying multiple files, but the destination is missing or a file."); 424 } 425 426 for(int j=0; j<vsize; j++){ 427 String _src=(String)(v.elementAt(j)); 428 String _dst=null; 429 if(isRemoteDir){ 430 int i=_src.lastIndexOf(file_separatorc); 431 if(fs_is_bs){ 432 int ii=_src.lastIndexOf('/'); 433 if(ii!=-1 && ii>i) 434 i=ii; 435 } 436 if(i==-1) dstsb.append(_src); 437 else dstsb.append(_src.substring(i + 1)); 438 _dst=dstsb.toString(); 439 dstsb.delete(dst.length(), _dst.length()); 440 } 441 else{ 442 _dst=dst; 443 } 444 //System.err.println("_dst "+_dst); 445 446 long size_of_dst=0; 447 if(mode==RESUME){ 448 try{ 449 SftpATTRS attr=_stat(_dst); 450 size_of_dst=attr.getSize(); 451 } 452 catch(Exception eee){ 453 //System.err.println(eee); 454 } 455 long size_of_src=new File(_src).length(); 456 if(size_of_src<size_of_dst){ 457 throw new SftpException(SSH_FX_FAILURE, 458 "failed to resume for "+_dst); 459 } 460 if(size_of_src==size_of_dst){ 461 return; 462 } 463 } 464 465 if(monitor!=null){ 466 monitor.init(SftpProgressMonitor.PUT, _src, _dst, 467 (new File(_src)).length()); 468 if(mode==RESUME){ 469 monitor.count(size_of_dst); 470 } 471 } 472 FileInputStream fis=null; 473 try{ 474 fis=new FileInputStream(_src); 475 _put(fis, _dst, monitor, mode); 476 } 477 finally{ 478 if(fis!=null) { 479 fis.close(); 480 } 481 } 482 } 483 } 484 catch(Exception e){ 485 if(e instanceof SftpException) throw (SftpException)e; 486 if(e instanceof Throwable) 487 throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e); 488 throw new SftpException(SSH_FX_FAILURE, e.toString()); 489 } 490 } put(InputStream src, String dst)491 public void put(InputStream src, String dst) throws SftpException{ 492 put(src, dst, null, OVERWRITE); 493 } put(InputStream src, String dst, int mode)494 public void put(InputStream src, String dst, int mode) throws SftpException{ 495 put(src, dst, null, mode); 496 } put(InputStream src, String dst, SftpProgressMonitor monitor)497 public void put(InputStream src, String dst, 498 SftpProgressMonitor monitor) throws SftpException{ 499 put(src, dst, monitor, OVERWRITE); 500 } 501 502 /** 503 * Sends data from the input stream <code>src</code> to <code>dst</code> file. 504 * The <code>mode</code> should be <code>OVERWRITE</code>, 505 * <code>RESUME</code> or <code>APPEND</code>. 506 * 507 * @param src input stream 508 * @param dst destination file 509 * @param monitor progress monitor 510 * @param mode how data should be added to dst 511 */ put(InputStream src, String dst, SftpProgressMonitor monitor, int mode)512 public void put(InputStream src, String dst, 513 SftpProgressMonitor monitor, int mode) throws SftpException{ 514 try{ 515 ((MyPipedInputStream)io_in).updateReadSide(); 516 517 dst=remoteAbsolutePath(dst); 518 519 Vector v=glob_remote(dst); 520 int vsize=v.size(); 521 if(vsize!=1){ 522 if(vsize==0){ 523 if(isPattern(dst)) 524 throw new SftpException(SSH_FX_FAILURE, dst); 525 else 526 dst=Util.unquote(dst); 527 } 528 throw new SftpException(SSH_FX_FAILURE, v.toString()); 529 } 530 else{ 531 dst=(String)(v.elementAt(0)); 532 } 533 534 if(monitor!=null){ 535 monitor.init(SftpProgressMonitor.PUT, 536 "-", dst, 537 SftpProgressMonitor.UNKNOWN_SIZE); 538 } 539 540 _put(src, dst, monitor, mode); 541 } 542 catch(Exception e){ 543 if(e instanceof SftpException) { 544 if(((SftpException)e).id == SSH_FX_FAILURE && 545 isRemoteDir(dst)) { 546 throw new SftpException(SSH_FX_FAILURE, dst+" is a directory"); 547 } 548 throw (SftpException)e; 549 } 550 if(e instanceof Throwable) 551 throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e); 552 throw new SftpException(SSH_FX_FAILURE, e.toString()); 553 } 554 } 555 _put(InputStream src, String dst, SftpProgressMonitor monitor, int mode)556 public void _put(InputStream src, String dst, 557 SftpProgressMonitor monitor, int mode) throws SftpException{ 558 try{ 559 ((MyPipedInputStream)io_in).updateReadSide(); 560 561 byte[] dstb=Util.str2byte(dst, fEncoding); 562 long skip=0; 563 if(mode==RESUME || mode==APPEND){ 564 try{ 565 SftpATTRS attr=_stat(dstb); 566 skip=attr.getSize(); 567 } 568 catch(Exception eee){ 569 //System.err.println(eee); 570 } 571 } 572 if(mode==RESUME && skip>0){ 573 long skipped=src.skip(skip); 574 if(skipped<skip){ 575 throw new SftpException(SSH_FX_FAILURE, "failed to resume for "+dst); 576 } 577 } 578 579 if(mode==OVERWRITE){ sendOPENW(dstb); } 580 else{ sendOPENA(dstb); } 581 582 Header header=new Header(); 583 header=header(buf, header); 584 int length=header.length; 585 int type=header.type; 586 587 fill(buf, length); 588 589 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){ 590 throw new SftpException(SSH_FX_FAILURE, "invalid type="+type); 591 } 592 if(type==SSH_FXP_STATUS){ 593 int i=buf.getInt(); 594 throwStatusError(buf, i); 595 } 596 byte[] handle=buf.getString(); // handle 597 byte[] data=null; 598 599 boolean dontcopy=true; 600 601 if(!dontcopy){ // This case will not work anymore. 602 data=new byte[obuf.buffer.length 603 -(5+13+21+handle.length+Session.buffer_margin 604 ) 605 ]; 606 } 607 608 long offset=0; 609 if(mode==RESUME || mode==APPEND){ 610 offset+=skip; 611 } 612 613 int startid=seq; 614 int ackcount=0; 615 int _s=0; 616 int _datalen=0; 617 618 if(!dontcopy){ // This case will not work anymore. 619 _datalen=data.length; 620 } 621 else{ 622 data=obuf.buffer; 623 _s=5+13+21+handle.length; 624 _datalen=obuf.buffer.length-_s-Session.buffer_margin; 625 } 626 627 int bulk_requests = rq.size(); 628 629 while(true){ 630 int nread=0; 631 int count=0; 632 int s=_s; 633 int datalen=_datalen; 634 635 do{ 636 nread=src.read(data, s, datalen); 637 if(nread>0){ 638 s+=nread; 639 datalen-=nread; 640 count+=nread; 641 } 642 } 643 while(datalen>0 && nread>0); 644 if(count<=0)break; 645 646 int foo=count; 647 while(foo>0){ 648 if((seq-1)==startid || 649 ((seq-startid)-ackcount)>=bulk_requests){ 650 while(((seq-startid)-ackcount)>=bulk_requests){ 651 if(checkStatus(ackid, header)){ 652 int _ackid = ackid[0]; 653 if(startid>_ackid || _ackid>seq-1){ 654 if(_ackid==seq){ 655 System.err.println("ack error: startid="+startid+" seq="+seq+" _ackid="+_ackid); 656 } 657 else{ 658 throw new SftpException(SSH_FX_FAILURE, "ack error: startid="+startid+" seq="+seq+" _ackid="+_ackid); 659 } 660 } 661 ackcount++; 662 } 663 else{ 664 break; 665 } 666 } 667 } 668 foo-=sendWRITE(handle, offset, data, 0, foo); 669 } 670 offset+=count; 671 if(monitor!=null && !monitor.count(count)){ 672 break; 673 } 674 } 675 int _ackcount=seq-startid; 676 while(_ackcount>ackcount){ 677 if(!checkStatus(null, header)){ 678 break; 679 } 680 ackcount++; 681 } 682 if(monitor!=null)monitor.end(); 683 _sendCLOSE(handle, header); 684 } 685 catch(Exception e){ 686 if(e instanceof SftpException) throw (SftpException)e; 687 if(e instanceof Throwable) 688 throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e); 689 throw new SftpException(SSH_FX_FAILURE, e.toString()); 690 } 691 } 692 put(String dst)693 public OutputStream put(String dst) throws SftpException{ 694 return put(dst, (SftpProgressMonitor)null, OVERWRITE); 695 } put(String dst, final int mode)696 public OutputStream put(String dst, final int mode) throws SftpException{ 697 return put(dst, (SftpProgressMonitor)null, mode); 698 } put(String dst, final SftpProgressMonitor monitor, final int mode)699 public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode) throws SftpException{ 700 return put(dst, monitor, mode, 0); 701 } 702 703 /** 704 * Sends data from the output stream to <code>dst</code> file. 705 * The <code>mode</code> should be <code>OVERWRITE</code>, 706 * <code>RESUME</code> or <code>APPEND</code>. 707 * 708 * @param dst destination file 709 * @param monitor progress monitor 710 * @param mode how data should be added to dst 711 * @param offset data will be added at offset 712 * @return output stream, which accepts data to be transferred. 713 */ put(String dst, final SftpProgressMonitor monitor, final int mode, long offset)714 public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode, long offset) throws SftpException{ 715 try{ 716 ((MyPipedInputStream)io_in).updateReadSide(); 717 718 dst=remoteAbsolutePath(dst); 719 dst=isUnique(dst); 720 721 if(isRemoteDir(dst)){ 722 throw new SftpException(SSH_FX_FAILURE, dst+" is a directory"); 723 } 724 725 byte[] dstb=Util.str2byte(dst, fEncoding); 726 727 long skip=0; 728 if(mode==RESUME || mode==APPEND){ 729 try{ 730 SftpATTRS attr=_stat(dstb); 731 skip=attr.getSize(); 732 } 733 catch(Exception eee){ 734 //System.err.println(eee); 735 } 736 } 737 738 if(mode==OVERWRITE){ sendOPENW(dstb); } 739 else{ sendOPENA(dstb); } 740 741 Header header=new Header(); 742 header=header(buf, header); 743 int length=header.length; 744 int type=header.type; 745 746 fill(buf, length); 747 748 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){ 749 throw new SftpException(SSH_FX_FAILURE, ""); 750 } 751 if(type==SSH_FXP_STATUS){ 752 int i=buf.getInt(); 753 throwStatusError(buf, i); 754 } 755 final byte[] handle=buf.getString(); // handle 756 757 if(mode==RESUME || mode==APPEND){ 758 offset+=skip; 759 } 760 761 final long[] _offset=new long[1]; 762 _offset[0]=offset; 763 OutputStream out = new OutputStream(){ 764 private boolean init=true; 765 private boolean isClosed=false; 766 private int[] ackid=new int[1]; 767 private int startid=0; 768 private int _ackid=0; 769 private int ackcount=0; 770 private int writecount=0; 771 private Header header=new Header(); 772 773 public void write(byte[] d) throws java.io.IOException{ 774 write(d, 0, d.length); 775 } 776 777 public void write(byte[] d, int s, int len) throws java.io.IOException{ 778 if(init){ 779 startid=seq; 780 _ackid=seq; 781 init=false; 782 } 783 784 if(isClosed){ 785 throw new IOException("stream already closed"); 786 } 787 788 try{ 789 int _len=len; 790 while(_len>0){ 791 int sent=sendWRITE(handle, _offset[0], d, s, _len); 792 writecount++; 793 _offset[0]+=sent; 794 s+=sent; 795 _len-=sent; 796 if((seq-1)==startid || 797 io_in.available()>=1024){ 798 while(io_in.available()>0){ 799 if(checkStatus(ackid, header)){ 800 _ackid=ackid[0]; 801 if(startid>_ackid || _ackid>seq-1){ 802 throw new SftpException(SSH_FX_FAILURE, ""); 803 } 804 ackcount++; 805 } 806 else{ 807 break; 808 } 809 } 810 } 811 } 812 if(monitor!=null && !monitor.count(len)){ 813 close(); 814 throw new IOException("canceled"); 815 } 816 } 817 catch(IOException e){ throw e; } 818 catch(Exception e){ throw new IOException(e.toString()); } 819 } 820 821 byte[] _data=new byte[1]; 822 public void write(int foo) throws java.io.IOException{ 823 _data[0]=(byte)foo; 824 write(_data, 0, 1); 825 } 826 827 public void flush() throws java.io.IOException{ 828 829 if(isClosed){ 830 throw new IOException("stream already closed"); 831 } 832 833 if(!init){ 834 try{ 835 while(writecount>ackcount){ 836 if(!checkStatus(null, header)){ 837 break; 838 } 839 ackcount++; 840 } 841 } 842 catch(SftpException e){ 843 throw new IOException(e.toString()); 844 } 845 } 846 } 847 848 public void close() throws java.io.IOException{ 849 if(isClosed){ 850 return; 851 } 852 flush(); 853 if(monitor!=null)monitor.end(); 854 try{ _sendCLOSE(handle, header); } 855 catch(IOException e){ throw e; } 856 catch(Exception e){ 857 throw new IOException(e.toString()); 858 } 859 isClosed=true; 860 } 861 }; 862 return out; 863 } 864 catch(Exception e){ 865 if(e instanceof SftpException) throw (SftpException)e; 866 if(e instanceof Throwable) 867 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 868 throw new SftpException(SSH_FX_FAILURE, ""); 869 } 870 } 871 get(String src, String dst)872 public void get(String src, String dst) throws SftpException{ 873 get(src, dst, null, OVERWRITE); 874 } get(String src, String dst, SftpProgressMonitor monitor)875 public void get(String src, String dst, 876 SftpProgressMonitor monitor) throws SftpException{ 877 get(src, dst, monitor, OVERWRITE); 878 } get(String src, String dst, SftpProgressMonitor monitor, int mode)879 public void get(String src, String dst, 880 SftpProgressMonitor monitor, int mode) throws SftpException{ 881 // System.out.println("get: "+src+" "+dst); 882 883 boolean _dstExist = false; 884 String _dst=null; 885 try{ 886 ((MyPipedInputStream)io_in).updateReadSide(); 887 888 src=remoteAbsolutePath(src); 889 dst=localAbsolutePath(dst); 890 891 Vector v=glob_remote(src); 892 int vsize=v.size(); 893 if(vsize==0){ 894 throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such file"); 895 } 896 897 File dstFile=new File(dst); 898 boolean isDstDir=dstFile.isDirectory(); 899 StringBuffer dstsb=null; 900 if(isDstDir){ 901 if(!dst.endsWith(file_separator)){ 902 dst+=file_separator; 903 } 904 dstsb=new StringBuffer(dst); 905 } 906 else if(vsize>1){ 907 throw new SftpException(SSH_FX_FAILURE, 908 "Copying multiple files, but destination is missing or a file."); 909 } 910 911 for(int j=0; j<vsize; j++){ 912 String _src=(String)(v.elementAt(j)); 913 SftpATTRS attr=_stat(_src); 914 if(attr.isDir()){ 915 throw new SftpException(SSH_FX_FAILURE, 916 "not supported to get directory "+_src); 917 } 918 919 _dst=null; 920 if(isDstDir){ 921 int i=_src.lastIndexOf('/'); 922 if(i==-1) dstsb.append(_src); 923 else dstsb.append(_src.substring(i + 1)); 924 _dst=dstsb.toString(); 925 dstsb.delete(dst.length(), _dst.length()); 926 } 927 else{ 928 _dst=dst; 929 } 930 931 File _dstFile=new File(_dst); 932 if(mode==RESUME){ 933 long size_of_src=attr.getSize(); 934 long size_of_dst=_dstFile.length(); 935 if(size_of_dst>size_of_src){ 936 throw new SftpException(SSH_FX_FAILURE, 937 "failed to resume for "+_dst); 938 } 939 if(size_of_dst==size_of_src){ 940 return; 941 } 942 } 943 944 if(monitor!=null){ 945 monitor.init(SftpProgressMonitor.GET, _src, _dst, attr.getSize()); 946 if(mode==RESUME){ 947 monitor.count(_dstFile.length()); 948 } 949 } 950 951 FileOutputStream fos=null; 952 _dstExist = _dstFile.exists(); 953 try{ 954 if(mode==OVERWRITE){ 955 fos=new FileOutputStream(_dst); 956 } 957 else{ 958 fos=new FileOutputStream(_dst, true); // append 959 } 960 // System.err.println("_get: "+_src+", "+_dst); 961 _get(_src, fos, monitor, mode, new File(_dst).length()); 962 } 963 finally{ 964 if(fos!=null){ 965 fos.close(); 966 } 967 } 968 } 969 } 970 catch(Exception e){ 971 if(!_dstExist && _dst!=null){ 972 File _dstFile = new File(_dst); 973 if(_dstFile.exists() && _dstFile.length()==0){ 974 _dstFile.delete(); 975 } 976 } 977 if(e instanceof SftpException) throw (SftpException)e; 978 if(e instanceof Throwable) 979 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 980 throw new SftpException(SSH_FX_FAILURE, ""); 981 } 982 } get(String src, OutputStream dst)983 public void get(String src, OutputStream dst) throws SftpException{ 984 get(src, dst, null, OVERWRITE, 0); 985 } get(String src, OutputStream dst, SftpProgressMonitor monitor)986 public void get(String src, OutputStream dst, 987 SftpProgressMonitor monitor) throws SftpException{ 988 get(src, dst, monitor, OVERWRITE, 0); 989 } get(String src, OutputStream dst, SftpProgressMonitor monitor, int mode, long skip)990 public void get(String src, OutputStream dst, 991 SftpProgressMonitor monitor, int mode, long skip) throws SftpException{ 992 //System.err.println("get: "+src+", "+dst); 993 try{ 994 ((MyPipedInputStream)io_in).updateReadSide(); 995 996 src=remoteAbsolutePath(src); 997 src=isUnique(src); 998 999 if(monitor!=null){ 1000 SftpATTRS attr=_stat(src); 1001 monitor.init(SftpProgressMonitor.GET, src, "??", attr.getSize()); 1002 if(mode==RESUME){ 1003 monitor.count(skip); 1004 } 1005 } 1006 _get(src, dst, monitor, mode, skip); 1007 } 1008 catch(Exception e){ 1009 if(e instanceof SftpException) throw (SftpException)e; 1010 if(e instanceof Throwable) 1011 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 1012 throw new SftpException(SSH_FX_FAILURE, ""); 1013 } 1014 } 1015 _get(String src, OutputStream dst, SftpProgressMonitor monitor, int mode, long skip)1016 private void _get(String src, OutputStream dst, 1017 SftpProgressMonitor monitor, int mode, long skip) throws SftpException{ 1018 //System.err.println("_get: "+src+", "+dst); 1019 1020 byte[] srcb=Util.str2byte(src, fEncoding); 1021 try{ 1022 sendOPENR(srcb); 1023 1024 Header header=new Header(); 1025 header=header(buf, header); 1026 int length=header.length; 1027 int type=header.type; 1028 1029 fill(buf, length); 1030 1031 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){ 1032 throw new SftpException(SSH_FX_FAILURE, ""); 1033 } 1034 1035 if(type==SSH_FXP_STATUS){ 1036 int i=buf.getInt(); 1037 throwStatusError(buf, i); 1038 } 1039 1040 byte[] handle=buf.getString(); // filename 1041 1042 long offset=0; 1043 if(mode==RESUME){ 1044 offset+=skip; 1045 } 1046 1047 int request_max=1; 1048 rq.init(); 1049 long request_offset=offset; 1050 1051 int request_len = buf.buffer.length-13; 1052 if(server_version==0){ request_len=1024; } 1053 1054 loop: 1055 while(true){ 1056 1057 while(rq.count() < request_max){ 1058 sendREAD(handle, request_offset, request_len, rq); 1059 request_offset += request_len; 1060 } 1061 1062 header=header(buf, header); 1063 length=header.length; 1064 type=header.type; 1065 1066 RequestQueue.Request rr = null; 1067 try{ 1068 rr = rq.get(header.rid); 1069 } 1070 catch(RequestQueue.OutOfOrderException e){ 1071 request_offset = e.offset; 1072 skip(header.length); 1073 rq.cancel(header, buf); 1074 continue; 1075 } 1076 1077 if(type==SSH_FXP_STATUS){ 1078 fill(buf, length); 1079 int i=buf.getInt(); 1080 if(i==SSH_FX_EOF){ 1081 break loop; 1082 } 1083 throwStatusError(buf, i); 1084 } 1085 1086 if(type!=SSH_FXP_DATA){ 1087 break loop; 1088 } 1089 1090 buf.rewind(); 1091 fill(buf.buffer, 0, 4); length-=4; 1092 int length_of_data = buf.getInt(); // length of data 1093 1094 /** 1095 Since sftp protocol version 6, "end-of-file" has been defined, 1096 1097 byte SSH_FXP_DATA 1098 uint32 request-id 1099 string data 1100 bool end-of-file [optional] 1101 1102 but some sftpd server will send such a field in the sftp protocol 3 ;-( 1103 */ 1104 int optional_data = length - length_of_data; 1105 1106 int foo = length_of_data; 1107 while(foo>0){ 1108 int bar=foo; 1109 if(bar>buf.buffer.length){ 1110 bar=buf.buffer.length; 1111 } 1112 int data_len = io_in.read(buf.buffer, 0, bar); 1113 if(data_len<0){ 1114 break loop; 1115 } 1116 1117 dst.write(buf.buffer, 0, data_len); 1118 1119 offset+=data_len; 1120 foo-=data_len; 1121 1122 if(monitor!=null){ 1123 if(!monitor.count(data_len)){ 1124 skip(foo); 1125 if(optional_data>0){ 1126 skip(optional_data); 1127 } 1128 break loop; 1129 } 1130 } 1131 1132 } 1133 //System.err.println("length: "+length); // length should be 0 1134 1135 if(optional_data>0){ 1136 skip(optional_data); 1137 } 1138 1139 if(length_of_data<rr.length){ // 1140 rq.cancel(header, buf); 1141 sendREAD(handle, rr.offset+length_of_data, (int)(rr.length-length_of_data), rq); 1142 request_offset=rr.offset+rr.length; 1143 } 1144 1145 if(request_max < rq.size()){ 1146 request_max++; 1147 } 1148 } 1149 dst.flush(); 1150 1151 if(monitor!=null)monitor.end(); 1152 1153 rq.cancel(header, buf); 1154 1155 _sendCLOSE(handle, header); 1156 } 1157 catch(Exception e){ 1158 if(e instanceof SftpException) throw (SftpException)e; 1159 if(e instanceof Throwable) 1160 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 1161 throw new SftpException(SSH_FX_FAILURE, ""); 1162 } 1163 } 1164 1165 1166 private class RequestQueue { 1167 class OutOfOrderException extends Exception { 1168 long offset; OutOfOrderException(long offset)1169 OutOfOrderException(long offset){ 1170 this.offset=offset; 1171 } 1172 } 1173 class Request { 1174 int id; 1175 long offset; 1176 long length; 1177 } 1178 1179 Request[] rrq=null; 1180 int head, count; RequestQueue(int size)1181 RequestQueue(int size){ 1182 rrq = new Request[size]; 1183 for(int i=0; i<rrq.length; i++){ 1184 rrq[i]=new Request(); 1185 } 1186 init(); 1187 } 1188 init()1189 void init(){ 1190 head=count=0; 1191 } 1192 add(int id, long offset, int length)1193 void add(int id, long offset, int length){ 1194 if(count == 0) head = 0; 1195 int tail = head + count; 1196 if(tail>=rrq.length) tail -= rrq.length; 1197 rrq[tail].id=id; 1198 rrq[tail].offset=offset; 1199 rrq[tail].length=length; 1200 count++; 1201 } 1202 get(int id)1203 Request get(int id) throws OutOfOrderException, SftpException { 1204 count -= 1; 1205 int i = head; 1206 head++; 1207 if(head==rrq.length) head=0; 1208 if(rrq[i].id != id){ 1209 long offset = getOffset(); 1210 boolean find = false; 1211 for(int j = 0; j<rrq.length; j++){ 1212 if(rrq[j].id == id){ 1213 find = true; 1214 rrq[j].id = 0; 1215 break; 1216 } 1217 } 1218 if(find) 1219 throw new OutOfOrderException(offset); 1220 throw new SftpException(SSH_FX_FAILURE, 1221 "RequestQueue: unknown request id "+id); 1222 } 1223 rrq[i].id = 0; 1224 return rrq[i]; 1225 } 1226 count()1227 int count() { 1228 return count; 1229 } 1230 size()1231 int size() { 1232 return rrq.length; 1233 } 1234 cancel(Header header, Buffer buf)1235 void cancel(Header header, Buffer buf) throws IOException { 1236 int _count = count; 1237 for(int i=0; i<_count; i++){ 1238 header=header(buf, header); 1239 int length=header.length; 1240 for(int j=0; j<rrq.length; j++){ 1241 if(rrq[j].id == header.rid){ 1242 rrq[j].id=0; 1243 break; 1244 } 1245 } 1246 skip(length); 1247 } 1248 init(); 1249 } 1250 getOffset()1251 long getOffset(){ 1252 long result = Long.MAX_VALUE; 1253 1254 for(int i=0; i<rrq.length; i++){ 1255 if(rrq[i].id == 0) 1256 continue; 1257 if(result>rrq[i].offset) 1258 result=rrq[i].offset; 1259 } 1260 1261 return result; 1262 } 1263 } 1264 get(String src)1265 public InputStream get(String src) throws SftpException{ 1266 return get(src, null, 0L); 1267 } get(String src, SftpProgressMonitor monitor)1268 public InputStream get(String src, SftpProgressMonitor monitor) throws SftpException{ 1269 return get(src, monitor, 0L); 1270 } 1271 1272 /** 1273 * @deprecated This method will be deleted in the future. 1274 */ get(String src, int mode)1275 public InputStream get(String src, int mode) throws SftpException{ 1276 return get(src, null, 0L); 1277 } 1278 /** 1279 * @deprecated This method will be deleted in the future. 1280 */ get(String src, final SftpProgressMonitor monitor, final int mode)1281 public InputStream get(String src, final SftpProgressMonitor monitor, final int mode) throws SftpException{ 1282 return get(src, monitor, 0L); 1283 } get(String src, final SftpProgressMonitor monitor, final long skip)1284 public InputStream get(String src, final SftpProgressMonitor monitor, final long skip) throws SftpException{ 1285 1286 try{ 1287 ((MyPipedInputStream)io_in).updateReadSide(); 1288 1289 src=remoteAbsolutePath(src); 1290 src=isUnique(src); 1291 1292 byte[] srcb=Util.str2byte(src, fEncoding); 1293 1294 SftpATTRS attr=_stat(srcb); 1295 if(monitor!=null){ 1296 monitor.init(SftpProgressMonitor.GET, src, "??", attr.getSize()); 1297 } 1298 1299 sendOPENR(srcb); 1300 1301 Header header=new Header(); 1302 header=header(buf, header); 1303 int length=header.length; 1304 int type=header.type; 1305 1306 fill(buf, length); 1307 1308 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){ 1309 throw new SftpException(SSH_FX_FAILURE, ""); 1310 } 1311 if(type==SSH_FXP_STATUS){ 1312 int i=buf.getInt(); 1313 throwStatusError(buf, i); 1314 } 1315 1316 final byte[] handle=buf.getString(); // handle 1317 1318 rq.init(); 1319 1320 java.io.InputStream in=new java.io.InputStream(){ 1321 long offset=skip; 1322 boolean closed=false; 1323 int rest_length=0; 1324 byte[] _data=new byte[1]; 1325 byte[] rest_byte=new byte[1024]; 1326 Header header=new Header(); 1327 int request_max=1; 1328 long request_offset=offset; 1329 1330 public int read() throws java.io.IOException{ 1331 if(closed)return -1; 1332 int i=read(_data, 0, 1); 1333 if (i==-1) { return -1; } 1334 else { 1335 return _data[0]&0xff; 1336 } 1337 } 1338 public int read(byte[] d) throws java.io.IOException{ 1339 if(closed)return -1; 1340 return read(d, 0, d.length); 1341 } 1342 public int read(byte[] d, int s, int len) throws java.io.IOException{ 1343 if(closed)return -1; 1344 if(d==null){throw new NullPointerException();} 1345 if(s<0 || len <0 || s+len>d.length){ 1346 throw new IndexOutOfBoundsException(); 1347 } 1348 if(len==0){ return 0; } 1349 1350 if(rest_length>0){ 1351 int foo=rest_length; 1352 if(foo>len) foo=len; 1353 System.arraycopy(rest_byte, 0, d, s, foo); 1354 if(foo!=rest_length){ 1355 System.arraycopy(rest_byte, foo, 1356 rest_byte, 0, rest_length-foo); 1357 } 1358 1359 if(monitor!=null){ 1360 if(!monitor.count(foo)){ 1361 close(); 1362 return -1; 1363 } 1364 } 1365 1366 rest_length-=foo; 1367 return foo; 1368 } 1369 1370 if(buf.buffer.length-13<len){ 1371 len=buf.buffer.length-13; 1372 } 1373 if(server_version==0 && len>1024){ 1374 len=1024; 1375 } 1376 1377 if(rq.count()==0) { 1378 int request_len = buf.buffer.length-13; 1379 if(server_version==0){ request_len=1024; } 1380 1381 while(rq.count() < request_max){ 1382 try{ 1383 sendREAD(handle, request_offset, request_len, rq); 1384 } 1385 catch(Exception e){ throw new IOException("error"); } 1386 request_offset += request_len; 1387 } 1388 } 1389 1390 header=header(buf, header); 1391 rest_length=header.length; 1392 int type=header.type; 1393 int id=header.rid; 1394 1395 RequestQueue.Request rr = null; 1396 try{ 1397 rr = rq.get(header.rid); 1398 } 1399 catch(RequestQueue.OutOfOrderException e){ 1400 request_offset = e.offset; 1401 skip(header.length); 1402 rq.cancel(header, buf); 1403 return 0; 1404 } 1405 catch(SftpException e){ 1406 throw new IOException("error: "+e.toString()); 1407 } 1408 1409 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_DATA){ 1410 throw new IOException("error"); 1411 } 1412 if(type==SSH_FXP_STATUS){ 1413 fill(buf, rest_length); 1414 int i=buf.getInt(); 1415 rest_length=0; 1416 if(i==SSH_FX_EOF){ 1417 close(); 1418 return -1; 1419 } 1420 //throwStatusError(buf, i); 1421 throw new IOException("error"); 1422 } 1423 1424 buf.rewind(); 1425 fill(buf.buffer, 0, 4); 1426 int length_of_data = buf.getInt(); rest_length-=4; 1427 1428 /** 1429 Since sftp protocol version 6, "end-of-file" has been defined, 1430 1431 byte SSH_FXP_DATA 1432 uint32 request-id 1433 string data 1434 bool end-of-file [optional] 1435 1436 but some sftpd server will send such a field in the sftp protocol 3 ;-( 1437 */ 1438 int optional_data = rest_length - length_of_data; 1439 1440 offset += length_of_data; 1441 int foo = length_of_data; 1442 if(foo>0){ 1443 int bar=foo; 1444 if(bar>len){ 1445 bar=len; 1446 } 1447 int i=io_in.read(d, s, bar); 1448 if(i<0){ 1449 return -1; 1450 } 1451 foo-=i; 1452 rest_length=foo; 1453 1454 if(foo>0){ 1455 if(rest_byte.length<foo){ 1456 rest_byte=new byte[foo]; 1457 } 1458 int _s=0; 1459 int _len=foo; 1460 int j; 1461 while(_len>0){ 1462 j=io_in.read(rest_byte, _s, _len); 1463 if(j<=0)break; 1464 _s+=j; 1465 _len-=j; 1466 } 1467 } 1468 1469 if(optional_data>0){ 1470 io_in.skip(optional_data); 1471 } 1472 1473 if(length_of_data<rr.length){ // 1474 rq.cancel(header, buf); 1475 try { 1476 sendREAD(handle, 1477 rr.offset+length_of_data, 1478 (int)(rr.length-length_of_data), rq); 1479 } 1480 catch(Exception e){ throw new IOException("error"); } 1481 request_offset=rr.offset+rr.length; 1482 } 1483 1484 if(request_max < rq.size()){ 1485 request_max++; 1486 } 1487 1488 if(monitor!=null){ 1489 if(!monitor.count(i)){ 1490 close(); 1491 return -1; 1492 } 1493 } 1494 1495 return i; 1496 } 1497 return 0; // ?? 1498 } 1499 public void close() throws IOException{ 1500 if(closed)return; 1501 closed=true; 1502 if(monitor!=null)monitor.end(); 1503 rq.cancel(header, buf); 1504 try{_sendCLOSE(handle, header);} 1505 catch(Exception e){throw new IOException("error");} 1506 } 1507 }; 1508 return in; 1509 } 1510 catch(Exception e){ 1511 if(e instanceof SftpException) throw (SftpException)e; 1512 if(e instanceof Throwable) 1513 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 1514 throw new SftpException(SSH_FX_FAILURE, ""); 1515 } 1516 } 1517 ls(String path)1518 public java.util.Vector ls(String path) throws SftpException{ 1519 final java.util.Vector v = new Vector(); 1520 LsEntrySelector selector = new LsEntrySelector(){ 1521 public int select(LsEntry entry){ 1522 v.addElement(entry); 1523 return CONTINUE; 1524 } 1525 }; 1526 ls(path, selector); 1527 return v; 1528 } 1529 1530 /** 1531 * List files specified by the remote <code>path</code>. 1532 * Each files and directories will be passed to 1533 * <code>LsEntrySelector#select(LsEntry)</code> method, and if that method 1534 * returns <code>LsEntrySelector#BREAK</code>, the operation will be 1535 * canceled immediately. 1536 * 1537 * @see ChannelSftp.LsEntrySelector 1538 * @since 0.1.47 1539 */ ls(String path, LsEntrySelector selector)1540 public void ls(String path, LsEntrySelector selector) throws SftpException{ 1541 //System.out.println("ls: "+path); 1542 try{ 1543 ((MyPipedInputStream)io_in).updateReadSide(); 1544 1545 path=remoteAbsolutePath(path); 1546 byte[] pattern=null; 1547 java.util.Vector v=new java.util.Vector(); 1548 1549 int foo=path.lastIndexOf('/'); 1550 String dir=path.substring(0, ((foo==0)?1:foo)); 1551 String _pattern=path.substring(foo+1); 1552 dir=Util.unquote(dir); 1553 1554 // If pattern has included '*' or '?', we need to convert 1555 // to UTF-8 string before globbing. 1556 byte[][] _pattern_utf8=new byte[1][]; 1557 boolean pattern_has_wildcard=isPattern(_pattern, _pattern_utf8); 1558 1559 if(pattern_has_wildcard){ 1560 pattern=_pattern_utf8[0]; 1561 } 1562 else{ 1563 String upath=Util.unquote(path); 1564 //SftpATTRS attr=_lstat(upath); 1565 SftpATTRS attr=_stat(upath); 1566 if(attr.isDir()){ 1567 pattern=null; 1568 dir=upath; 1569 } 1570 else{ 1571 /* 1572 // If we can generage longname by ourself, 1573 // we don't have to use openDIR. 1574 String filename=Util.unquote(_pattern); 1575 String longname=... 1576 v.addElement(new LsEntry(filename, longname, attr)); 1577 return v; 1578 */ 1579 1580 if(fEncoding_is_utf8){ 1581 pattern=_pattern_utf8[0]; 1582 pattern=Util.unquote(pattern); 1583 } 1584 else{ 1585 _pattern=Util.unquote(_pattern); 1586 pattern=Util.str2byte(_pattern, fEncoding); 1587 } 1588 1589 } 1590 } 1591 1592 sendOPENDIR(Util.str2byte(dir, fEncoding)); 1593 1594 Header header=new Header(); 1595 header=header(buf, header); 1596 int length=header.length; 1597 int type=header.type; 1598 1599 fill(buf, length); 1600 1601 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){ 1602 throw new SftpException(SSH_FX_FAILURE, ""); 1603 } 1604 if(type==SSH_FXP_STATUS){ 1605 int i=buf.getInt(); 1606 throwStatusError(buf, i); 1607 } 1608 1609 int cancel = LsEntrySelector.CONTINUE; 1610 byte[] handle=buf.getString(); // handle 1611 1612 while(cancel==LsEntrySelector.CONTINUE){ 1613 1614 sendREADDIR(handle); 1615 1616 header=header(buf, header); 1617 length=header.length; 1618 type=header.type; 1619 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){ 1620 throw new SftpException(SSH_FX_FAILURE, ""); 1621 } 1622 if(type==SSH_FXP_STATUS){ 1623 fill(buf, length); 1624 int i=buf.getInt(); 1625 if(i==SSH_FX_EOF) 1626 break; 1627 throwStatusError(buf, i); 1628 } 1629 1630 buf.rewind(); 1631 fill(buf.buffer, 0, 4); length-=4; 1632 int count=buf.getInt(); 1633 1634 byte[] str; 1635 int flags; 1636 1637 buf.reset(); 1638 while(count>0){ 1639 if(length>0){ 1640 buf.shift(); 1641 int j=(buf.buffer.length>(buf.index+length)) ? 1642 length : 1643 (buf.buffer.length-buf.index); 1644 int i=fill(buf.buffer, buf.index, j); 1645 buf.index+=i; 1646 length-=i; 1647 } 1648 byte[] filename=buf.getString(); 1649 byte[] longname=null; 1650 if(server_version<=3){ 1651 longname=buf.getString(); 1652 } 1653 SftpATTRS attrs=SftpATTRS.getATTR(buf); 1654 1655 if(cancel==LsEntrySelector.BREAK){ 1656 count--; 1657 continue; 1658 } 1659 1660 boolean find=false; 1661 String f=null; 1662 if(pattern==null){ 1663 find=true; 1664 } 1665 else if(!pattern_has_wildcard){ 1666 find=Util.array_equals(pattern, filename); 1667 } 1668 else{ 1669 byte[] _filename=filename; 1670 if(!fEncoding_is_utf8){ 1671 f=Util.byte2str(_filename, fEncoding); 1672 _filename=Util.str2byte(f, UTF8); 1673 } 1674 find=Util.glob(pattern, _filename); 1675 } 1676 1677 if(find){ 1678 if(f==null){ 1679 f=Util.byte2str(filename, fEncoding); 1680 } 1681 String l=null; 1682 if(longname==null){ 1683 // TODO: we need to generate long name from attrs 1684 // for the sftp protocol 4(and later). 1685 l=attrs.toString()+" "+f; 1686 } 1687 else{ 1688 l=Util.byte2str(longname, fEncoding); 1689 } 1690 1691 cancel = selector.select(new LsEntry(f, l, attrs)); 1692 } 1693 1694 count--; 1695 } 1696 } 1697 _sendCLOSE(handle, header); 1698 1699 /* 1700 if(v.size()==1 && pattern_has_wildcard){ 1701 LsEntry le=(LsEntry)v.elementAt(0); 1702 if(le.getAttrs().isDir()){ 1703 String f=le.getFilename(); 1704 if(isPattern(f)){ 1705 f=Util.quote(f); 1706 } 1707 if(!dir.endsWith("/")){ 1708 dir+="/"; 1709 } 1710 v=null; 1711 return ls(dir+f); 1712 } 1713 } 1714 */ 1715 1716 } 1717 catch(Exception e){ 1718 if(e instanceof SftpException) throw (SftpException)e; 1719 if(e instanceof Throwable) 1720 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 1721 throw new SftpException(SSH_FX_FAILURE, ""); 1722 } 1723 } 1724 readlink(String path)1725 public String readlink(String path) throws SftpException{ 1726 try{ 1727 if(server_version<3){ 1728 throw new SftpException(SSH_FX_OP_UNSUPPORTED, 1729 "The remote sshd is too old to support symlink operation."); 1730 } 1731 1732 ((MyPipedInputStream)io_in).updateReadSide(); 1733 1734 path=remoteAbsolutePath(path); 1735 1736 path=isUnique(path); 1737 1738 sendREADLINK(Util.str2byte(path, fEncoding)); 1739 1740 Header header=new Header(); 1741 header=header(buf, header); 1742 int length=header.length; 1743 int type=header.type; 1744 1745 fill(buf, length); 1746 1747 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){ 1748 throw new SftpException(SSH_FX_FAILURE, ""); 1749 } 1750 if(type==SSH_FXP_NAME){ 1751 int count=buf.getInt(); // count 1752 byte[] filename=null; 1753 for(int i=0; i<count; i++){ 1754 filename=buf.getString(); 1755 if(server_version<=3){ 1756 byte[] longname=buf.getString(); 1757 } 1758 SftpATTRS.getATTR(buf); 1759 } 1760 return Util.byte2str(filename, fEncoding); 1761 } 1762 1763 int i=buf.getInt(); 1764 throwStatusError(buf, i); 1765 } 1766 catch(Exception e){ 1767 if(e instanceof SftpException) throw (SftpException)e; 1768 if(e instanceof Throwable) 1769 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 1770 throw new SftpException(SSH_FX_FAILURE, ""); 1771 } 1772 return null; 1773 } 1774 symlink(String oldpath, String newpath)1775 public void symlink(String oldpath, String newpath) throws SftpException{ 1776 if(server_version<3){ 1777 throw new SftpException(SSH_FX_OP_UNSUPPORTED, 1778 "The remote sshd is too old to support symlink operation."); 1779 } 1780 1781 try{ 1782 ((MyPipedInputStream)io_in).updateReadSide(); 1783 1784 String _oldpath=remoteAbsolutePath(oldpath); 1785 newpath=remoteAbsolutePath(newpath); 1786 1787 _oldpath=isUnique(_oldpath); 1788 if(oldpath.charAt(0)!='/'){ // relative path 1789 String cwd=getCwd(); 1790 oldpath=_oldpath.substring(cwd.length()+(cwd.endsWith("/")?0:1)); 1791 } 1792 else { 1793 oldpath=_oldpath; 1794 } 1795 1796 if(isPattern(newpath)){ 1797 throw new SftpException(SSH_FX_FAILURE, newpath); 1798 } 1799 newpath=Util.unquote(newpath); 1800 1801 sendSYMLINK(Util.str2byte(oldpath, fEncoding), 1802 Util.str2byte(newpath, fEncoding)); 1803 1804 Header header=new Header(); 1805 header=header(buf, header); 1806 int length=header.length; 1807 int type=header.type; 1808 1809 fill(buf, length); 1810 1811 if(type!=SSH_FXP_STATUS){ 1812 throw new SftpException(SSH_FX_FAILURE, ""); 1813 } 1814 1815 int i=buf.getInt(); 1816 if(i==SSH_FX_OK) return; 1817 throwStatusError(buf, i); 1818 } 1819 catch(Exception e){ 1820 if(e instanceof SftpException) throw (SftpException)e; 1821 if(e instanceof Throwable) 1822 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 1823 throw new SftpException(SSH_FX_FAILURE, ""); 1824 } 1825 } 1826 hardlink(String oldpath, String newpath)1827 public void hardlink(String oldpath, String newpath) throws SftpException{ 1828 if(!extension_hardlink){ 1829 throw new SftpException(SSH_FX_OP_UNSUPPORTED, 1830 "hardlink@openssh.com is not supported"); 1831 } 1832 1833 try{ 1834 ((MyPipedInputStream)io_in).updateReadSide(); 1835 1836 String _oldpath=remoteAbsolutePath(oldpath); 1837 newpath=remoteAbsolutePath(newpath); 1838 1839 _oldpath=isUnique(_oldpath); 1840 if(oldpath.charAt(0)!='/'){ // relative path 1841 String cwd=getCwd(); 1842 oldpath=_oldpath.substring(cwd.length()+(cwd.endsWith("/")?0:1)); 1843 } 1844 else { 1845 oldpath=_oldpath; 1846 } 1847 1848 if(isPattern(newpath)){ 1849 throw new SftpException(SSH_FX_FAILURE, newpath); 1850 } 1851 newpath=Util.unquote(newpath); 1852 1853 sendHARDLINK(Util.str2byte(oldpath, fEncoding), 1854 Util.str2byte(newpath, fEncoding)); 1855 1856 Header header=new Header(); 1857 header=header(buf, header); 1858 int length=header.length; 1859 int type=header.type; 1860 1861 fill(buf, length); 1862 1863 if(type!=SSH_FXP_STATUS){ 1864 throw new SftpException(SSH_FX_FAILURE, ""); 1865 } 1866 1867 int i=buf.getInt(); 1868 if(i==SSH_FX_OK) return; 1869 throwStatusError(buf, i); 1870 } 1871 catch(Exception e){ 1872 if(e instanceof SftpException) throw (SftpException)e; 1873 if(e instanceof Throwable) 1874 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 1875 throw new SftpException(SSH_FX_FAILURE, ""); 1876 } 1877 } 1878 rename(String oldpath, String newpath)1879 public void rename(String oldpath, String newpath) throws SftpException{ 1880 if(server_version<2){ 1881 throw new SftpException(SSH_FX_OP_UNSUPPORTED, 1882 "The remote sshd is too old to support rename operation."); 1883 } 1884 1885 try{ 1886 ((MyPipedInputStream)io_in).updateReadSide(); 1887 1888 oldpath=remoteAbsolutePath(oldpath); 1889 newpath=remoteAbsolutePath(newpath); 1890 1891 oldpath=isUnique(oldpath); 1892 1893 Vector v=glob_remote(newpath); 1894 int vsize=v.size(); 1895 if(vsize>=2){ 1896 throw new SftpException(SSH_FX_FAILURE, v.toString()); 1897 } 1898 if(vsize==1){ 1899 newpath=(String)(v.elementAt(0)); 1900 } 1901 else{ // vsize==0 1902 if(isPattern(newpath)) 1903 throw new SftpException(SSH_FX_FAILURE, newpath); 1904 newpath=Util.unquote(newpath); 1905 } 1906 1907 sendRENAME(Util.str2byte(oldpath, fEncoding), 1908 Util.str2byte(newpath, fEncoding)); 1909 1910 Header header=new Header(); 1911 header=header(buf, header); 1912 int length=header.length; 1913 int type=header.type; 1914 1915 fill(buf, length); 1916 1917 if(type!=SSH_FXP_STATUS){ 1918 throw new SftpException(SSH_FX_FAILURE, ""); 1919 } 1920 1921 int i=buf.getInt(); 1922 if(i==SSH_FX_OK) return; 1923 throwStatusError(buf, i); 1924 } 1925 catch(Exception e){ 1926 if(e instanceof SftpException) throw (SftpException)e; 1927 if(e instanceof Throwable) 1928 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 1929 throw new SftpException(SSH_FX_FAILURE, ""); 1930 } 1931 } rm(String path)1932 public void rm(String path) throws SftpException{ 1933 try{ 1934 ((MyPipedInputStream)io_in).updateReadSide(); 1935 1936 path=remoteAbsolutePath(path); 1937 1938 Vector v=glob_remote(path); 1939 int vsize=v.size(); 1940 1941 Header header=new Header(); 1942 1943 for(int j=0; j<vsize; j++){ 1944 path=(String)(v.elementAt(j)); 1945 sendREMOVE(Util.str2byte(path, fEncoding)); 1946 1947 header=header(buf, header); 1948 int length=header.length; 1949 int type=header.type; 1950 1951 fill(buf, length); 1952 1953 if(type!=SSH_FXP_STATUS){ 1954 throw new SftpException(SSH_FX_FAILURE, ""); 1955 } 1956 int i=buf.getInt(); 1957 if(i!=SSH_FX_OK){ 1958 throwStatusError(buf, i); 1959 } 1960 } 1961 } 1962 catch(Exception e){ 1963 if(e instanceof SftpException) throw (SftpException)e; 1964 if(e instanceof Throwable) 1965 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 1966 throw new SftpException(SSH_FX_FAILURE, ""); 1967 } 1968 } 1969 isRemoteDir(String path)1970 private boolean isRemoteDir(String path){ 1971 try{ 1972 sendSTAT(Util.str2byte(path, fEncoding)); 1973 1974 Header header=new Header(); 1975 header=header(buf, header); 1976 int length=header.length; 1977 int type=header.type; 1978 1979 fill(buf, length); 1980 1981 if(type!=SSH_FXP_ATTRS){ 1982 return false; 1983 } 1984 SftpATTRS attr=SftpATTRS.getATTR(buf); 1985 return attr.isDir(); 1986 } 1987 catch(Exception e){} 1988 return false; 1989 } 1990 chgrp(int gid, String path)1991 public void chgrp(int gid, String path) throws SftpException{ 1992 try{ 1993 ((MyPipedInputStream)io_in).updateReadSide(); 1994 1995 path=remoteAbsolutePath(path); 1996 1997 Vector v=glob_remote(path); 1998 int vsize=v.size(); 1999 for(int j=0; j<vsize; j++){ 2000 path=(String)(v.elementAt(j)); 2001 2002 SftpATTRS attr=_stat(path); 2003 2004 attr.setFLAGS(0); 2005 attr.setUIDGID(attr.uid, gid); 2006 _setStat(path, attr); 2007 } 2008 } 2009 catch(Exception e){ 2010 if(e instanceof SftpException) throw (SftpException)e; 2011 if(e instanceof Throwable) 2012 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2013 throw new SftpException(SSH_FX_FAILURE, ""); 2014 } 2015 } 2016 chown(int uid, String path)2017 public void chown(int uid, String path) throws SftpException{ 2018 try{ 2019 ((MyPipedInputStream)io_in).updateReadSide(); 2020 2021 path=remoteAbsolutePath(path); 2022 2023 Vector v=glob_remote(path); 2024 int vsize=v.size(); 2025 for(int j=0; j<vsize; j++){ 2026 path=(String)(v.elementAt(j)); 2027 2028 SftpATTRS attr=_stat(path); 2029 2030 attr.setFLAGS(0); 2031 attr.setUIDGID(uid, attr.gid); 2032 _setStat(path, attr); 2033 } 2034 } 2035 catch(Exception e){ 2036 if(e instanceof SftpException) throw (SftpException)e; 2037 if(e instanceof Throwable) 2038 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2039 throw new SftpException(SSH_FX_FAILURE, ""); 2040 } 2041 } 2042 chmod(int permissions, String path)2043 public void chmod(int permissions, String path) throws SftpException{ 2044 try{ 2045 ((MyPipedInputStream)io_in).updateReadSide(); 2046 2047 path=remoteAbsolutePath(path); 2048 2049 Vector v=glob_remote(path); 2050 int vsize=v.size(); 2051 for(int j=0; j<vsize; j++){ 2052 path=(String)(v.elementAt(j)); 2053 2054 SftpATTRS attr=_stat(path); 2055 2056 attr.setFLAGS(0); 2057 attr.setPERMISSIONS(permissions); 2058 _setStat(path, attr); 2059 } 2060 } 2061 catch(Exception e){ 2062 if(e instanceof SftpException) throw (SftpException)e; 2063 if(e instanceof Throwable) 2064 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2065 throw new SftpException(SSH_FX_FAILURE, ""); 2066 } 2067 } 2068 setMtime(String path, int mtime)2069 public void setMtime(String path, int mtime) throws SftpException{ 2070 try{ 2071 ((MyPipedInputStream)io_in).updateReadSide(); 2072 2073 path=remoteAbsolutePath(path); 2074 2075 Vector v=glob_remote(path); 2076 int vsize=v.size(); 2077 for(int j=0; j<vsize; j++){ 2078 path=(String)(v.elementAt(j)); 2079 2080 SftpATTRS attr=_stat(path); 2081 2082 attr.setFLAGS(0); 2083 attr.setACMODTIME(attr.getATime(), mtime); 2084 _setStat(path, attr); 2085 } 2086 } 2087 catch(Exception e){ 2088 if(e instanceof SftpException) throw (SftpException)e; 2089 if(e instanceof Throwable) 2090 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2091 throw new SftpException(SSH_FX_FAILURE, ""); 2092 } 2093 } 2094 rmdir(String path)2095 public void rmdir(String path) throws SftpException{ 2096 try{ 2097 ((MyPipedInputStream)io_in).updateReadSide(); 2098 2099 path=remoteAbsolutePath(path); 2100 2101 Vector v=glob_remote(path); 2102 int vsize=v.size(); 2103 2104 Header header=new Header(); 2105 2106 for(int j=0; j<vsize; j++){ 2107 path=(String)(v.elementAt(j)); 2108 sendRMDIR(Util.str2byte(path, fEncoding)); 2109 2110 header=header(buf, header); 2111 int length=header.length; 2112 int type=header.type; 2113 2114 fill(buf, length); 2115 2116 if(type!=SSH_FXP_STATUS){ 2117 throw new SftpException(SSH_FX_FAILURE, ""); 2118 } 2119 2120 int i=buf.getInt(); 2121 if(i!=SSH_FX_OK){ 2122 throwStatusError(buf, i); 2123 } 2124 } 2125 } 2126 catch(Exception e){ 2127 if(e instanceof SftpException) throw (SftpException)e; 2128 if(e instanceof Throwable) 2129 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2130 throw new SftpException(SSH_FX_FAILURE, ""); 2131 } 2132 } 2133 mkdir(String path)2134 public void mkdir(String path) throws SftpException{ 2135 try{ 2136 ((MyPipedInputStream)io_in).updateReadSide(); 2137 2138 path=remoteAbsolutePath(path); 2139 2140 sendMKDIR(Util.str2byte(path, fEncoding), null); 2141 2142 Header header=new Header(); 2143 header=header(buf, header); 2144 int length=header.length; 2145 int type=header.type; 2146 2147 fill(buf, length); 2148 2149 if(type!=SSH_FXP_STATUS){ 2150 throw new SftpException(SSH_FX_FAILURE, ""); 2151 } 2152 2153 int i=buf.getInt(); 2154 if(i==SSH_FX_OK) return; 2155 throwStatusError(buf, i); 2156 } 2157 catch(Exception e){ 2158 if(e instanceof SftpException) throw (SftpException)e; 2159 if(e instanceof Throwable) 2160 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2161 throw new SftpException(SSH_FX_FAILURE, ""); 2162 } 2163 } 2164 stat(String path)2165 public SftpATTRS stat(String path) throws SftpException{ 2166 try{ 2167 ((MyPipedInputStream)io_in).updateReadSide(); 2168 2169 path=remoteAbsolutePath(path); 2170 path=isUnique(path); 2171 2172 return _stat(path); 2173 } 2174 catch(Exception e){ 2175 if(e instanceof SftpException) throw (SftpException)e; 2176 if(e instanceof Throwable) 2177 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2178 throw new SftpException(SSH_FX_FAILURE, ""); 2179 } 2180 //return null; 2181 } 2182 _stat(byte[] path)2183 private SftpATTRS _stat(byte[] path) throws SftpException{ 2184 try{ 2185 2186 sendSTAT(path); 2187 2188 Header header=new Header(); 2189 header=header(buf, header); 2190 int length=header.length; 2191 int type=header.type; 2192 2193 fill(buf, length); 2194 2195 if(type!=SSH_FXP_ATTRS){ 2196 if(type==SSH_FXP_STATUS){ 2197 int i=buf.getInt(); 2198 throwStatusError(buf, i); 2199 } 2200 throw new SftpException(SSH_FX_FAILURE, ""); 2201 } 2202 SftpATTRS attr=SftpATTRS.getATTR(buf); 2203 return attr; 2204 } 2205 catch(Exception e){ 2206 if(e instanceof SftpException) throw (SftpException)e; 2207 if(e instanceof Throwable) 2208 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2209 throw new SftpException(SSH_FX_FAILURE, ""); 2210 } 2211 //return null; 2212 } 2213 _stat(String path)2214 private SftpATTRS _stat(String path) throws SftpException{ 2215 return _stat(Util.str2byte(path, fEncoding)); 2216 } 2217 statVFS(String path)2218 public SftpStatVFS statVFS(String path) throws SftpException{ 2219 try{ 2220 ((MyPipedInputStream)io_in).updateReadSide(); 2221 2222 path=remoteAbsolutePath(path); 2223 path=isUnique(path); 2224 2225 return _statVFS(path); 2226 } 2227 catch(Exception e){ 2228 if(e instanceof SftpException) throw (SftpException)e; 2229 if(e instanceof Throwable) 2230 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2231 throw new SftpException(SSH_FX_FAILURE, ""); 2232 } 2233 //return null; 2234 } 2235 _statVFS(byte[] path)2236 private SftpStatVFS _statVFS(byte[] path) throws SftpException{ 2237 if(!extension_statvfs){ 2238 throw new SftpException(SSH_FX_OP_UNSUPPORTED, 2239 "statvfs@openssh.com is not supported"); 2240 } 2241 2242 try{ 2243 2244 sendSTATVFS(path); 2245 2246 Header header=new Header(); 2247 header=header(buf, header); 2248 int length=header.length; 2249 int type=header.type; 2250 2251 fill(buf, length); 2252 2253 if(type != (SSH_FXP_EXTENDED_REPLY&0xff)){ 2254 if(type==SSH_FXP_STATUS){ 2255 int i=buf.getInt(); 2256 throwStatusError(buf, i); 2257 } 2258 throw new SftpException(SSH_FX_FAILURE, ""); 2259 } 2260 else { 2261 SftpStatVFS stat = SftpStatVFS.getStatVFS(buf); 2262 return stat; 2263 } 2264 } 2265 catch(Exception e){ 2266 if(e instanceof SftpException) throw (SftpException)e; 2267 if(e instanceof Throwable) 2268 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2269 throw new SftpException(SSH_FX_FAILURE, ""); 2270 } 2271 //return null; 2272 } 2273 _statVFS(String path)2274 private SftpStatVFS _statVFS(String path) throws SftpException{ 2275 return _statVFS(Util.str2byte(path, fEncoding)); 2276 } 2277 lstat(String path)2278 public SftpATTRS lstat(String path) throws SftpException{ 2279 try{ 2280 ((MyPipedInputStream)io_in).updateReadSide(); 2281 2282 path=remoteAbsolutePath(path); 2283 path=isUnique(path); 2284 2285 return _lstat(path); 2286 } 2287 catch(Exception e){ 2288 if(e instanceof SftpException) throw (SftpException)e; 2289 if(e instanceof Throwable) 2290 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2291 throw new SftpException(SSH_FX_FAILURE, ""); 2292 } 2293 } 2294 _lstat(String path)2295 private SftpATTRS _lstat(String path) throws SftpException{ 2296 try{ 2297 sendLSTAT(Util.str2byte(path, fEncoding)); 2298 2299 Header header=new Header(); 2300 header=header(buf, header); 2301 int length=header.length; 2302 int type=header.type; 2303 2304 fill(buf, length); 2305 2306 if(type!=SSH_FXP_ATTRS){ 2307 if(type==SSH_FXP_STATUS){ 2308 int i=buf.getInt(); 2309 throwStatusError(buf, i); 2310 } 2311 throw new SftpException(SSH_FX_FAILURE, ""); 2312 } 2313 SftpATTRS attr=SftpATTRS.getATTR(buf); 2314 return attr; 2315 } 2316 catch(Exception e){ 2317 if(e instanceof SftpException) throw (SftpException)e; 2318 if(e instanceof Throwable) 2319 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2320 throw new SftpException(SSH_FX_FAILURE, ""); 2321 } 2322 } 2323 _realpath(String path)2324 private byte[] _realpath(String path) throws SftpException, IOException, Exception{ 2325 sendREALPATH(Util.str2byte(path, fEncoding)); 2326 2327 Header header=new Header(); 2328 header=header(buf, header); 2329 int length=header.length; 2330 int type=header.type; 2331 2332 fill(buf, length); 2333 2334 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){ 2335 throw new SftpException(SSH_FX_FAILURE, ""); 2336 } 2337 int i; 2338 if(type==SSH_FXP_STATUS){ 2339 i=buf.getInt(); 2340 throwStatusError(buf, i); 2341 } 2342 i=buf.getInt(); // count 2343 2344 byte[] str=null; 2345 while(i-->0){ 2346 str=buf.getString(); // absolute path; 2347 if(server_version<=3){ 2348 byte[] lname=buf.getString(); // long filename 2349 } 2350 SftpATTRS attr=SftpATTRS.getATTR(buf); // dummy attribute 2351 } 2352 return str; 2353 } 2354 setStat(String path, SftpATTRS attr)2355 public void setStat(String path, SftpATTRS attr) throws SftpException{ 2356 try{ 2357 ((MyPipedInputStream)io_in).updateReadSide(); 2358 2359 path=remoteAbsolutePath(path); 2360 2361 Vector v=glob_remote(path); 2362 int vsize=v.size(); 2363 for(int j=0; j<vsize; j++){ 2364 path=(String)(v.elementAt(j)); 2365 _setStat(path, attr); 2366 } 2367 } 2368 catch(Exception e){ 2369 if(e instanceof SftpException) throw (SftpException)e; 2370 if(e instanceof Throwable) 2371 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2372 throw new SftpException(SSH_FX_FAILURE, ""); 2373 } 2374 } _setStat(String path, SftpATTRS attr)2375 private void _setStat(String path, SftpATTRS attr) throws SftpException{ 2376 try{ 2377 sendSETSTAT(Util.str2byte(path, fEncoding), attr); 2378 2379 Header header=new Header(); 2380 header=header(buf, header); 2381 int length=header.length; 2382 int type=header.type; 2383 2384 fill(buf, length); 2385 2386 if(type!=SSH_FXP_STATUS){ 2387 throw new SftpException(SSH_FX_FAILURE, ""); 2388 } 2389 int i=buf.getInt(); 2390 if(i!=SSH_FX_OK){ 2391 throwStatusError(buf, i); 2392 } 2393 } 2394 catch(Exception e){ 2395 if(e instanceof SftpException) throw (SftpException)e; 2396 if(e instanceof Throwable) 2397 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2398 throw new SftpException(SSH_FX_FAILURE, ""); 2399 } 2400 } 2401 pwd()2402 public String pwd() throws SftpException{ return getCwd(); } lpwd()2403 public String lpwd(){ return lcwd; } version()2404 public String version(){ return version; } getHome()2405 public String getHome() throws SftpException { 2406 if(home==null){ 2407 try{ 2408 ((MyPipedInputStream)io_in).updateReadSide(); 2409 2410 byte[] _home=_realpath(""); 2411 home=Util.byte2str(_home, fEncoding); 2412 } 2413 catch(Exception e){ 2414 if(e instanceof SftpException) throw (SftpException)e; 2415 if(e instanceof Throwable) 2416 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2417 throw new SftpException(SSH_FX_FAILURE, ""); 2418 } 2419 } 2420 return home; 2421 } 2422 getCwd()2423 private String getCwd() throws SftpException{ 2424 if(cwd==null) 2425 cwd=getHome(); 2426 return cwd; 2427 } 2428 setCwd(String cwd)2429 private void setCwd(String cwd){ 2430 this.cwd=cwd; 2431 } 2432 read(byte[] buf, int s, int l)2433 private void read(byte[] buf, int s, int l) throws IOException, SftpException{ 2434 int i=0; 2435 while(l>0){ 2436 i=io_in.read(buf, s, l); 2437 if(i<=0){ 2438 throw new SftpException(SSH_FX_FAILURE, ""); 2439 } 2440 s+=i; 2441 l-=i; 2442 } 2443 } 2444 checkStatus(int[] ackid, Header header)2445 private boolean checkStatus(int[] ackid, Header header) throws IOException, SftpException{ 2446 header=header(buf, header); 2447 int length=header.length; 2448 int type=header.type; 2449 if(ackid!=null) 2450 ackid[0]=header.rid; 2451 2452 fill(buf, length); 2453 2454 if(type!=SSH_FXP_STATUS){ 2455 throw new SftpException(SSH_FX_FAILURE, ""); 2456 } 2457 int i=buf.getInt(); 2458 if(i!=SSH_FX_OK){ 2459 throwStatusError(buf, i); 2460 } 2461 return true; 2462 } _sendCLOSE(byte[] handle, Header header)2463 private boolean _sendCLOSE(byte[] handle, Header header) throws Exception{ 2464 sendCLOSE(handle); 2465 return checkStatus(null, header); 2466 } 2467 sendINIT()2468 private void sendINIT() throws Exception{ 2469 packet.reset(); 2470 putHEAD(SSH_FXP_INIT, 5); 2471 buf.putInt(3); // version 3 2472 getSession().write(packet, this, 5+4); 2473 } 2474 sendREALPATH(byte[] path)2475 private void sendREALPATH(byte[] path) throws Exception{ 2476 sendPacketPath(SSH_FXP_REALPATH, path); 2477 } sendSTAT(byte[] path)2478 private void sendSTAT(byte[] path) throws Exception{ 2479 sendPacketPath(SSH_FXP_STAT, path); 2480 } sendSTATVFS(byte[] path)2481 private void sendSTATVFS(byte[] path) throws Exception{ 2482 sendPacketPath((byte)0, path, "statvfs@openssh.com"); 2483 } 2484 /* 2485 private void sendFSTATVFS(byte[] handle) throws Exception{ 2486 sendPacketPath((byte)0, handle, "fstatvfs@openssh.com"); 2487 } 2488 */ sendLSTAT(byte[] path)2489 private void sendLSTAT(byte[] path) throws Exception{ 2490 sendPacketPath(SSH_FXP_LSTAT, path); 2491 } sendFSTAT(byte[] handle)2492 private void sendFSTAT(byte[] handle) throws Exception{ 2493 sendPacketPath(SSH_FXP_FSTAT, handle); 2494 } sendSETSTAT(byte[] path, SftpATTRS attr)2495 private void sendSETSTAT(byte[] path, SftpATTRS attr) throws Exception{ 2496 packet.reset(); 2497 putHEAD(SSH_FXP_SETSTAT, 9+path.length+attr.length()); 2498 buf.putInt(seq++); 2499 buf.putString(path); // path 2500 attr.dump(buf); 2501 getSession().write(packet, this, 9+path.length+attr.length()+4); 2502 } sendREMOVE(byte[] path)2503 private void sendREMOVE(byte[] path) throws Exception{ 2504 sendPacketPath(SSH_FXP_REMOVE, path); 2505 } sendMKDIR(byte[] path, SftpATTRS attr)2506 private void sendMKDIR(byte[] path, SftpATTRS attr) throws Exception{ 2507 packet.reset(); 2508 putHEAD(SSH_FXP_MKDIR, 9+path.length+(attr!=null?attr.length():4)); 2509 buf.putInt(seq++); 2510 buf.putString(path); // path 2511 if(attr!=null) attr.dump(buf); 2512 else buf.putInt(0); 2513 getSession().write(packet, this, 9+path.length+(attr!=null?attr.length():4)+4); 2514 } sendRMDIR(byte[] path)2515 private void sendRMDIR(byte[] path) throws Exception{ 2516 sendPacketPath(SSH_FXP_RMDIR, path); 2517 } sendSYMLINK(byte[] p1, byte[] p2)2518 private void sendSYMLINK(byte[] p1, byte[] p2) throws Exception{ 2519 sendPacketPath(SSH_FXP_SYMLINK, p1, p2); 2520 } sendHARDLINK(byte[] p1, byte[] p2)2521 private void sendHARDLINK(byte[] p1, byte[] p2) throws Exception{ 2522 sendPacketPath((byte)0, p1, p2, "hardlink@openssh.com"); 2523 } sendREADLINK(byte[] path)2524 private void sendREADLINK(byte[] path) throws Exception{ 2525 sendPacketPath(SSH_FXP_READLINK, path); 2526 } sendOPENDIR(byte[] path)2527 private void sendOPENDIR(byte[] path) throws Exception{ 2528 sendPacketPath(SSH_FXP_OPENDIR, path); 2529 } sendREADDIR(byte[] path)2530 private void sendREADDIR(byte[] path) throws Exception{ 2531 sendPacketPath(SSH_FXP_READDIR, path); 2532 } sendRENAME(byte[] p1, byte[] p2)2533 private void sendRENAME(byte[] p1, byte[] p2) throws Exception{ 2534 sendPacketPath(SSH_FXP_RENAME, p1, p2, 2535 extension_posix_rename ? "posix-rename@openssh.com" : null); 2536 } sendCLOSE(byte[] path)2537 private void sendCLOSE(byte[] path) throws Exception{ 2538 sendPacketPath(SSH_FXP_CLOSE, path); 2539 } sendOPENR(byte[] path)2540 private void sendOPENR(byte[] path) throws Exception{ 2541 sendOPEN(path, SSH_FXF_READ); 2542 } sendOPENW(byte[] path)2543 private void sendOPENW(byte[] path) throws Exception{ 2544 sendOPEN(path, SSH_FXF_WRITE|SSH_FXF_CREAT|SSH_FXF_TRUNC); 2545 } sendOPENA(byte[] path)2546 private void sendOPENA(byte[] path) throws Exception{ 2547 sendOPEN(path, SSH_FXF_WRITE|/*SSH_FXF_APPEND|*/SSH_FXF_CREAT); 2548 } sendOPEN(byte[] path, int mode)2549 private void sendOPEN(byte[] path, int mode) throws Exception{ 2550 packet.reset(); 2551 putHEAD(SSH_FXP_OPEN, 17+path.length); 2552 buf.putInt(seq++); 2553 buf.putString(path); 2554 buf.putInt(mode); 2555 buf.putInt(0); // attrs 2556 getSession().write(packet, this, 17+path.length+4); 2557 } sendPacketPath(byte fxp, byte[] path)2558 private void sendPacketPath(byte fxp, byte[] path) throws Exception{ 2559 sendPacketPath(fxp, path, (String)null); 2560 } sendPacketPath(byte fxp, byte[] path, String extension)2561 private void sendPacketPath(byte fxp, byte[] path, String extension) throws Exception{ 2562 packet.reset(); 2563 int len = 9+path.length; 2564 if(extension == null) { 2565 putHEAD(fxp, len); 2566 buf.putInt(seq++); 2567 } 2568 else { 2569 len+=(4+extension.length()); 2570 putHEAD(SSH_FXP_EXTENDED, len); 2571 buf.putInt(seq++); 2572 buf.putString(Util.str2byte(extension)); 2573 } 2574 buf.putString(path); // path 2575 getSession().write(packet, this, len+4); 2576 } 2577 sendPacketPath(byte fxp, byte[] p1, byte[] p2)2578 private void sendPacketPath(byte fxp, byte[] p1, byte[] p2) throws Exception{ 2579 sendPacketPath(fxp, p1, p2, null); 2580 } sendPacketPath(byte fxp, byte[] p1, byte[] p2, String extension)2581 private void sendPacketPath(byte fxp, byte[] p1, byte[] p2, String extension) throws Exception{ 2582 packet.reset(); 2583 int len = 13+p1.length+p2.length; 2584 if(extension==null){ 2585 putHEAD(fxp, len); 2586 buf.putInt(seq++); 2587 } 2588 else { 2589 len+=(4+extension.length()); 2590 putHEAD(SSH_FXP_EXTENDED, len); 2591 buf.putInt(seq++); 2592 buf.putString(Util.str2byte(extension)); 2593 } 2594 buf.putString(p1); 2595 buf.putString(p2); 2596 getSession().write(packet, this, len+4); 2597 } 2598 sendWRITE(byte[] handle, long offset, byte[] data, int start, int length)2599 private int sendWRITE(byte[] handle, long offset, 2600 byte[] data, int start, int length) throws Exception{ 2601 int _length=length; 2602 opacket.reset(); 2603 if(obuf.buffer.length<obuf.index+13+21+handle.length+length+Session.buffer_margin){ 2604 _length=obuf.buffer.length-(obuf.index+13+21+handle.length+Session.buffer_margin); 2605 // System.err.println("_length="+_length+" length="+length); 2606 } 2607 2608 putHEAD(obuf, SSH_FXP_WRITE, 21+handle.length+_length); // 14 2609 obuf.putInt(seq++); // 4 2610 obuf.putString(handle); // 4+handle.length 2611 obuf.putLong(offset); // 8 2612 if(obuf.buffer!=data){ 2613 obuf.putString(data, start, _length); // 4+_length 2614 } 2615 else{ 2616 obuf.putInt(_length); 2617 obuf.skip(_length); 2618 } 2619 getSession().write(opacket, this, 21+handle.length+_length+4); 2620 return _length; 2621 } sendREAD(byte[] handle, long offset, int length)2622 private void sendREAD(byte[] handle, long offset, int length) throws Exception{ 2623 sendREAD(handle, offset, length, null); 2624 } sendREAD(byte[] handle, long offset, int length, RequestQueue rrq)2625 private void sendREAD(byte[] handle, long offset, int length, 2626 RequestQueue rrq) throws Exception{ 2627 packet.reset(); 2628 putHEAD(SSH_FXP_READ, 21+handle.length); 2629 buf.putInt(seq++); 2630 buf.putString(handle); 2631 buf.putLong(offset); 2632 buf.putInt(length); 2633 getSession().write(packet, this, 21+handle.length+4); 2634 if(rrq!=null){ 2635 rrq.add(seq-1, offset, length); 2636 } 2637 } 2638 putHEAD(Buffer buf, byte type, int length)2639 private void putHEAD(Buffer buf, byte type, int length) throws Exception{ 2640 buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA); 2641 buf.putInt(recipient); 2642 buf.putInt(length+4); 2643 buf.putInt(length); 2644 buf.putByte(type); 2645 } 2646 putHEAD(byte type, int length)2647 private void putHEAD(byte type, int length) throws Exception{ 2648 putHEAD(buf, type, length); 2649 } 2650 glob_remote(String _path)2651 private Vector glob_remote(String _path) throws Exception{ 2652 Vector v=new Vector(); 2653 int i=0; 2654 2655 int foo=_path.lastIndexOf('/'); 2656 if(foo<0){ // it is not absolute path. 2657 v.addElement(Util.unquote(_path)); 2658 return v; 2659 } 2660 2661 String dir=_path.substring(0, ((foo==0)?1:foo)); 2662 String _pattern=_path.substring(foo+1); 2663 2664 dir=Util.unquote(dir); 2665 2666 byte[] pattern=null; 2667 byte[][] _pattern_utf8=new byte[1][]; 2668 boolean pattern_has_wildcard=isPattern(_pattern, _pattern_utf8); 2669 2670 if(!pattern_has_wildcard){ 2671 if(!dir.equals("/")) 2672 dir+="/"; 2673 v.addElement(dir+Util.unquote(_pattern)); 2674 return v; 2675 } 2676 2677 pattern=_pattern_utf8[0]; 2678 2679 sendOPENDIR(Util.str2byte(dir, fEncoding)); 2680 2681 Header header=new Header(); 2682 header=header(buf, header); 2683 int length=header.length; 2684 int type=header.type; 2685 2686 fill(buf, length); 2687 2688 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){ 2689 throw new SftpException(SSH_FX_FAILURE, ""); 2690 } 2691 if(type==SSH_FXP_STATUS){ 2692 i=buf.getInt(); 2693 throwStatusError(buf, i); 2694 } 2695 2696 byte[] handle=buf.getString(); // filename 2697 String pdir=null; // parent directory 2698 2699 while(true){ 2700 sendREADDIR(handle); 2701 header=header(buf, header); 2702 length=header.length; 2703 type=header.type; 2704 2705 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){ 2706 throw new SftpException(SSH_FX_FAILURE, ""); 2707 } 2708 if(type==SSH_FXP_STATUS){ 2709 fill(buf, length); 2710 break; 2711 } 2712 2713 buf.rewind(); 2714 fill(buf.buffer, 0, 4); length-=4; 2715 int count=buf.getInt(); 2716 2717 byte[] str; 2718 int flags; 2719 2720 buf.reset(); 2721 while(count>0){ 2722 if(length>0){ 2723 buf.shift(); 2724 int j=(buf.buffer.length>(buf.index+length)) ? length : (buf.buffer.length-buf.index); 2725 i=io_in.read(buf.buffer, buf.index, j); 2726 if(i<=0)break; 2727 buf.index+=i; 2728 length-=i; 2729 } 2730 2731 byte[] filename=buf.getString(); 2732 //System.err.println("filename: "+new String(filename)); 2733 if(server_version<=3){ 2734 str=buf.getString(); // longname 2735 } 2736 SftpATTRS attrs=SftpATTRS.getATTR(buf); 2737 2738 byte[] _filename=filename; 2739 String f=null; 2740 boolean found=false; 2741 2742 if(!fEncoding_is_utf8){ 2743 f=Util.byte2str(filename, fEncoding); 2744 _filename=Util.str2byte(f, UTF8); 2745 } 2746 found=Util.glob(pattern, _filename); 2747 2748 if(found){ 2749 if(f==null){ 2750 f=Util.byte2str(filename, fEncoding); 2751 } 2752 if(pdir==null){ 2753 pdir=dir; 2754 if(!pdir.endsWith("/")){ 2755 pdir+="/"; 2756 } 2757 } 2758 v.addElement(pdir+f); 2759 } 2760 count--; 2761 } 2762 } 2763 if(_sendCLOSE(handle, header)) 2764 return v; 2765 return null; 2766 } 2767 isPattern(byte[] path)2768 private boolean isPattern(byte[] path){ 2769 int length=path.length; 2770 int i=0; 2771 while(i<length){ 2772 if(path[i]=='*' || path[i]=='?') 2773 return true; 2774 if(path[i]=='\\' && (i+1)<length) 2775 i++; 2776 i++; 2777 } 2778 return false; 2779 } 2780 glob_local(String _path)2781 private Vector glob_local(String _path) throws Exception{ 2782 //System.err.println("glob_local: "+_path); 2783 Vector v=new Vector(); 2784 byte[] path=Util.str2byte(_path, UTF8); 2785 int i=path.length-1; 2786 while(i>=0){ 2787 if(path[i]!='*' && path[i]!='?'){ 2788 i--; 2789 continue; 2790 } 2791 if(!fs_is_bs && 2792 i>0 && path[i-1]=='\\'){ 2793 i--; 2794 if(i>0 && path[i-1]=='\\'){ 2795 i--; 2796 i--; 2797 continue; 2798 } 2799 } 2800 break; 2801 } 2802 2803 if(i<0){ v.addElement(fs_is_bs ? _path : Util.unquote(_path)); return v;} 2804 2805 while(i>=0){ 2806 if(path[i]==file_separatorc || 2807 (fs_is_bs && path[i]=='/')){ // On Windows, '/' is also the separator. 2808 break; 2809 } 2810 i--; 2811 } 2812 2813 if(i<0){ v.addElement(fs_is_bs ? _path : Util.unquote(_path)); return v;} 2814 2815 byte[] dir; 2816 if(i==0){dir=new byte[]{(byte)file_separatorc};} 2817 else{ 2818 dir=new byte[i]; 2819 System.arraycopy(path, 0, dir, 0, i); 2820 } 2821 2822 byte[] pattern=new byte[path.length-i-1]; 2823 System.arraycopy(path, i+1, pattern, 0, pattern.length); 2824 2825 //System.err.println("dir: "+new String(dir)+" pattern: "+new String(pattern)); 2826 try{ 2827 String[] children=(new File(Util.byte2str(dir, UTF8))).list(); 2828 String pdir=Util.byte2str(dir)+file_separator; 2829 for(int j=0; j<children.length; j++){ 2830 //System.err.println("children: "+children[j]); 2831 if(Util.glob(pattern, Util.str2byte(children[j], UTF8))){ 2832 v.addElement(pdir+children[j]); 2833 } 2834 } 2835 } 2836 catch(Exception e){ 2837 } 2838 return v; 2839 } 2840 throwStatusError(Buffer buf, int i)2841 private void throwStatusError(Buffer buf, int i) throws SftpException{ 2842 if(server_version>=3 && // WindRiver's sftp will send invalid 2843 buf.getLength()>=4){ // SSH_FXP_STATUS packet. 2844 byte[] str=buf.getString(); 2845 //byte[] tag=buf.getString(); 2846 throw new SftpException(i, Util.byte2str(str, UTF8)); 2847 } 2848 else{ 2849 throw new SftpException(i, "Failure"); 2850 } 2851 } 2852 isLocalAbsolutePath(String path)2853 private static boolean isLocalAbsolutePath(String path){ 2854 return (new File(path)).isAbsolute(); 2855 } 2856 disconnect()2857 public void disconnect(){ 2858 super.disconnect(); 2859 } 2860 isPattern(String path, byte[][] utf8)2861 private boolean isPattern(String path, byte[][] utf8){ 2862 byte[] _path=Util.str2byte(path, UTF8); 2863 if(utf8!=null) 2864 utf8[0]=_path; 2865 return isPattern(_path); 2866 } 2867 isPattern(String path)2868 private boolean isPattern(String path){ 2869 return isPattern(path, null); 2870 } 2871 fill(Buffer buf, int len)2872 private void fill(Buffer buf, int len) throws IOException{ 2873 buf.reset(); 2874 fill(buf.buffer, 0, len); 2875 buf.skip(len); 2876 } 2877 fill(byte[] buf, int s, int len)2878 private int fill(byte[] buf, int s, int len) throws IOException{ 2879 int i=0; 2880 int foo=s; 2881 while(len>0){ 2882 i=io_in.read(buf, s, len); 2883 if(i<=0){ 2884 throw new IOException("inputstream is closed"); 2885 //return (s-foo)==0 ? i : s-foo; 2886 } 2887 s+=i; 2888 len-=i; 2889 } 2890 return s-foo; 2891 } skip(long foo)2892 private void skip(long foo) throws IOException{ 2893 while(foo>0){ 2894 long bar=io_in.skip(foo); 2895 if(bar<=0) 2896 break; 2897 foo-=bar; 2898 } 2899 } 2900 2901 class Header{ 2902 int length; 2903 int type; 2904 int rid; 2905 } header(Buffer buf, Header header)2906 private Header header(Buffer buf, Header header) throws IOException{ 2907 buf.rewind(); 2908 int i=fill(buf.buffer, 0, 9); 2909 header.length=buf.getInt()-5; 2910 header.type=buf.getByte()&0xff; 2911 header.rid=buf.getInt(); 2912 return header; 2913 } 2914 remoteAbsolutePath(String path)2915 private String remoteAbsolutePath(String path) throws SftpException{ 2916 if(path.charAt(0)=='/') return path; 2917 String cwd=getCwd(); 2918 // if(cwd.equals(getHome())) return path; 2919 if(cwd.endsWith("/")) return cwd+path; 2920 return cwd+"/"+path; 2921 } 2922 localAbsolutePath(String path)2923 private String localAbsolutePath(String path){ 2924 if(isLocalAbsolutePath(path)) return path; 2925 if(lcwd.endsWith(file_separator)) return lcwd+path; 2926 return lcwd+file_separator+path; 2927 } 2928 2929 /** 2930 * This method will check if the given string can be expanded to the 2931 * unique string. If it can be expanded to mutiple files, SftpException 2932 * will be thrown. 2933 * @return the returned string is unquoted. 2934 */ isUnique(String path)2935 private String isUnique(String path) throws SftpException, Exception{ 2936 Vector v=glob_remote(path); 2937 if(v.size()!=1){ 2938 throw new SftpException(SSH_FX_FAILURE, path+" is not unique: "+v.toString()); 2939 } 2940 return (String)(v.elementAt(0)); 2941 } 2942 getServerVersion()2943 public int getServerVersion() throws SftpException{ 2944 if(!isConnected()){ 2945 throw new SftpException(SSH_FX_FAILURE, "The channel is not connected."); 2946 } 2947 return server_version; 2948 } 2949 setFilenameEncoding(String encoding)2950 public void setFilenameEncoding(String encoding) throws SftpException{ 2951 int sversion=getServerVersion(); 2952 if(3 <= sversion && sversion <= 5 && 2953 !encoding.equals(UTF8)){ 2954 throw new SftpException(SSH_FX_FAILURE, 2955 "The encoding can not be changed for this sftp server."); 2956 } 2957 if(encoding.equals(UTF8)){ 2958 encoding=UTF8; 2959 } 2960 fEncoding=encoding; 2961 fEncoding_is_utf8=fEncoding.equals(UTF8); 2962 } 2963 getExtension(String key)2964 public String getExtension(String key){ 2965 if(extensions==null) 2966 return null; 2967 return (String)extensions.get(key); 2968 } 2969 realpath(String path)2970 public String realpath(String path) throws SftpException{ 2971 try{ 2972 byte[] _path=_realpath(remoteAbsolutePath(path)); 2973 return Util.byte2str(_path, fEncoding); 2974 } 2975 catch(Exception e){ 2976 if(e instanceof SftpException) throw (SftpException)e; 2977 if(e instanceof Throwable) 2978 throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e); 2979 throw new SftpException(SSH_FX_FAILURE, ""); 2980 } 2981 } 2982 2983 public class LsEntry implements Comparable{ 2984 private String filename; 2985 private String longname; 2986 private SftpATTRS attrs; LsEntry(String filename, String longname, SftpATTRS attrs)2987 LsEntry(String filename, String longname, SftpATTRS attrs){ 2988 setFilename(filename); 2989 setLongname(longname); 2990 setAttrs(attrs); 2991 } getFilename()2992 public String getFilename(){return filename;}; setFilename(String filename)2993 void setFilename(String filename){this.filename = filename;}; getLongname()2994 public String getLongname(){return longname;}; setLongname(String longname)2995 void setLongname(String longname){this.longname = longname;}; getAttrs()2996 public SftpATTRS getAttrs(){return attrs;}; setAttrs(SftpATTRS attrs)2997 void setAttrs(SftpATTRS attrs) {this.attrs = attrs;}; toString()2998 public String toString(){ return longname; } compareTo(Object o)2999 public int compareTo(Object o) throws ClassCastException{ 3000 if(o instanceof LsEntry){ 3001 return filename.compareTo(((LsEntry)o).getFilename()); 3002 } 3003 throw new ClassCastException("a decendent of LsEntry must be given."); 3004 } 3005 } 3006 3007 /** 3008 * This interface will be passed as an argument for <code>ls</code> method. 3009 * 3010 * @see ChannelSftp.LsEntry 3011 * @see #ls(String, ChannelSftp.LsEntrySelector) 3012 * @since 0.1.47 3013 */ 3014 public interface LsEntrySelector { 3015 public final int CONTINUE = 0; 3016 public final int BREAK = 1; 3017 3018 /** 3019 * <p> The <code>select</code> method will be invoked in <code>ls</code> 3020 * method for each file entry. If this method returns BREAK, 3021 * <code>ls</code> will be canceled. 3022 * 3023 * @param entry one of entry from ls 3024 * @return if BREAK is returned, the 'ls' operation will be canceled. 3025 */ select(LsEntry entry)3026 public int select(LsEntry entry); 3027 } 3028 } 3029