Java Source Code: com.jcraft.jsch.ChannelSftp


   1: /* -*-mode:java; c-basic-offset:2; -*- */
   2: /*
   3: Copyright (c) 2002,2003,2004 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.net.*;
  33: import java.io.*;
  34: 
  35: import java.util.Vector;
  36: 
  37:	  public class ChannelSftp extends ChannelSession{
  38:
  39:  private static final byte SSH_FXP_INIT=               1;
  40:  private static final byte SSH_FXP_VERSION=            2;
  41:  private static final byte SSH_FXP_OPEN=               3;
  42:  private static final byte SSH_FXP_CLOSE=              4;
  43:  private static final byte SSH_FXP_READ=               5;
  44:  private static final byte SSH_FXP_WRITE=              6;
  45:  private static final byte SSH_FXP_LSTAT=              7;
  46:  private static final byte SSH_FXP_FSTAT=              8;
  47:  private static final byte SSH_FXP_SETSTAT=            9;
  48:  private static final byte SSH_FXP_FSETSTAT=          10;
  49:  private static final byte SSH_FXP_OPENDIR=           11;
  50:  private static final byte SSH_FXP_READDIR=           12;
  51:  private static final byte SSH_FXP_REMOVE=            13;
  52:  private static final byte SSH_FXP_MKDIR=             14;
  53:  private static final byte SSH_FXP_RMDIR=             15;
  54:  private static final byte SSH_FXP_REALPATH=          16;
  55:  private static final byte SSH_FXP_STAT=              17;
  56:  private static final byte SSH_FXP_RENAME=            18;
  57:  private static final byte SSH_FXP_READLINK=          19;
  58:  private static final byte SSH_FXP_SYMLINK=           20;
  59:  private static final byte SSH_FXP_STATUS=           101;
  60:  private static final byte SSH_FXP_HANDLE=           102;
  61:  private static final byte SSH_FXP_DATA=             103;
  62:  private static final byte SSH_FXP_NAME=             104;
  63:  private static final byte SSH_FXP_ATTRS=            105;
  64:  private static final byte SSH_FXP_EXTENDED=         (byte)200;
  65:  private static final byte SSH_FXP_EXTENDED_REPLY=   (byte)201;
  66:
  67:  // pflags
  68:  private static final int SSH_FXF_READ=           0x00000001;
  69:  private static final int SSH_FXF_WRITE=          0x00000002;
  70:  private static final int SSH_FXF_APPEND=         0x00000004;
  71:  private static final int SSH_FXF_CREAT=          0x00000008;
  72:  private static final int SSH_FXF_TRUNC=          0x00000010;
  73:  private static final int SSH_FXF_EXCL=           0x00000020;
  74:
  75:  private static final int SSH_FILEXFER_ATTR_SIZE=         0x00000001;
  76:  private static final int SSH_FILEXFER_ATTR_UIDGID=       0x00000002;
  77:  private static final int SSH_FILEXFER_ATTR_PERMISSIONS=  0x00000004;
  78:  private static final int SSH_FILEXFER_ATTR_ACMODTIME=    0x00000008;
  79:  private static final int SSH_FILEXFER_ATTR_EXTENDED=     0x80000000;
  80:
  81:  public static final int SSH_FX_OK=                            0;
  82:  public static final int SSH_FX_EOF=                           1;
  83:  public static final int SSH_FX_NO_SUCH_FILE=                  2;
  84:  public static final int SSH_FX_PERMISSION_DENIED=             3;
  85:  public static final int SSH_FX_FAILURE=                       4;
  86:  public static final int SSH_FX_BAD_MESSAGE=                   5;
  87:  public static final int SSH_FX_NO_CONNECTION=                 6;
  88:  public static final int SSH_FX_CONNECTION_LOST=               7;
  89:  public static final int SSH_FX_OP_UNSUPPORTED=                8;
  90:/*
  91:   SSH_FX_OK
  92:      Indicates successful completion of the operation.
  93:   SSH_FX_EOF
  94:     indicates end-of-file condition; for SSH_FX_READ it means that no
  95:       more data is available in the file, and for SSH_FX_READDIR it
  96:      indicates that no more files are contained in the directory.
  97:   SSH_FX_NO_SUCH_FILE
  98:      is returned when a reference is made to a file which should exist
  99:      but doesn't.
 100:   SSH_FX_PERMISSION_DENIED
 101:      is returned when the authenticated user does not have sufficient
 102:      permissions to perform the operation.
 103:   SSH_FX_FAILURE
 104:      is a generic catch-all error message; it should be returned if an
 105:      error occurs for which there is no more specific error code
 106:      defined.
 107:   SSH_FX_BAD_MESSAGE
 108:      may be returned if a badly formatted packet or protocol
 109:      incompatibility is detected.
 110:   SSH_FX_NO_CONNECTION
 111:      is a pseudo-error which indicates that the client has no
 112:      connection to the server (it can only be generated locally by the
 113:      client, and MUST NOT be returned by servers).
 114:   SSH_FX_CONNECTION_LOST
 115:      is a pseudo-error which indicates that the connection to the
 116:      server has been lost (it can only be generated locally by the
 117:      client, and MUST NOT be returned by servers).
 118:   SSH_FX_OP_UNSUPPORTED
 119:      indicates that an attempt was made to perform an operation which
 120:      is not supported for the server (it may be generated locally by
 121:      the client if e.g.  the version number exchange indicates that a
 122:      required feature is not supported by the server, or it may be
 123:      returned by the server if the server does not implement an
 124:      operation).
 125:*/
 126:
 127:  public static final int OVERWRITE=0;
 128:  public static final int RESUME=1;
 129:  public static final int APPEND=2;
 130:
 131://  private boolean interactive=true;
 132:  private boolean interactive=false;
 133:  private int count=1;
 134:  private Buffer buf;
 135:  private Packet packet=new Packet(buf);
 136:
 137:  private String version="3";
 138:  private int server_version=3;
 139:/*
 140:10. Changes from previous protocol versions
 141:  The SSH File Transfer Protocol has changed over time, before it's
 142:   standardization.  The following is a description of the incompatible
 143:   changes between different versions.
 144:10.1 Changes between versions 3 and 2
 145:   o  The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added.
 146:   o  The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were added.
 147:   o  The SSH_FXP_STATUS message was changed to include fields `error
 148:      message' and `language tag'.
 149:10.2 Changes between versions 2 and 1
 150:   o  The SSH_FXP_RENAME message was added.
 151:10.3 Changes between versions 1 and 0
 152:   o  Implementation changes, no actual protocol changes.
 153:*/
 154:
 155:  private static final String file_separator=java.io.File.separator;
 156:  private static final char file_separatorc=java.io.File.separatorChar;
 157:
 158:  private String cwd;
 159:  private String home;
 160:  private String lcwd;
 161:
 162:  //ChannelSftp(){}
 163:
 164:	    public void init(){
 165:    /*
 166:    io.setInputStream(session.in);
 167:    io.setOutputStream(session.out);
 168:    */
 169:  }
 170:
 171:	    public void start() throws JSchException{
 172:	      try{
 173:
 174:      PipedOutputStream pos=new PipedOutputStream();
 175:      io.setOutputStream(pos);
 176:      PipedInputStream pis=new PipedInputStream(pos);
 177:      io.setInputStream(pis);
 178:
 179:      Request request=new RequestSftp();
 180:      request.request(session, this);
 181:
 182:      thread=this;
 183:      buf=new Buffer();
 184:      packet=new Packet(buf);
 185:      int i=0;
 186:      int j=0;
 187:      int length;
 188:      int type;
 189:      byte[] str;
 190:
 191:      // send SSH_FXP_INIT
 192:      sendINIT();
 193:
 194:      // receive SSH_FXP_VERSION
 195:      buf.rewind();
 196:      i=io.in.read(buf.buffer, 0, buf.buffer.length);
 197:      length=buf.getInt();
 198:      type=buf.getByte();           // 2 -> SSH_FXP_VERSION
 199:      server_version=buf.getInt();
 200://System.out.println("SFTP protocol server-version="+server_version);
 201:
 202:      // send SSH_FXP_REALPATH
 203:      sendREALPATH(".".getBytes());
 204:
 205:      // receive SSH_FXP_NAME
 206:      buf.rewind();
 207:      i=io.in.read(buf.buffer, 0, buf.buffer.length);
 208:      length=buf.getInt();
 209:      type=buf.getByte();          // 104 -> SSH_FXP_NAME
 210:      buf.getInt();                //
 211:      i=buf.getInt();              // count
 212:      str=buf.getString();         // filename
 213:      home=cwd=new String(str);
 214:      str=buf.getString();         // logname
 215://    SftpATTRS.getATTR(buf);           // attrs
 216:
 217:      //lcwd=new File(".").getAbsolutePath();
 218:      lcwd=new File(".").getCanonicalPath();
 219:    }
 220:	      catch(Exception e){
 221:      //System.out.println(e);
 222:      if(e instanceof JSchException) throw (JSchException)e;
 223:      throw new JSchException(e.toString());
 224:    }
 225:  }
 226:
 227:  public void quit(){ disconnect();}
 228:  public void exit(){ disconnect();}
 229:	    public void lcd(String path) throws SftpException{
 230://    if(!path.startsWith("/")){ path=lcwd+file_separator+path; }
 231:    if(!isLocalAbsolutePath(path)){ path=lcwd+file_separator+path; }
 232:	      if((new File(path)).isDirectory()){
 233:	        try{
 234:    //path=(new File(path)).getAbsolutePath();
 235:    path=(new File(path)).getCanonicalPath();
 236:      }
 237:      catch(Exception e){}
 238:      lcwd=path;
 239:      return;
 240:    }
 241:    throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such directory");
 242:  }
 243:
 244:  /*
 245:      cd /tmp
 246:      c->s REALPATH
 247:      s->c NAME
 248:      c->s STAT
 249:      s->c ATTR 
 250:  */
 251:	    public void cd(String path) throws SftpException{
 252:	      try{
 253:      if(!path.startsWith("/")){ path=cwd+"/"+path; }
 254:
 255:      Vector v=glob_remote(path);
 256:	        if(v.size()!=1){
 257:    throw new SftpException(SSH_FX_FAILURE, v.toString());
 258:      }
 259:      path=(String)(v.elementAt(0));
 260:
 261:      sendREALPATH(path.getBytes());
 262:
 263:      buf.rewind();
 264:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
 265:      int length=buf.getInt();
 266:      int type=buf.getByte();
 267:	        if(type!=101 && type!=104){
 268:    throw new SftpException(SSH_FX_FAILURE, "");
 269:      }
 270:	        if(type==101){
 271:    buf.getInt();
 272:    i=buf.getInt();
 273:    throwStatusError(buf, i);
 274://    byte[] str=buf.getString();
 275://    throw new SftpException(i, new String(str));
 276:      }
 277:      buf.getInt();
 278:      i=buf.getInt();
 279:      byte[] str=buf.getString();
 280:	        if(str!=null && str[0]!='/'){
 281:        str=(cwd+"/"+new String(str)).getBytes();
 282:      }
 283:      cwd=new String(str);
 284:      str=buf.getString();         // logname
 285:      i=buf.getInt();              // attrs
 286:    }
 287:	      catch(Exception e){
 288:      if(e instanceof SftpException) throw (SftpException)e;
 289:      throw new SftpException(SSH_FX_FAILURE, "");
 290:    }
 291:  }
 292:
 293:  /*
 294:      put foo
 295:      c->s OPEN
 296:      s->c HANDLE
 297:      c->s WRITE
 298:      s->c STATUS
 299:      c->s CLOSE 
 300:      s->c STATUS 
 301:  */
 302:	    public void put(String src, String dst) throws SftpException{
 303:    put(src, dst, null, OVERWRITE);
 304:  }
 305:	    public void put(String src, String dst, int mode) throws SftpException{
 306:    put(src, dst, null, mode);
 307:  }
 308:  public void put(String src, String dst, 
 309:	            SftpProgressMonitor monitor) throws SftpException{
 310:    put(src, dst, monitor, OVERWRITE);
 311:  }
 312:  public void put(String src, String dst, 
 313:	            SftpProgressMonitor monitor, int mode) throws SftpException{
 314://    if(!src.startsWith("/")){ src=lcwd+file_separator+src; } 
 315:    if(!isLocalAbsolutePath(src)){ src=lcwd+file_separator+src; } 
 316:    if(!dst.startsWith("/")){ dst=cwd+"/"+dst; }
 317://System.out.println("src: "+src+", "+dst);
 318:	      try{
 319:      Vector v=glob_remote(dst);
 320:	        if(v.size()!=1){
 321:        throw new SftpException(SSH_FX_FAILURE, v.toString());
 322:      }
 323:      dst=(String)(v.elementAt(0));
 324:
 325:      boolean isRemoteDir=isRemoteDir(dst);
 326:
 327:      v=glob_local(src);
 328://System.out.println("glob_local: "+v+" dst="+dst);
 329:	        for(int j=0; j<v.size(); j++){
 330:    String _src=(String)(v.elementAt(j));
 331:    String _dst=dst;
 332:	      if(isRemoteDir){
 333:	        if(!_dst.endsWith("/")){
 334:        _dst+="/";
 335:      }
 336:      int i=_src.lastIndexOf(file_separatorc);
 337:      if(i==-1) _dst+=_src;
 338:      else _dst+=_src.substring(i+1);
 339:    }
 340:
 341://System.out.println("_dst "+_dst);
 342:
 343:    long size_of_dst=0;
 344:	      if(mode==RESUME){
 345:	        try{
 346:        SftpATTRS attr=stat(_dst);
 347:        size_of_dst=attr.getSize();
 348:      }
 349:	        catch(Exception eee){
 350:        //System.out.println(eee);
 351:      }
 352:      long size_of_src=new File(_src).length();
 353:	        if(size_of_src<size_of_dst){
 354:        throw new SftpException(SSH_FX_FAILURE, "failed to resume for "+_dst);
 355:      }
 356:	        if(size_of_src==size_of_dst){
 357:        return;
 358:      }
 359:    }
 360:
 361:	          if(monitor!=null){
 362:       monitor.init(SftpProgressMonitor.PUT, _src, _dst,
 363:               (new File(_src)).length());
 364:	        if(mode==RESUME){
 365:        monitor.count(size_of_dst);
 366:      }
 367:        }
 368:
 369:        FileInputStream fis=new FileInputStream(_src);
 370:        put(fis, _dst, monitor, mode);
 371:        fis.close();
 372:      }
 373:    }
 374:	      catch(Exception e){
 375:      if(e instanceof SftpException) throw (SftpException)e;
 376:      throw new SftpException(SSH_FX_FAILURE, "");
 377:    }
 378:  }
 379:	    public void put(InputStream src, String dst) throws SftpException{
 380:    put(src, dst, null, OVERWRITE);
 381:  }
 382:	    public void put(InputStream src, String dst, int mode) throws SftpException{
 383:    put(src, dst, null, mode);
 384:  }
 385:  public void put(InputStream src, String dst, 
 386:	            SftpProgressMonitor monitor) throws SftpException{
 387:    put(src, dst, monitor, OVERWRITE);
 388:  }
 389:  public void put(InputStream src, String dst, 
 390:	            SftpProgressMonitor monitor, int mode) throws SftpException{
 391:	      try{
 392:      if(!dst.startsWith("/")){ dst=cwd+"/"+dst; } 
 393:      Vector v=glob_remote(dst);
 394:	        if(v.size()!=1){
 395:        throw new SftpException(SSH_FX_FAILURE, v.toString());
 396:      }
 397:      dst=(String)(v.elementAt(0));
 398:	        if(isRemoteDir(dst)){
 399:    throw new SftpException(SSH_FX_FAILURE, dst+" is a directory");
 400:      }
 401:
 402:      long skip=0;
 403:	        if(mode==RESUME || mode==APPEND){
 404:	      try{
 405:      SftpATTRS attr=stat(dst);
 406:      skip=attr.getSize();
 407:    }
 408:	      catch(Exception eee){
 409:      //System.out.println(eee);
 410:    }
 411:      }
 412:
 413:	        if(mode==RESUME && skip>0){
 414:    long skipped=src.skip(skip);
 415:	      if(skipped<skip){
 416:      throw new SftpException(SSH_FX_FAILURE, "failed to resume for "+dst);
 417:    }
 418:      }
 419:
 420:	        if(mode==OVERWRITE){
 421:    sendOPENW(dst.getBytes());
 422:      }
 423:	        else{
 424:    sendOPENA(dst.getBytes());
 425:      }
 426:
 427:      buf.rewind();
 428:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
 429:      int length=buf.getInt();
 430:      int type=buf.getByte();
 431:	        if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
 432:    throw new SftpException(SSH_FX_FAILURE, "");
 433:      }
 434:	        if(type==SSH_FXP_STATUS){
 435:    buf.getInt();
 436:    i=buf.getInt();
 437:    throwStatusError(buf, i);
 438:      }
 439:      buf.getInt();
 440:      byte[] handle=buf.getString();         // filename
 441:      byte[] data=new byte[1024];
 442:
 443:      long offset=0;
 444:	        if(mode==RESUME || mode==APPEND){
 445:    offset+=skip;
 446:      }
 447:	        while(true){
 448:        i=src.read(data, 0, 1024);
 449:        if(i<=0)break;
 450:        sendWRITE(handle, offset, data, 0, i);
 451:        offset+=i;
 452:
 453:        buf.rewind();
 454:    io.in.read(buf.buffer, 0, buf.buffer.length);
 455:    length=buf.getInt();
 456:    type=buf.getByte();
 457:    if(type!=SSH_FXP_STATUS){ break;}
 458:        buf.getInt();
 459:	          if(buf.getInt()!=SSH_FX_OK){
 460://System.out.println("getInt="+buf.getInt());
 461:          break;
 462:    }
 463:
 464:	      if(monitor!=null){
 465:	        if(!monitor.count(i)){
 466:        break;
 467:      }
 468:    }
 469:
 470:      }
 471:
 472:      sendCLOSE(handle);
 473://System.out.println("done");
 474:      if(monitor!=null)monitor.end();
 475:
 476:      buf.rewind();
 477:      i=io.in.read(buf.buffer, 0, buf.buffer.length);
 478:      length=buf.getInt();
 479:      type=buf.getByte();
 480:	        if(type!=SSH_FXP_STATUS){
 481:    throw new SftpException(SSH_FX_FAILURE, "");
 482:      }
 483:      buf.getInt();
 484:      i=buf.getInt();
 485:      if(i==SSH_FX_OK) return;
 486:      throwStatusError(buf, i);
 487:    }
 488:	      catch(Exception e){
 489:      if(e instanceof SftpException) throw (SftpException)e;
 490:      throw new SftpException(SSH_FX_FAILURE, "");
 491:    }
 492:  }
 493:	    public OutputStream put(String dst) throws SftpException{
 494:    return put(dst, (SftpProgressMonitor)null, OVERWRITE);
 495:  }
 496:	    public OutputStream put(String dst, final int mode) throws SftpException{
 497:    return put(dst, (SftpProgressMonitor)null, mode);
 498:  }
 499:	    public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode) throws SftpException{
 500:    if(!dst.startsWith("/")){ dst=cwd+"/"+dst; } 
 501:	      try{
 502:      Vector v=glob_remote(dst);
 503:	        if(v.size()!=1){
 504:    throw new SftpException(SSH_FX_FAILURE, v.toString());
 505:      }
 506:      dst=(String)(v.elementAt(0));
 507:	        if(isRemoteDir(dst)){
 508:    throw new SftpException(SSH_FX_FAILURE, dst+" is a directory");
 509:      }
 510:      PipedOutputStream pos=new java.io.PipedOutputStream();
 511:
 512:      final PipedInputStream pis=new java.io.PipedInputStream(pos);
 513:      final ChannelSftp channel=this;
 514:      final String _dst=dst;
 515:	        new Thread(new Runnable(){
 516:	        public void run(){
 517:        try{ channel.put(pis, _dst, monitor, mode); }
 518:	          catch(Exception ee){
 519:          System.out.println("!!"+ee);
 520:        }
 521:        try{ pis.close(); }catch(Exception ee){}
 522:      }
 523:    }).start();
 524:      return pos;
 525:    }
 526:	      catch(Exception e){
 527:      if(e instanceof SftpException) throw (SftpException)e;
 528:      throw new SftpException(SSH_FX_FAILURE, "");
 529:    }
 530:  }
 531:	    public void get(String src, String dst) throws SftpException{
 532:    get(src, dst, null, OVERWRITE);
 533:  }
 534:  public void get(String src, String dst,
 535:	            SftpProgressMonitor monitor) throws SftpException{
 536:    get(src, dst, monitor, OVERWRITE);
 537:  }
 538:  public void get(String src, String dst,
 539:	            SftpProgressMonitor monitor, int mode) throws SftpException{
 540:    if(!src.startsWith("/")){ src=cwd+"/"+src; } 
 541://    if(!dst.startsWith("/")){ dst=lcwd+file_separator+dst; } 
 542:    if(!isLocalAbsolutePath(dst)){ dst=lcwd+file_separator+dst; } 
 543:	      try{
 544:      Vector v=glob_remote(src);
 545:	        for(int j=0; j<v.size(); j++){
 546:    String _dst=dst;
 547:    String _src=(String)(v.elementAt(j));
 548:	      if((new File(_dst)).isDirectory()){
 549:	        if(!_dst.endsWith(file_separator)){
 550:        _dst+=file_separator;
 551:      }
 552:      int i=_src.lastIndexOf('/');
 553:      if(i==-1) _dst+=src;
 554:      else _dst+=_src.substring(i+1);
 555:    }
 556:
 557:    SftpATTRS attr=stat(_src);
 558:	      if(mode==RESUME){
 559:      long size_of_src=attr.getSize();
 560:      long size_of_dst=new File(_dst).length();
 561:	        if(size_of_dst>size_of_src){
 562:        throw new SftpException(SSH_FX_FAILURE, "failed to resume for "+_dst);
 563:      }
 564:	        if(size_of_dst==size_of_src){
 565:        return;
 566:      }
 567:    }
 568:
 569:	      if(monitor!=null){
 570:      monitor.init(SftpProgressMonitor.GET, _src, _dst, attr.getSize());
 571:	        if(mode==RESUME){
 572:        monitor.count(new File(_dst).length());
 573:      }
 574:    }
 575:    FileOutputStream fos=null;
 576:	      if(mode==OVERWRITE){
 577:      fos=new FileOutputStream(_dst);
 578:    }
 579:	      else{
 580:      fos=new FileOutputStream(_dst, true); // append
 581:    }
 582:    get(_src, fos, monitor, mode, new File(_dst).length());
 583:    fos.close();
 584:      }
 585:    }
 586:	      catch(Exception e){
 587:      if(e instanceof SftpException) throw (SftpException)e;
 588:      throw new SftpException(SSH_FX_FAILURE, "");
 589:    }
 590:  }
 591:	    public void get(String src, OutputStream dst) throws SftpException{
 592:    get(src, dst, null, OVERWRITE, 0);
 593:  }
 594:  public void get(String src, OutputStream dst,
 595:	            SftpProgressMonitor monitor) throws SftpException{
 596:    get(src, dst, monitor, OVERWRITE, 0);
 597:  }
 598:  private void get(String src, OutputStream dst,
 599:	             SftpProgressMonitor monitor, int mode, long skip) throws SftpException{
 600://System.out.println("get: "+src+", "+dst);
 601:	      try{
 602:      if(!src.startsWith("/")){ src=cwd+"/"+src; } 
 603:      Vector v=glob_remote(src);
 604:	        if(v.size()!=1){
 605:        throw new SftpException(SSH_FX_FAILURE, v.toString());
 606:      }
 607:      src=(String)(v.elementAt(0));
 608:
 609:      sendOPENR(src.getBytes());
 610:      buf.rewind();
 611:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
 612:      int length=buf.getInt();
 613:      int type=buf.getByte();
 614:	        if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
 615:    throw new SftpException(SSH_FX_FAILURE, "");
 616:      }
 617:	        if(type==SSH_FXP_STATUS){
 618:    buf.getInt();
 619:    i=buf.getInt();
 620:    throwStatusError(buf, i);
 621:      }
 622:      buf.getInt();
 623:      byte[] handle=buf.getString();         // filename
 624:
 625:      byte[] data=null;
 626:      int[] data_start=new int[1];
 627:      int[] data_len=new int[1];
 628:
 629:      long offset=0;
 630:	        if(mode==RESUME){
 631:    offset+=skip;
 632:      }
 633:	        while(true){
 634:        sendREAD(handle, offset, 1000);
 635:        buf.rewind();
 636:    i=io.in.read(buf.buffer, 0, buf.buffer.length);
 637:    length=buf.getInt();
 638:    type=buf.getByte();
 639:        buf.getInt();
 640:    if(type!=SSH_FXP_STATUS && type!=SSH_FXP_DATA){ break;}
 641:	      if(type==SSH_FXP_STATUS){
 642:       i=buf.getInt();
 643:	        if(i==SSH_FX_EOF){
 644:         break;
 645:       }
 646:       throwStatusError(buf, i);
 647:    }
 648:    data=buf.getString(data_start, data_len);
 649:        dst.write(data, data_start[0], data_len[0]);
 650:    dst.flush();
 651:	      if(monitor!=null){
 652:	        if(!monitor.count(data_len[0])){
 653:        break;
 654:      }
 655:    }
 656:        offset+=data_len[0];
 657:      }
 658:      sendCLOSE(handle);
 659:
 660:	        if(monitor!=null){
 661:    monitor.end();
 662:      }
 663:
 664:      buf.rewind();
 665:      i=io.in.read(buf.buffer, 0, buf.buffer.length);
 666:      length=buf.getInt();
 667:      type=buf.getByte();
 668:	        if(type!=SSH_FXP_STATUS){
 669:    throw new SftpException(SSH_FX_FAILURE, "");
 670:      }
 671:      buf.getInt();
 672:      i=buf.getInt();
 673:      if(i==SSH_FX_OK) return;
 674:      throwStatusError(buf, i);
 675:    }
 676:	      catch(Exception e){
 677:      if(e instanceof SftpException) throw (SftpException)e;
 678:      throw new SftpException(SSH_FX_FAILURE, "");
 679:    }
 680:  }
 681:	    public InputStream get(String src) throws SftpException{
 682:    return get(src, null, OVERWRITE);
 683:  }
 684:	    public InputStream get(String src, int mode) throws SftpException{
 685:    return get(src, null, mode);
 686:  }
 687:	    public InputStream get(String src, final SftpProgressMonitor monitor, final int mode) throws SftpException{
 688:	      if(mode==RESUME){
 689:      throw new SftpException(SSH_FX_FAILURE, "faile to resume from "+src);
 690:    }
 691:    if(!src.startsWith("/")){ src=cwd+"/"+src; } 
 692:	      try{
 693:      Vector v=glob_remote(src);
 694:	        if(v.size()!=1){
 695:        throw new SftpException(SSH_FX_FAILURE, v.toString());
 696:      }
 697:      src=(String)(v.elementAt(0));
 698:
 699:      SftpATTRS attr=stat(src);
 700:
 701:      final PipedInputStream pis=new java.io.PipedInputStream();
 702:      final PipedOutputStream pos=new java.io.PipedOutputStream(pis);
 703:      final ChannelSftp channel=this;
 704:      final String _src=src;
 705:
 706:	        if(attr.getSize()<=0){
 707:        try{ pos.close(); }catch(Exception ee){}
 708:    return pis;
 709:      }
 710:
 711:      final Exception[] closed=new Exception[1];
 712:      closed[0]=null;
 713:	        new Thread(new Runnable(){
 714:	        public void run(){
 715:        try{ channel.get(_src, pos, monitor, mode, (long)0); }
 716:	          catch(Exception ee){
 717:          //System.out.println("!!"+ee);
 718:          closed[0]=ee;
 719://          try{ pis.close(); }catch(Exception eee){}
 720:        }
 721://System.out.println("channel.get end");
 722:        try{ pos.close(); }catch(Exception ee){}
 723://System.out.println("pos.close end");
 724:      }
 725:    }).start();
 726:	        while(true){
 727:    if(pis.available()!=0)break;
 728:	      if(closed[0]!=null){
 729:      throw closed[0];
 730:    }
 731://    System.out.println("pis wait");
 732:    Thread.sleep(1000);
 733:      }
 734:      return pis;
 735:    }
 736:	      catch(Exception e){
 737:      if(e instanceof SftpException) throw (SftpException)e;
 738:      throw new SftpException(SSH_FX_FAILURE, "");
 739:    }
 740:  }
 741:	    public Vector ls(String path) throws SftpException{
 742:	      try{
 743:      if(!path.startsWith("/")){ path=cwd+"/"+path; }
 744:
 745:      String dir=path;
 746:      byte[] pattern=null;
 747:	        if(!isRemoteDir(dir)){
 748:    int foo=path.lastIndexOf('/');
 749:    dir=path.substring(0, foo);
 750:    pattern=path.substring(foo+1).getBytes();
 751:      }
 752:
 753:      sendOPENDIR(dir.getBytes());
 754:
 755:      buf.rewind();
 756:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
 757:      int length=buf.getInt();
 758:      int type=buf.getByte();
 759:	        if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
 760:    throw new SftpException(SSH_FX_FAILURE, "");
 761:      }
 762:	        if(type==SSH_FXP_STATUS){
 763:    buf.getInt();
 764:    i=buf.getInt();
 765:    throwStatusError(buf, i);
 766:      }
 767:      buf.getInt();
 768:      byte[] handle=buf.getString();         // filename
 769:
 770:      Vector v=new java.util.Vector();
 771:	        while(true){
 772:        sendREADDIR(handle);
 773:        buf.rewind();
 774:        i=io.in.read(buf.buffer, 0, buf.buffer.length);
 775:        buf.index=i;
 776:        length=buf.getInt();
 777:        length=length-(i-4);
 778:        type=buf.getByte();
 779:
 780:	          if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
 781:      throw new SftpException(SSH_FX_FAILURE, "");
 782:    }
 783:	          if(type==SSH_FXP_STATUS){ 
 784:      /*
 785:      buf.getInt();
 786:      i=buf.getInt();
 787:      System.out.println("i="+i);
 788:      if(i==SSH_FX_EOF) break;
 789:      byte[] str=buf.getString();
 790:      throw new SftpException(i, new String(str));
 791:      */
 792:      break;
 793:    }
 794:
 795:        buf.getInt();
 796:        int count=buf.getInt();
 797:
 798:        byte[] str;
 799:        int flags;
 800:
 801:	          while(count>0){
 802:	            if(length>0){
 803:            buf.shift();
 804:            i=io.in.read(buf.buffer, buf.index, buf.buffer.length-buf.index);
 805:          if(i<=0)break;
 806:        buf.index+=i;
 807:            length-=i;
 808:      }
 809:
 810:      byte[] filename=buf.getString();
 811:      // System.out.println("filename: "+new String(filename));
 812:      str=buf.getString();
 813:      String longname=new String(str);
 814:      // System.out.println("longname: "+longname);
 815:
 816:      SftpATTRS attrs=SftpATTRS.getATTR(buf);
 817:	        if(pattern==null || Util.glob(pattern, filename)){
 818:          v.addElement(longname);
 819://        v.addElement(new Ssh_exp_name(new String(filename), longname, attrs));
 820:      }
 821:
 822:      count--; 
 823:        }
 824:      }
 825:
 826:      sendCLOSE(handle);
 827:      buf.rewind();
 828:      i=io.in.read(buf.buffer, 0, buf.buffer.length);
 829:      length=buf.getInt();
 830:      type=buf.getByte();
 831:	        if(type!=SSH_FXP_STATUS){
 832:    throw new SftpException(SSH_FX_FAILURE, "");
 833:      }
 834:      buf.getInt();
 835:      i=buf.getInt();
 836:      if(i==SSH_FX_OK) return v;
 837:      throwStatusError(buf, i);
 838:    }
 839:	      catch(Exception e){
 840:      if(e instanceof SftpException) throw (SftpException)e;
 841:      throw new SftpException(SSH_FX_FAILURE, "");
 842:    }
 843:    return null;
 844:  }
 845:	    public void symlink(String oldpath, String newpath) throws SftpException{
 846:	      if(server_version<3){
 847:      throw new SftpException(SSH_FX_FAILURE, 
 848:                  "The remote sshd is too old to support symlink operation.");
 849:    }
 850:
 851:	      try{
 852:      if(!oldpath.startsWith("/")){ oldpath=cwd+"/"+oldpath; } 
 853:      if(!newpath.startsWith("/")){ newpath=cwd+"/"+newpath; } 
 854:
 855:      Vector v=glob_remote(oldpath);
 856:	        if(v.size()!=1){
 857:    throw new SftpException(SSH_FX_FAILURE, v.toString());
 858:      }
 859:      oldpath=(String)(v.elementAt(0));
 860:
 861:      sendSYMLINK(oldpath.getBytes(), newpath.getBytes());
 862:      buf.rewind();
 863:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
 864:      int length=buf.getInt();
 865:      int type=buf.getByte();
 866:	        if(type!=SSH_FXP_STATUS){
 867:    throw new SftpException(SSH_FX_FAILURE, "");
 868:      }
 869:      buf.getInt();
 870:      i=buf.getInt();
 871:      if(i==SSH_FX_OK) return;
 872:      throwStatusError(buf, i);
 873:    }
 874:	      catch(Exception e){
 875:      if(e instanceof SftpException) throw (SftpException)e;
 876:      throw new SftpException(SSH_FX_FAILURE, "");
 877:    }
 878:  }
 879:	    public void rename(String oldpath, String newpath) throws SftpException{
 880:	      if(server_version<2){
 881:      throw new SftpException(SSH_FX_FAILURE, 
 882:                  "The remote sshd is too old to support rename operation.");
 883:    }
 884:	      try{
 885:      if(!oldpath.startsWith("/")){ oldpath=cwd+"/"+oldpath; } 
 886:      if(!newpath.startsWith("/")){ newpath=cwd+"/"+newpath; } 
 887:
 888:      Vector v=glob_remote(oldpath);
 889:	        if(v.size()!=1){
 890:    throw new SftpException(SSH_FX_FAILURE, v.toString());
 891:      }
 892:      oldpath=(String)(v.elementAt(0));
 893:
 894:      v=glob_remote(newpath);
 895:	        if(v.size()>=2){
 896:    throw new SftpException(SSH_FX_FAILURE, v.toString());
 897:      }
 898:	        if(v.size()==1){
 899:        newpath=(String)(v.elementAt(0));
 900:      }
 901:
 902:      sendRENAME(oldpath.getBytes(), newpath.getBytes());
 903:      buf.rewind();
 904:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
 905:      int length=buf.getInt();
 906:      int type=buf.getByte();
 907:	        if(type!=SSH_FXP_STATUS){
 908:    throw new SftpException(SSH_FX_FAILURE, "");
 909:      }
 910:      buf.getInt();
 911:      i=buf.getInt();
 912:      if(i==SSH_FX_OK) return;
 913:      throwStatusError(buf, i);
 914:    }
 915:	      catch(Exception e){
 916:      if(e instanceof SftpException) throw (SftpException)e;
 917:      throw new SftpException(SSH_FX_FAILURE, "");
 918:    }
 919:  }
 920:	    public void rm(String path) throws SftpException{
 921:	      try{
 922:      if(!path.startsWith("/")){ path=cwd+"/"+path; }
 923:      Vector v=glob_remote(path);
 924:	        for(int j=0; j<v.size(); j++){
 925:    path=(String)(v.elementAt(j));
 926:        sendREMOVE(path.getBytes());
 927:        buf.rewind();
 928:        int i=io.in.read(buf.buffer, 0, buf.buffer.length);
 929:        int length=buf.getInt();
 930:        int type=buf.getByte();
 931:	          if(type!=SSH_FXP_STATUS){
 932:      throw new SftpException(SSH_FX_FAILURE, "");
 933:        }
 934:        buf.getInt();
 935:        i=buf.getInt();
 936:	      if(i!=SSH_FX_OK){
 937:      throwStatusError(buf, i);
 938:    }
 939:      }
 940:    }
 941:	      catch(Exception e){
 942:      if(e instanceof SftpException) throw (SftpException)e;
 943:      throw new SftpException(SSH_FX_FAILURE, "");
 944:    }
 945:  }
 946:	    boolean isRemoteDir(String path){
 947:	      try{
 948:      sendSTAT(path.getBytes());
 949:      buf.rewind();
 950:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
 951:      int length=buf.getInt();
 952:      int type=buf.getByte();
 953:      if(type!=SSH_FXP_ATTRS){ return false; }
 954:      buf.getInt();
 955:      SftpATTRS attr=SftpATTRS.getATTR(buf);
 956:      return attr.isDir();
 957:    }
 958:    catch(Exception e){}
 959:    return false;
 960:  }
 961:	    public void chgrp(int gid, String path) throws SftpException{
 962:	      try{
 963:      if(!path.startsWith("/")){ path=cwd+"/"+path; }
 964:
 965:      Vector v=glob_remote(path);
 966:	        for(int j=0; j<v.size(); j++){
 967:    path=(String)(v.elementAt(j));
 968:        sendSTAT(path.getBytes());
 969: 
 970:        buf.rewind();
 971:        int i=io.in.read(buf.buffer, 0, buf.buffer.length);
 972:        int length=buf.getInt();
 973:        int type=buf.getByte();
 974:	          if(type!=SSH_FXP_ATTRS){
 975:      throw new SftpException(SSH_FX_FAILURE, "");
 976:    }
 977:    buf.getInt();
 978:    SftpATTRS attr=SftpATTRS.getATTR(buf);
 979:    attr.setUIDGID(attr.uid, gid); 
 980:    _setStat(path, attr);
 981:      }
 982:    }
 983:	      catch(Exception e){
 984:      if(e instanceof SftpException) throw (SftpException)e;
 985:      throw new SftpException(SSH_FX_FAILURE, "");
 986:    }
 987:  }
 988:	    public void chown(int uid, String path) throws SftpException{
 989:	      try{
 990:      if(!path.startsWith("/")){ path=cwd+"/"+path; }
 991:
 992:      Vector v=glob_remote(path);
 993:	        for(int j=0; j<v.size(); j++){
 994:    path=(String)(v.elementAt(j));
 995:
 996:    sendSTAT(path.getBytes());
 997: 
 998:    buf.rewind();
 999:    int i=io.in.read(buf.buffer, 0, buf.buffer.length);
1000:    int length=buf.getInt();
1001:    int type=buf.getByte();
1002:	      if(type!=SSH_FXP_ATTRS){
1003:      throw new SftpException(SSH_FX_FAILURE, "");
1004:    }
1005:    buf.getInt();
1006:    SftpATTRS attr=SftpATTRS.getATTR(buf);
1007:    attr.setUIDGID(uid, attr.gid); 
1008:    _setStat(path, attr);
1009:      }
1010:    }
1011:	      catch(Exception e){
1012:      if(e instanceof SftpException) throw (SftpException)e;
1013:      throw new SftpException(SSH_FX_FAILURE, "");
1014:    }
1015:  }
1016:	    public void chmod(int permissions, String path) throws SftpException{
1017:	      try{
1018:      if(!path.startsWith("/")){ path=cwd+"/"+path; }
1019:
1020:      Vector v=glob_remote(path);
1021:	        for(int j=0; j<v.size(); j++){
1022:    path=(String)(v.elementAt(j));
1023:
1024:    sendSTAT(path.getBytes());
1025: 
1026:    buf.rewind();
1027:    int i=io.in.read(buf.buffer, 0, buf.buffer.length);
1028:    int length=buf.getInt();
1029:    int type=buf.getByte();
1030:	      if(type!=SSH_FXP_ATTRS){
1031:      throw new SftpException(SSH_FX_FAILURE, "");
1032:    }
1033:    buf.getInt();
1034:    SftpATTRS attr=SftpATTRS.getATTR(buf);
1035:    attr.setPERMISSIONS(permissions); 
1036:    _setStat(path, attr);
1037:      }
1038:    }
1039:	      catch(Exception e){
1040:      if(e instanceof SftpException) throw (SftpException)e;
1041:      throw new SftpException(SSH_FX_FAILURE, "");
1042:    }
1043:  }
1044:	    public void setMtime(String path, int mtime) throws SftpException{
1045:	      try{
1046:      if(!path.startsWith("/")){ path=cwd+"/"+path; }
1047:
1048:      Vector v=glob_remote(path);
1049:	        for(int j=0; j<v.size(); j++){
1050:    path=(String)(v.elementAt(j));
1051:    sendSTAT(path.getBytes());
1052:    buf.rewind();
1053:    int i=io.in.read(buf.buffer, 0, buf.buffer.length);
1054:    int length=buf.getInt();
1055:    int type=buf.getByte();
1056:	      if(type!=SSH_FXP_ATTRS){
1057:      throw new SftpException(SSH_FX_FAILURE, "");
1058:    }
1059:    buf.getInt();
1060:    SftpATTRS attr=SftpATTRS.getATTR(buf);
1061:    attr.setACMODTIME(attr.getATime(), mtime);
1062:    _setStat(path, attr);
1063:      }
1064:    }
1065:	      catch(Exception e){
1066:      if(e instanceof SftpException) throw (SftpException)e;
1067:      throw new SftpException(SSH_FX_FAILURE, "");
1068:    }
1069:  }
1070:	    public void rmdir(String path) throws SftpException{
1071:	      try{
1072:      if(!path.startsWith("/")){ path=cwd+"/"+path; }
1073:      Vector v=glob_remote(path);
1074:	        for(int j=0; j<v.size(); j++){
1075:    path=(String)(v.elementAt(j));
1076:
1077:    sendRMDIR(path.getBytes());
1078:    buf.rewind();
1079:    int i=io.in.read(buf.buffer, 0, buf.buffer.length);
1080:    int length=buf.getInt();
1081:    int type=buf.getByte();
1082:	      if(type!=SSH_FXP_STATUS){
1083:      throw new SftpException(SSH_FX_FAILURE, "");
1084:    }
1085:    buf.getInt();
1086:    i=buf.getInt();
1087:	      if(i!=SSH_FX_OK){
1088:      throwStatusError(buf, i);
1089:    }
1090:      }
1091:    }
1092:	      catch(Exception e){
1093:      if(e instanceof SftpException) throw (SftpException)e;
1094:      throw new SftpException(SSH_FX_FAILURE, "");
1095:    }
1096:  }
1097:
1098:	    public void mkdir(String path) throws SftpException{
1099:	      try{
1100:     if(!path.startsWith("/")){ path=cwd+"/"+path; }
1101:      sendMKDIR(path.getBytes(), null);
1102:      buf.rewind();
1103:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
1104:      int length=buf.getInt();
1105:      int type=buf.getByte();
1106:	        if(type!=SSH_FXP_STATUS){
1107:    throw new SftpException(SSH_FX_FAILURE, "");
1108:      }
1109:      buf.getInt();
1110:      i=buf.getInt();
1111:      if(i==SSH_FX_OK) return;
1112:      throwStatusError(buf, i);
1113:    }
1114:	      catch(Exception e){
1115:      if(e instanceof SftpException) throw (SftpException)e;
1116:      throw new SftpException(SSH_FX_FAILURE, "");
1117:    }
1118:  }
1119:
1120:	    public SftpATTRS stat(String path) throws SftpException{
1121:	      try{
1122:     if(!path.startsWith("/")){ path=cwd+"/"+path; }
1123:      sendSTAT(path.getBytes());
1124:      buf.rewind();
1125:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
1126:      int length=buf.getInt();
1127:      int type=buf.getByte();
1128:	        if(type!=SSH_FXP_ATTRS){
1129:	      if(type==SSH_FXP_STATUS){
1130:      buf.getInt();
1131:      i=buf.getInt();
1132:      throwStatusError(buf, i);
1133:    }
1134:    throw new SftpException(SSH_FX_FAILURE, "");
1135:      }
1136:      buf.getInt();
1137:      SftpATTRS attr=SftpATTRS.getATTR(buf);
1138:      return attr;
1139:    }
1140:	      catch(Exception e){
1141:      if(e instanceof SftpException) throw (SftpException)e;
1142:      throw new SftpException(SSH_FX_FAILURE, "");
1143:    }
1144:    //return null;
1145:  }
1146:	    public SftpATTRS lstat(String path) throws SftpException{
1147:	      try{
1148:     if(!path.startsWith("/")){ path=cwd+"/"+path; }
1149:      sendLSTAT(path.getBytes());
1150:      buf.rewind();
1151:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
1152:      int length=buf.getInt();
1153:      int type=buf.getByte();
1154:	        if(type!=SSH_FXP_ATTRS){
1155:	      if(type==SSH_FXP_STATUS){
1156:      buf.getInt();
1157:      i=buf.getInt();
1158:      throwStatusError(buf, i);
1159:    }
1160:    throw new SftpException(SSH_FX_FAILURE, "");
1161:      }
1162:      buf.getInt();
1163:      SftpATTRS attr=SftpATTRS.getATTR(buf);
1164:      return attr;
1165:    }
1166:	      catch(Exception e){
1167:      if(e instanceof SftpException) throw (SftpException)e;
1168:      throw new SftpException(SSH_FX_FAILURE, "");
1169:    }
1170:  }
1171:	    public void setStat(String path, SftpATTRS attr) throws SftpException{
1172:	      try{
1173:      if(!path.startsWith("/")){ path=cwd+"/"+path; }
1174:      Vector v=glob_remote(path);
1175:	        for(int j=0; j<v.size(); j++){
1176:    path=(String)(v.elementAt(j));
1177:    _setStat(path, attr);
1178:      }
1179:    }
1180:	      catch(Exception e){
1181:      if(e instanceof SftpException) throw (SftpException)e;
1182:      throw new SftpException(SSH_FX_FAILURE, "");
1183:    }
1184:  }
1185:	    private void _setStat(String path, SftpATTRS attr) throws SftpException{
1186:	      try{
1187:      sendSETSTAT(path.getBytes(), attr);
1188:
1189:      buf.rewind();
1190:      int i=io.in.read(buf.buffer, 0, buf.buffer.length);
1191:      int length=buf.getInt();
1192:      int type=buf.getByte();
1193:	        if(type!=SSH_FXP_STATUS){
1194:    throw new SftpException(SSH_FX_FAILURE, "");
1195:      }
1196:      buf.getInt();
1197:      i=buf.getInt();
1198:	        if(i!=SSH_FX_OK){
1199:    throwStatusError(buf, i);
1200:      }
1201:    }
1202:	      catch(Exception e){
1203:      if(e instanceof SftpException) throw (SftpException)e;
1204:      throw new SftpException(SSH_FX_FAILURE, "");
1205:    }
1206:  }
1207:
1208:  public String pwd(){ return cwd; }
1209:  public String lpwd(){ return lcwd; }
1210:  public String version(){ return version; }
1211:
1212:	    private void sendINIT() throws Exception{
1213:    packet.reset();
1214:    putHEAD(SSH_FXP_INIT, 5);
1215:    buf.putInt(3);                // version 3
1216:   session.write(packet, this, 5+4);
1217:  }
1218:
1219:	    private void sendREALPATH(byte[] path) throws Exception{
1220:    sendPacketPath(SSH_FXP_REALPATH, path);
1221:  }
1222:	    private void sendSTAT(byte[] path) throws Exception{
1223:    sendPacketPath(SSH_FXP_STAT, path);
1224:  }
1225:	    private void sendLSTAT(byte[] path) throws Exception{
1226:    sendPacketPath(SSH_FXP_LSTAT, path);
1227:  }
1228:	    private void sendFSTAT(byte[] handle) throws Exception{
1229:    sendPacketPath(SSH_FXP_FSTAT, handle);
1230:  }
1231:	    private void sendSETSTAT(byte[] path, SftpATTRS attr) throws Exception{
1232:    packet.reset();
1233:    putHEAD(SSH_FXP_SETSTAT, 9+path.length+attr.length());
1234:    buf.putInt(count++);
1235:    buf.putString(path);             // path
1236:    attr.dump(buf);
1237:    session.write(packet, this, 9+path.length+attr.length()+4);
1238:  }
1239:	    private void sendREMOVE(byte[] path) throws Exception{
1240:    sendPacketPath(SSH_FXP_REMOVE, path);
1241:  }
1242:	    private void sendMKDIR(byte[] path, SftpATTRS attr) throws Exception{
1243:    packet.reset();
1244:    putHEAD(SSH_FXP_MKDIR, 9+path.length+(attr!=null?attr.length():4));
1245:    buf.putInt(count++);
1246:    buf.putString(path);             // path
1247:    if(attr!=null) attr.dump(buf);
1248:    else buf.putInt(0);
1249:    session.write(packet, this, 9+path.length+(attr!=null?attr.length():4)+4);
1250:  }
1251:	    private void sendRMDIR(byte[] path) throws Exception{
1252:    sendPacketPath(SSH_FXP_RMDIR, path);
1253:  }
1254:	    private void sendSYMLINK(byte[] p1, byte[] p2) throws Exception{
1255:    sendPacketPath(SSH_FXP_SYMLINK, p1, p2);
1256:  }
1257:	    private void sendREADLINK(byte[] path) throws Exception{
1258:    sendPacketPath(SSH_FXP_READLINK, path);
1259:  }
1260:	    private void sendOPENDIR(byte[] path) throws Exception{
1261:    sendPacketPath(SSH_FXP_OPENDIR, path);
1262:  }
1263:	    private void sendREADDIR(byte[] path) throws Exception{
1264:    sendPacketPath(SSH_FXP_READDIR, path);
1265:  }
1266:	    private void sendRENAME(byte[] p1, byte[] p2) throws Exception{
1267:    sendPacketPath(SSH_FXP_RENAME, p1, p2);
1268:  }
1269:	    private void sendCLOSE(byte[] path) throws Exception{
1270:    sendPacketPath(SSH_FXP_CLOSE, path);
1271:  }
1272:	    private void sendOPENR(byte[] path) throws Exception{
1273:    sendOPEN(path, SSH_FXF_READ);
1274:  }
1275:	    private void sendOPENW(byte[] path) throws Exception{
1276:    sendOPEN(path, SSH_FXF_WRITE|SSH_FXF_CREAT|SSH_FXF_TRUNC);
1277:  }
1278:	    private void sendOPENA(byte[] path) throws Exception{
1279:    sendOPEN(path, SSH_FXF_WRITE|/*SSH_FXF_APPEND|*/SSH_FXF_CREAT);
1280:  }
1281:	    private void sendOPEN(byte[] path, int mode) throws Exception{
1282:    packet.reset();
1283:    putHEAD(SSH_FXP_OPEN, 17+path.length);
1284:    buf.putInt(count++);
1285:    buf.putString(path);
1286:    buf.putInt(mode);
1287:    buf.putInt(0);           // attrs
1288:    session.write(packet, this, 17+path.length+4);
1289:  }
1290:	    private void sendPacketPath(byte fxp, byte[] path) throws Exception{
1291:    packet.reset();
1292:    putHEAD(fxp, 9+path.length);
1293:    buf.putInt(count++);
1294:    buf.putString(path);             // path
1295:    session.write(packet, this, 9+path.length+4);
1296:  }
1297:	    private void sendPacketPath(byte fxp, byte[] p1, byte[] p2) throws Exception{
1298:    packet.reset();
1299:    putHEAD(fxp, 13+p1.length+p2.length);
1300:    buf.putInt(count++);
1301:    buf.putString(p1);
1302:    buf.putString(p2);
1303:    session.write(packet, this, 13+p1.length+p2.length+4);
1304:  }
1305:
1306:  private void sendWRITE(byte[] handle, long offset, 
1307:	               byte[] data, int start, int length) throws Exception{
1308:    packet.reset();
1309:    putHEAD(SSH_FXP_WRITE, 21+handle.length+length);
1310:    buf.putInt(count++);
1311:    buf.putString(handle);
1312:    buf.putLong(offset);
1313:    buf.putString(data, start, length);
1314:    session.write(packet, this, 21+handle.length+length+4);
1315:  }
1316:
1317:	    private void sendREAD(byte[] handle, long offset, int length) throws Exception{
1318:    packet.reset();
1319:    putHEAD(SSH_FXP_READ, 21+handle.length);
1320:    buf.putInt(count++);
1321:    buf.putString(handle);
1322:    buf.putLong(offset);
1323:    buf.putInt(length);
1324:    session.write(packet, this, 21+handle.length+4);
1325:  }
1326:
1327:	    private void putHEAD(byte type, int length) throws Exception{
1328:    buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
1329:    buf.putInt(recipient);
1330:    buf.putInt(length+4);
1331:    buf.putInt(length);
1332:    buf.putByte(type);
1333:  }
1334:	    private Vector glob_remote(String _path) throws Exception{
1335://System.out.println("glob_remote: "+_path);
1336:    Vector v=new Vector();
1337:    byte[] path=_path.getBytes();
1338:    int i=path.length-1;
1339:    while(i>=0){if(path[i]=='*' || path[i]=='?')break;i--;}
1340:    if(i<0){ v.addElement(_path); return v;}
1341:    while(i>=0){if(path[i]=='/')break;i--;}
1342:    if(i<0){ v.addElement(_path); return v;}
1343:    byte[] dir;
1344:    if(i==0){dir=new byte[]{(byte)'/'};}
1345:	      else{ 
1346:      dir=new byte[i];
1347:      System.arraycopy(path, 0, dir, 0, i);
1348:    }
1349://System.out.println("dir: "+new String(dir));
1350:    byte[] pattern=new byte[path.length-i-1];
1351:    System.arraycopy(path, i+1, pattern, 0, pattern.length);
1352://System.out.println("file: "+new String(pattern));
1353:
1354:    sendOPENDIR(dir);
1355:
1356:    buf.rewind();
1357:    i=io.in.read(buf.buffer, 0, buf.buffer.length);
1358:    int length=buf.getInt();
1359:    int type=buf.getByte();
1360:	      if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
1361:      throw new SftpException(SSH_FX_FAILURE, "");
1362:    }
1363:	      if(type==SSH_FXP_STATUS){
1364:      buf.getInt();
1365:      i=buf.getInt();
1366:      throwStatusError(buf, i);
1367:    }
1368:    buf.getInt();
1369:    byte[] handle=buf.getString();         // filename
1370:
1371:	      while(true){
1372:      sendREADDIR(handle);
1373:      buf.rewind();
1374:      i=io.in.read(buf.buffer, 0, buf.buffer.length);
1375:      buf.index=i;
1376:      length=buf.getInt();
1377:      length=length-(i-4);
1378:      type=buf.getByte();
1379:
1380:	        if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
1381:    throw new SftpException(SSH_FX_FAILURE, "");
1382:      }
1383:	        if(type==SSH_FXP_STATUS){ 
1384:    break;
1385:      }
1386:
1387:      buf.getInt();
1388:      int count=buf.getInt();
1389:
1390:      byte[] str;
1391:      int flags;
1392:
1393:	        while(count>0){
1394:	      if(length>0){
1395:      buf.shift();
1396:      i=io.in.read(buf.buffer, buf.index, buf.buffer.length-buf.index);
1397:      if(i<=0)break;
1398:      buf.index+=i;
1399:      length-=i;
1400:    }
1401:
1402:    byte[] filename=buf.getString();
1403:    //System.out.println("filename: "+new String(filename));
1404:    str=buf.getString();
1405:    SftpATTRS attrs=SftpATTRS.getATTR(buf);
1406:
1407:	      if(Util.glob(pattern, filename)){
1408:      v.addElement(new String(dir)+"/"+new String(filename));
1409:    }
1410:
1411:    count--; 
1412:      }
1413:    }
1414:
1415:    sendCLOSE(handle);
1416:    buf.rewind();
1417:    i=io.in.read(buf.buffer, 0, buf.buffer.length);
1418:    length=buf.getInt();
1419:    type=buf.getByte();
1420:	      if(type!=SSH_FXP_STATUS){
1421:      throw new SftpException(SSH_FX_FAILURE, "");
1422:    }
1423:    buf.getInt();
1424:    i=buf.getInt();
1425:    if(i==SSH_FX_OK) return v;
1426:
1427:    return null;
1428:  }
1429:
1430:	    private Vector glob_local(String _path) throws Exception{
1431://System.out.println("glob_local: "+_path);
1432:    Vector v=new Vector();
1433:    byte[] path=_path.getBytes();
1434:    int i=path.length-1;
1435:    while(i>=0){if(path[i]=='*' || path[i]=='?')break;i--;}
1436:    if(i<0){ v.addElement(_path); return v;}
1437:    while(i>=0){if(path[i]==file_separatorc)break;i--;}
1438:    if(i<0){ v.addElement(_path); return v;}
1439:    byte[] dir;
1440:    if(i==0){dir=new byte[]{(byte)file_separatorc};}
1441:	      else{ 
1442:      dir=new byte[i];
1443:      System.arraycopy(path, 0, dir, 0, i);
1444:    }
1445:    byte[] pattern=new byte[path.length-i-1];
1446:    System.arraycopy(path, i+1, pattern, 0, pattern.length);
1447://System.out.println("dir: "+dir+" pattern: "+pattern);
1448:	      try{
1449:      String[] children=(new File(new String(dir))).list();
1450:	        for(int j=0; j<children.length; j++){
1451://System.out.println("children: "+children[j]);
1452:	      if(Util.glob(pattern, children[j].getBytes())){
1453:      v.addElement(new String(dir)+file_separator+children[j]);
1454:    }
1455:      }
1456:    }
1457:	      catch(Exception e){
1458:    }
1459:    return v;
1460:  }
1461:
1462:	    private void throwStatusError(Buffer buf, int i) throws SftpException{
1463:	      if(server_version>=3){
1464:      byte[] str=buf.getString();
1465:      //byte[] tag=buf.getString();
1466:      throw new SftpException(i, new String(str));
1467:    }
1468:	      else{
1469:      throw new SftpException(i, "Failure");
1470:    }
1471:  }
1472:
1473:	    private static boolean isLocalAbsolutePath(String path){
1474:    return (new File(path)).isAbsolute();
1475:  }
1476:
1477:  /*
1478:   * Class: Ssh_exp_name
1479:   *
1480:   * Represents the result of a query about filenames (e.g. FXP_OPENDIR+ FXP_READDIR )
1481:   */
1482:	    public static class Ssh_exp_name {
1483:    private  String filename;
1484:    private  String longname;
1485:    private  SftpATTRS attrs;
1486:    Ssh_exp_name(String filename,
1487:         String longname,
1488:	           SftpATTRS attrs){
1489:      setFilename(filename);
1490:      setLongname(longname);
1491:      setAttrs(attrs);
1492:    }
1493:    public String getFilename(){return filename;};
1494:    public void setFilename(String filename){this.filename = filename;};
1495:    public String getLongname(){return longname;};
1496:    public void setLongname(String longname){this.longname = longname;};
1497:    public SftpATTRS getAttrs(){return attrs;};
1498:    public void setAttrs(SftpATTRS attrs) {this.attrs = attrs;};
1499:	      public String toString(){
1500:      return (attrs.toString()+" "+filename);
1501:    }
1502:  }
1503:}