ChannelSftp.java

Go to the documentation of this file.
00001 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
00002 /*
00003 Copyright (c) 2002-2011 ymnk, JCraft,Inc. All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007 
00008   1. Redistributions of source code must retain the above copyright notice,
00009      this list of conditions and the following disclaimer.
00010 
00011   2. Redistributions in binary form must reproduce the above copyright 
00012      notice, this list of conditions and the following disclaimer in 
00013      the documentation and/or other materials provided with the distribution.
00014 
00015   3. The names of the authors may not be used to endorse or promote products
00016      derived from this software without specific prior written permission.
00017 
00018 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
00019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
00020 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
00021 INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
00022 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00023 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00024 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00025 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00026 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00027 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028 */
00029 
00030 package com.jcraft.jsch;
00031 
00032 import java.io.*;
00033 
00034 import java.util.Vector;
00035 
00067 public class ChannelSftp extends ChannelSession{
00068 
00069   static private final int LOCAL_MAXIMUM_PACKET_SIZE=32*1024;
00070   static private final int LOCAL_WINDOW_SIZE_MAX=(64*LOCAL_MAXIMUM_PACKET_SIZE);
00071 
00072   private static final byte SSH_FXP_INIT=               1;
00073   private static final byte SSH_FXP_VERSION=            2;
00074   private static final byte SSH_FXP_OPEN=               3;
00075   private static final byte SSH_FXP_CLOSE=              4;
00076   private static final byte SSH_FXP_READ=               5;
00077   private static final byte SSH_FXP_WRITE=              6;
00078   private static final byte SSH_FXP_LSTAT=              7;
00079   private static final byte SSH_FXP_FSTAT=              8;
00080   private static final byte SSH_FXP_SETSTAT=            9;
00081   private static final byte SSH_FXP_FSETSTAT=          10;
00082   private static final byte SSH_FXP_OPENDIR=           11;
00083   private static final byte SSH_FXP_READDIR=           12;
00084   private static final byte SSH_FXP_REMOVE=            13;
00085   private static final byte SSH_FXP_MKDIR=             14;
00086   private static final byte SSH_FXP_RMDIR=             15;
00087   private static final byte SSH_FXP_REALPATH=          16;
00088   private static final byte SSH_FXP_STAT=              17;
00089   private static final byte SSH_FXP_RENAME=            18;
00090   private static final byte SSH_FXP_READLINK=          19;
00091   private static final byte SSH_FXP_SYMLINK=           20;
00092   private static final byte SSH_FXP_STATUS=           101;
00093   private static final byte SSH_FXP_HANDLE=           102;
00094   private static final byte SSH_FXP_DATA=             103;
00095   private static final byte SSH_FXP_NAME=             104;
00096   private static final byte SSH_FXP_ATTRS=            105;
00097   private static final byte SSH_FXP_EXTENDED=         (byte)200;
00098   private static final byte SSH_FXP_EXTENDED_REPLY=   (byte)201;
00099 
00100   // pflags
00101   private static final int SSH_FXF_READ=           0x00000001;
00102   private static final int SSH_FXF_WRITE=          0x00000002;
00103   private static final int SSH_FXF_APPEND=         0x00000004;
00104   private static final int SSH_FXF_CREAT=          0x00000008;
00105   private static final int SSH_FXF_TRUNC=          0x00000010;
00106   private static final int SSH_FXF_EXCL=           0x00000020;
00107 
00108   private static final int SSH_FILEXFER_ATTR_SIZE=         0x00000001;
00109   private static final int SSH_FILEXFER_ATTR_UIDGID=       0x00000002;
00110   private static final int SSH_FILEXFER_ATTR_PERMISSIONS=  0x00000004;
00111   private static final int SSH_FILEXFER_ATTR_ACMODTIME=    0x00000008;
00112   private static final int SSH_FILEXFER_ATTR_EXTENDED=     0x80000000;
00113 
00114   public static final int SSH_FX_OK=                            0;
00115   public static final int SSH_FX_EOF=                           1;
00116   public static final int SSH_FX_NO_SUCH_FILE=                  2;
00117   public static final int SSH_FX_PERMISSION_DENIED=             3;
00118   public static final int SSH_FX_FAILURE=                       4;
00119   public static final int SSH_FX_BAD_MESSAGE=                   5;
00120   public static final int SSH_FX_NO_CONNECTION=                 6;
00121   public static final int SSH_FX_CONNECTION_LOST=               7;
00122   public static final int SSH_FX_OP_UNSUPPORTED=                8;
00123 /*
00124    SSH_FX_OK
00125       Indicates successful completion of the operation.
00126    SSH_FX_EOF
00127      indicates end-of-file condition; for SSH_FX_READ it means that no
00128        more data is available in the file, and for SSH_FX_READDIR it
00129       indicates that no more files are contained in the directory.
00130    SSH_FX_NO_SUCH_FILE
00131       is returned when a reference is made to a file which should exist
00132       but doesn't.
00133    SSH_FX_PERMISSION_DENIED
00134       is returned when the authenticated user does not have sufficient
00135       permissions to perform the operation.
00136    SSH_FX_FAILURE
00137       is a generic catch-all error message; it should be returned if an
00138       error occurs for which there is no more specific error code
00139       defined.
00140    SSH_FX_BAD_MESSAGE
00141       may be returned if a badly formatted packet or protocol
00142       incompatibility is detected.
00143    SSH_FX_NO_CONNECTION
00144       is a pseudo-error which indicates that the client has no
00145       connection to the server (it can only be generated locally by the
00146       client, and MUST NOT be returned by servers).
00147    SSH_FX_CONNECTION_LOST
00148       is a pseudo-error which indicates that the connection to the
00149       server has been lost (it can only be generated locally by the
00150       client, and MUST NOT be returned by servers).
00151    SSH_FX_OP_UNSUPPORTED
00152       indicates that an attempt was made to perform an operation which
00153       is not supported for the server (it may be generated locally by
00154       the client if e.g.  the version number exchange indicates that a
00155       required feature is not supported by the server, or it may be
00156       returned by the server if the server does not implement an
00157       operation).
00158 */
00159   private static final int MAX_MSG_LENGTH = 256* 1024;
00160 
00164   public static final int OVERWRITE=0;
00170   public static final int RESUME=1;
00174   public static final int APPEND=2;
00175 
00176   private boolean interactive=false;
00177   private int seq=1;
00178   private int[] ackid=new int[1];
00179 
00180   private Buffer buf;
00181   private Packet packet;
00182 
00183   // The followings will be used in file uploading.
00184   private Buffer obuf;
00185   private Packet opacket;
00186 
00187   private int client_version=3;
00188   private int server_version=3;
00189   private String version=String.valueOf(client_version);
00190 
00191   private java.util.Hashtable extensions=null;
00192   private InputStream io_in=null;
00193 
00194 /*
00195 10. Changes from previous protocol versions
00196   The SSH File Transfer Protocol has changed over time, before it's
00197    standardization.  The following is a description of the incompatible
00198    changes between different versions.
00199 10.1 Changes between versions 3 and 2
00200    o  The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added.
00201    o  The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were added.
00202    o  The SSH_FXP_STATUS message was changed to include fields `error
00203       message' and `language tag'.
00204 10.2 Changes between versions 2 and 1
00205    o  The SSH_FXP_RENAME message was added.
00206 10.3 Changes between versions 1 and 0
00207    o  Implementation changes, no actual protocol changes.
00208 */
00209 
00210   private static final String file_separator=java.io.File.separator;
00211   private static final char file_separatorc=java.io.File.separatorChar;
00212   private static boolean fs_is_bs=(byte)java.io.File.separatorChar == '\\';
00213 
00214   private String cwd;
00215   private String home;
00216   private String lcwd;
00217 
00218   private static final String UTF8="UTF-8";
00219   private String fEncoding=UTF8;
00220   private boolean fEncoding_is_utf8=true;
00221 
00222   private RequestQueue rq = new RequestQueue(10);
00223   public void setBulkRequests(int bulk_requests) throws JSchException {
00224     if(bulk_requests>0) 
00225       rq = new RequestQueue(bulk_requests);
00226     else 
00227       throw new JSchException("setBulkRequests: "+ 
00228                               bulk_requests+" must be greater than 0.");
00229   }
00230   public int getBulkRequests(){
00231     return rq.size();
00232   }
00233 
00234   ChannelSftp(){
00235     super();
00236     setLocalWindowSizeMax(LOCAL_WINDOW_SIZE_MAX);
00237     setLocalWindowSize(LOCAL_WINDOW_SIZE_MAX);
00238     setLocalPacketSize(LOCAL_MAXIMUM_PACKET_SIZE);
00239   }
00240 
00241   void init(){
00242   }
00243 
00244   // javadoc copied from superclass -- P.E.
00245   public void start() throws JSchException{
00246     try{
00247 
00248       PipedOutputStream pos=new PipedOutputStream();
00249       io.setOutputStream(pos);
00250       PipedInputStream pis=new MyPipedInputStream(pos, rmpsize);
00251       io.setInputStream(pis);
00252 
00253       io_in=io.in;
00254 
00255       if(io_in==null){
00256         throw new JSchException("channel is down");
00257       }
00258 
00259       Request request=new RequestSftp();
00260       request.request(getSession(), this);
00261 
00262       /*
00263       System.err.println("lmpsize: "+lmpsize);
00264       System.err.println("lwsize: "+lwsize);
00265       System.err.println("rmpsize: "+rmpsize);
00266       System.err.println("rwsize: "+rwsize);
00267       */
00268 
00269       buf=new Buffer(lmpsize);
00270       packet=new Packet(buf);
00271 
00272       obuf=new Buffer(rmpsize);
00273       opacket=new Packet(obuf);
00274 
00275       int i=0;
00276       int length;
00277       int type;
00278       byte[] str;
00279 
00280       // send SSH_FXP_INIT
00281       sendINIT();
00282 
00283       // receive SSH_FXP_VERSION
00284       Header header=new Header();
00285       header=header(buf, header);
00286       length=header.length;
00287       if(length > MAX_MSG_LENGTH){
00288         throw new SftpException(SSH_FX_FAILURE, 
00289                                 "Received message is too long: " + length);
00290       }
00291       type=header.type;             // 2 -> SSH_FXP_VERSION
00292       server_version=header.rid;
00293       //System.err.println("SFTP protocol server-version="+server_version);
00294       if(length>0){
00295         extensions=new java.util.Hashtable();
00296         // extension data
00297         fill(buf, length);
00298         byte[] extension_name=null;
00299         byte[] extension_data=null;
00300         while(length>0){
00301           extension_name=buf.getString();
00302           length-=(4+extension_name.length);
00303           extension_data=buf.getString();
00304           length-=(4+extension_data.length);
00305           extensions.put(Util.byte2str(extension_name),
00306                          Util.byte2str(extension_data));
00307         }
00308       }
00309 
00310       lcwd=new File(".").getCanonicalPath();
00311     }
00312     catch(Exception e){
00313       //System.err.println(e);
00314       if(e instanceof JSchException) throw (JSchException)e;
00315       if(e instanceof Throwable)
00316         throw new JSchException(e.toString(), (Throwable)e);
00317       throw new JSchException(e.toString());
00318     }
00319   }
00320 
00324   public void quit(){ disconnect();}
00325 
00329   public void exit(){ disconnect();}
00330 
00338   public void lcd(String path) throws SftpException{
00339     path=localAbsolutePath(path);
00340     if((new File(path)).isDirectory()){
00341       try{
00342     path=(new File(path)).getCanonicalPath();
00343       }
00344       catch(Exception e){}
00345       lcwd=path;
00346       return;
00347     }
00348     throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such directory");
00349   }
00350 
00362   public void cd(String path) throws SftpException{
00363     try{
00364       ((MyPipedInputStream)io_in).updateReadSide();
00365 
00366       path=remoteAbsolutePath(path);
00367       path=isUnique(path);
00368 
00369       byte[] str=_realpath(path);
00370       SftpATTRS attr=_stat(str);
00371 
00372       if((attr.getFlags()&SftpATTRS.SSH_FILEXFER_ATTR_PERMISSIONS)==0){
00373         throw new SftpException(SSH_FX_FAILURE, 
00374                                 "Can't change directory: "+path);
00375       }
00376       if(!attr.isDir()){
00377         throw new SftpException(SSH_FX_FAILURE, 
00378                                 "Can't change directory: "+path);
00379       }
00380 
00381       setCwd(Util.byte2str(str, fEncoding));
00382     }
00383     catch(Exception e){
00384       if(e instanceof SftpException) throw (SftpException)e;
00385       if(e instanceof Throwable)
00386         // shouldn't every exception be a Throwable? -- P.E.
00387         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
00388       throw new SftpException(SSH_FX_FAILURE, "");
00389     }
00390   }
00391 
00392   // ------------ upload ----------------------------
00393 
00394 
00404   public void put(String src, String dst) throws SftpException{
00405     put(src, dst, null, OVERWRITE);
00406   }
00407 
00419   public void put(String src, String dst, int mode) throws SftpException{
00420     put(src, dst, null, mode);
00421   }
00422 
00435   public void put(String src, String dst, 
00436           SftpProgressMonitor monitor) throws SftpException{
00437     put(src, dst, monitor, OVERWRITE);
00438   }
00439 
00453   public void put(String src, String dst, 
00454           SftpProgressMonitor monitor, int mode) throws SftpException{
00455 
00456     try{
00457       ((MyPipedInputStream)io_in).updateReadSide();
00458 
00459       src=localAbsolutePath(src);
00460       dst=remoteAbsolutePath(dst);
00461 
00462       Vector v=glob_remote(dst);
00463       int vsize=v.size();
00464       if(vsize!=1){
00465         if(vsize==0){
00466           if(isPattern(dst))
00467             throw new SftpException(SSH_FX_FAILURE, dst);
00468           else
00469             dst=Util.unquote(dst);
00470         }
00471         throw new SftpException(SSH_FX_FAILURE, v.toString());
00472       }
00473       else{
00474         dst=(String)(v.elementAt(0));
00475       }
00476 
00477       boolean isRemoteDir=isRemoteDir(dst);
00478 
00479       v=glob_local(src);
00480       vsize=v.size();
00481 
00482       StringBuffer dstsb=null;
00483       if(isRemoteDir){
00484         if(!dst.endsWith("/")){
00485         dst+="/";
00486         }
00487         dstsb=new StringBuffer(dst);
00488       }
00489       else if(vsize>1){
00490         throw new SftpException(SSH_FX_FAILURE, 
00491                                 "Copying multiple files, but the destination is missing or a file.");
00492       }
00493 
00494       for(int j=0; j<vsize; j++){
00495     String _src=(String)(v.elementAt(j));
00496     String _dst=null;
00497     if(isRemoteDir){
00498       int i=_src.lastIndexOf(file_separatorc);
00499           if(fs_is_bs){
00500             int ii=_src.lastIndexOf('/');
00501             if(ii!=-1 && ii>i)
00502               i=ii; 
00503           }
00504       if(i==-1) dstsb.append(_src);
00505       else dstsb.append(_src.substring(i + 1));
00506           _dst=dstsb.toString();
00507           dstsb.delete(dst.length(), _dst.length());
00508     }
00509         else{
00510           _dst=dst;
00511         }
00512         //System.err.println("_dst "+_dst);
00513 
00514     long size_of_dst=0;
00515     if(mode==RESUME){
00516       try{
00517         SftpATTRS attr=_stat(_dst);
00518         size_of_dst=attr.getSize();
00519       }
00520       catch(Exception eee){
00521         //System.err.println(eee);
00522       }
00523       long size_of_src=new File(_src).length();
00524       if(size_of_src<size_of_dst){
00525         throw new SftpException(SSH_FX_FAILURE, 
00526                                     "failed to resume for "+_dst);
00527       }
00528       if(size_of_src==size_of_dst){
00529         return;
00530       }
00531     }
00532 
00533         if(monitor!=null){
00534       monitor.init(SftpProgressMonitor.PUT, _src, _dst,
00535                (new File(_src)).length());
00536       if(mode==RESUME){
00537         monitor.count(size_of_dst);
00538       }
00539         }
00540     FileInputStream fis=null;
00541     try{
00542       fis=new FileInputStream(_src);
00543       _put(fis, _dst, monitor, mode);
00544     }
00545     finally{
00546       if(fis!=null) {
00547         fis.close();
00548       }
00549     }
00550       }
00551     }
00552     catch(Exception e){
00553       if(e instanceof SftpException) throw (SftpException)e;
00554       if(e instanceof Throwable)
00555         throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e);
00556       throw new SftpException(SSH_FX_FAILURE, e.toString());
00557     }
00558   }
00559 
00569   public void put(InputStream src, String dst) throws SftpException{
00570     put(src, dst, null, OVERWRITE);
00571   }
00572 
00584   public void put(InputStream src, String dst, int mode) throws SftpException{
00585     put(src, dst, null, mode);
00586   }
00587 
00600   public void put(InputStream src, String dst, 
00601           SftpProgressMonitor monitor) throws SftpException{
00602     put(src, dst, monitor, OVERWRITE);
00603   }
00604 
00617   public void put(InputStream src, String dst, 
00618           SftpProgressMonitor monitor, int mode) throws SftpException{
00619     try{
00620       ((MyPipedInputStream)io_in).updateReadSide();
00621 
00622       dst=remoteAbsolutePath(dst);
00623 
00624       Vector v=glob_remote(dst);
00625       int vsize=v.size();
00626       if(vsize!=1){
00627         if(vsize==0){
00628           if(isPattern(dst))
00629             throw new SftpException(SSH_FX_FAILURE, dst);
00630           else
00631             dst=Util.unquote(dst);
00632         }
00633         throw new SftpException(SSH_FX_FAILURE, v.toString());
00634       }
00635       else{
00636         dst=(String)(v.elementAt(0));
00637       }
00638 
00639       if(isRemoteDir(dst)){
00640         throw new SftpException(SSH_FX_FAILURE, dst+" is a directory");
00641       }
00642 
00643       if(monitor!=null){
00644         monitor.init(SftpProgressMonitor.PUT, 
00645                      "-", dst,
00646                      SftpProgressMonitor.UNKNOWN_SIZE);
00647       }
00648 
00649       _put(src, dst, monitor, mode);
00650     }
00651     catch(Exception e){
00652       if(e instanceof SftpException) throw (SftpException)e;
00653       if(e instanceof Throwable)
00654         throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e);
00655       throw new SftpException(SSH_FX_FAILURE, e.toString());
00656     }
00657   }
00658 
00666   public void _put(InputStream src, String dst, 
00667                    SftpProgressMonitor monitor, int mode) throws SftpException{
00668     try{
00669       ((MyPipedInputStream)io_in).updateReadSide();
00670 
00671       byte[] dstb=Util.str2byte(dst, fEncoding);
00672       long skip=0;
00673       if(mode==RESUME || mode==APPEND){
00674     try{
00675       SftpATTRS attr=_stat(dstb);
00676       skip=attr.getSize();
00677     }
00678     catch(Exception eee){
00679       //System.err.println(eee);
00680     }
00681       }
00682       if(mode==RESUME && skip>0){
00683     long skipped=src.skip(skip);
00684     if(skipped<skip){
00685       throw new SftpException(SSH_FX_FAILURE, "failed to resume for "+dst);
00686     }
00687       }
00688 
00689       if(mode==OVERWRITE){ sendOPENW(dstb); }
00690       else{ sendOPENA(dstb); }
00691 
00692       Header header=new Header();
00693       header=header(buf, header);
00694       int length=header.length;
00695       int type=header.type;
00696 
00697       fill(buf, length);
00698 
00699       if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
00700     throw new SftpException(SSH_FX_FAILURE, "invalid type="+type);
00701       }
00702       if(type==SSH_FXP_STATUS){
00703         int i=buf.getInt();
00704         throwStatusError(buf, i);
00705       }
00706       byte[] handle=buf.getString();         // handle
00707       byte[] data=null;
00708 
00709       boolean dontcopy=true;
00710 
00711       if(!dontcopy){  // This case will not work anymore.
00712         data=new byte[obuf.buffer.length
00713                       -(5+13+21+handle.length+Session.buffer_margin
00714                         )
00715         ];
00716       }
00717 
00718       long offset=0;
00719       if(mode==RESUME || mode==APPEND){
00720     offset+=skip;
00721       }
00722 
00723       int startid=seq;
00724       int ackcount=0;
00725       int _s=0;
00726       int _datalen=0;
00727 
00728       if(!dontcopy){  // This case will not work anymore.
00729         _datalen=data.length;
00730       }
00731       else{
00732         data=obuf.buffer;
00733         _s=5+13+21+handle.length;
00734         _datalen=obuf.buffer.length-_s-Session.buffer_margin;
00735       }
00736 
00737       int bulk_requests = rq.size();
00738 
00739       while(true){
00740         int nread=0;
00741         int count=0;
00742         int s=_s;
00743         int datalen=_datalen;
00744 
00745         do{
00746           nread=src.read(data, s, datalen);
00747           if(nread>0){
00748             s+=nread;
00749             datalen-=nread;
00750             count+=nread;
00751           }
00752         }
00753         while(datalen>0 && nread>0); 
00754         if(count<=0)break;
00755 
00756         int foo=count;
00757         while(foo>0){
00758           if((seq-1)==startid ||
00759              ((seq-startid)-ackcount)>=bulk_requests){
00760             while(((seq-startid)-ackcount)>=bulk_requests){
00761               if(this.rwsize>=foo) break;
00762               if(checkStatus(ackid, header)){
00763                 int _ackid = ackid[0];
00764                 if(startid>_ackid || _ackid>seq-1){
00765                   if(_ackid==seq){
00766                     System.err.println("ack error: startid="+startid+" seq="+seq+" _ackid="+_ackid);
00767                   } 
00768                   else{
00769                     throw new SftpException(SSH_FX_FAILURE, "ack error: startid="+startid+" seq="+seq+" _ackid="+_ackid);
00770                   }
00771                 }
00772                 ackcount++;
00773               }
00774               else{
00775                 break;
00776               }
00777             }
00778           }
00779           foo-=sendWRITE(handle, offset, data, 0, foo);
00780         }
00781         offset+=count;
00782     if(monitor!=null && !monitor.count(count)){
00783           break;
00784     }
00785       }
00786       int _ackcount=seq-startid;
00787       while(_ackcount>ackcount){
00788         if(!checkStatus(null, header)){
00789           break;
00790         }
00791         ackcount++;
00792       }
00793       if(monitor!=null)monitor.end();
00794       _sendCLOSE(handle, header);
00795     }
00796     catch(Exception e){
00797       if(e instanceof SftpException) throw (SftpException)e;
00798       if(e instanceof Throwable)
00799         throw new SftpException(SSH_FX_FAILURE, e.toString(), (Throwable)e);
00800       throw new SftpException(SSH_FX_FAILURE, e.toString());
00801     }
00802   }
00803 
00815   public OutputStream put(String dst) throws SftpException{
00816     return put(dst, (SftpProgressMonitor)null, OVERWRITE);
00817   }
00818 
00831   public OutputStream put(String dst, final int mode) throws SftpException{
00832     return put(dst, (SftpProgressMonitor)null, mode);
00833   }
00834 
00850   public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode) throws SftpException{
00851     return put(dst, monitor, mode, 0);
00852   }
00853 
00878   public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode, long offset) throws SftpException{
00879     try{
00880       ((MyPipedInputStream)io_in).updateReadSide();
00881 
00882       dst=remoteAbsolutePath(dst);
00883       dst=isUnique(dst);
00884 
00885       if(isRemoteDir(dst)){
00886     throw new SftpException(SSH_FX_FAILURE, dst+" is a directory");
00887       }
00888 
00889       byte[] dstb=Util.str2byte(dst, fEncoding);
00890 
00891       long skip=0;
00892       if(mode==RESUME || mode==APPEND){
00893     try{
00894       SftpATTRS attr=_stat(dstb);
00895       skip=attr.getSize();
00896     }
00897     catch(Exception eee){
00898       //System.err.println(eee);
00899     }
00900       }
00901 
00902       if(mode==OVERWRITE){ sendOPENW(dstb); }
00903       else{ sendOPENA(dstb); }
00904 
00905       Header header=new Header();
00906       header=header(buf, header);
00907       int length=header.length;
00908       int type=header.type;
00909 
00910       fill(buf, length);
00911 
00912       if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
00913     throw new SftpException(SSH_FX_FAILURE, "");
00914       }
00915       if(type==SSH_FXP_STATUS){
00916         int i=buf.getInt();
00917         throwStatusError(buf, i);
00918       }
00919       final byte[] handle=buf.getString();         // handle
00920 
00921       if(mode==RESUME || mode==APPEND){
00922     offset+=skip;
00923       }
00924 
00925       final long[] _offset=new long[1];
00926       _offset[0]=offset;
00927       OutputStream out = new OutputStream(){
00928         private boolean init=true;
00929         private boolean isClosed=false;
00930         private int[] ackid=new int[1];
00931         private int startid=0;
00932         private int _ackid=0;
00933         private int ackcount=0;
00934         private int writecount=0;
00935         private Header header=new Header();          
00936 
00937         public void write(byte[] d) throws java.io.IOException{
00938           write(d, 0, d.length);
00939         }
00940 
00941         public void write(byte[] d, int s, int len) throws java.io.IOException{
00942           if(init){
00943             startid=seq;
00944             _ackid=seq;
00945             init=false;
00946           }
00947 
00948           if(isClosed){
00949             throw new IOException("stream already closed");
00950           }
00951 
00952           try{
00953             int _len=len;
00954             while(_len>0){
00955               int sent=sendWRITE(handle, _offset[0], d, s, _len);
00956               writecount++;
00957               _offset[0]+=sent;
00958               s+=sent;
00959               _len-=sent;
00960               if((seq-1)==startid ||
00961                  io_in.available()>=1024){
00962                 while(io_in.available()>0){
00963                   if(checkStatus(ackid, header)){
00964                     _ackid=ackid[0];
00965                     if(startid>_ackid || _ackid>seq-1){
00966                       throw new SftpException(SSH_FX_FAILURE, "");
00967                     }
00968                     ackcount++;
00969                   }
00970                   else{
00971                     break;
00972                   }
00973                 }
00974               }
00975             }
00976             if(monitor!=null && !monitor.count(len)){
00977               close();
00978               throw new IOException("canceled");
00979         }
00980           }
00981           catch(IOException e){ throw e; }
00982           catch(Exception e){ throw new IOException(e.toString());  }
00983         }
00984 
00985         byte[] _data=new byte[1];
00986         public void write(int foo) throws java.io.IOException{
00987           _data[0]=(byte)foo;
00988           write(_data, 0, 1);
00989         }
00990 
00991         public void flush() throws java.io.IOException{
00992 
00993           if(isClosed){
00994             throw new IOException("stream already closed");
00995           }
00996 
00997           if(!init){
00998             try{
00999               while(writecount>ackcount){
01000                 if(!checkStatus(null, header)){
01001                   break;
01002                 }
01003                 ackcount++;
01004               }
01005             }
01006             catch(SftpException e){
01007               throw new IOException(e.toString());
01008             }
01009           }
01010         }
01011 
01012         public void close() throws java.io.IOException{
01013           if(isClosed){
01014             return;
01015           }
01016           flush();
01017           if(monitor!=null)monitor.end();
01018           try{ _sendCLOSE(handle, header); }
01019           catch(IOException e){ throw e; }
01020           catch(Exception e){
01021             throw new IOException(e.toString());
01022           }
01023           isClosed=true;
01024         }
01025       };
01026       return out;
01027     }
01028     catch(Exception e){
01029       if(e instanceof SftpException) throw (SftpException)e;
01030       if(e instanceof Throwable)
01031         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
01032       throw new SftpException(SSH_FX_FAILURE, "");
01033     }
01034   }
01035 
01036   // ------------ download ----------------------------
01037 
01038 
01044   public void get(String src, String dst) throws SftpException{
01045     get(src, dst, null, OVERWRITE);
01046   }
01047 
01053   public void get(String src, String dst,
01054           SftpProgressMonitor monitor) throws SftpException{
01055     get(src, dst, monitor, OVERWRITE);
01056   }
01057 
01071   public void get(String src, String dst,
01072           SftpProgressMonitor monitor, int mode) throws SftpException{
01073     // System.out.println("get: "+src+" "+dst);
01074 
01075     boolean _dstExist = false;
01076     String _dst=null;
01077     try{
01078       ((MyPipedInputStream)io_in).updateReadSide();
01079 
01080       src=remoteAbsolutePath(src);
01081       dst=localAbsolutePath(dst);
01082 
01083       Vector v=glob_remote(src);
01084       int vsize=v.size();
01085       if(vsize==0){
01086         throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such file");
01087       }
01088 
01089       File dstFile=new File(dst);
01090       boolean isDstDir=dstFile.isDirectory();
01091       StringBuffer dstsb=null;
01092       if(isDstDir){
01093         if(!dst.endsWith(file_separator)){
01094           dst+=file_separator;
01095         }
01096         dstsb=new StringBuffer(dst);
01097       }
01098       else if(vsize>1){
01099         throw new SftpException(SSH_FX_FAILURE, 
01100                                 "Copying multiple files, but destination is missing or a file.");
01101       }
01102 
01103       for(int j=0; j<vsize; j++){
01104     String _src=(String)(v.elementAt(j));
01105     SftpATTRS attr=_stat(_src);
01106         if(attr.isDir()){
01107           throw new SftpException(SSH_FX_FAILURE, 
01108                                   "not supported to get directory "+_src);
01109         } 
01110 
01111     _dst=null;
01112     if(isDstDir){
01113       int i=_src.lastIndexOf('/');
01114       if(i==-1) dstsb.append(_src);
01115       else dstsb.append(_src.substring(i + 1));
01116           _dst=dstsb.toString();
01117           dstsb.delete(dst.length(), _dst.length());
01118     }
01119         else{
01120           _dst=dst;
01121         }
01122 
01123         File _dstFile=new File(_dst);
01124     if(mode==RESUME){
01125       long size_of_src=attr.getSize();
01126       long size_of_dst=_dstFile.length();
01127       if(size_of_dst>size_of_src){
01128         throw new SftpException(SSH_FX_FAILURE, 
01129                                     "failed to resume for "+_dst);
01130       }
01131       if(size_of_dst==size_of_src){
01132         return;
01133       }
01134     }
01135 
01136     if(monitor!=null){
01137       monitor.init(SftpProgressMonitor.GET, _src, _dst, attr.getSize());
01138       if(mode==RESUME){
01139         monitor.count(_dstFile.length());
01140       }
01141     }
01142 
01143         FileOutputStream fos=null;
01144         _dstExist = _dstFile.exists();
01145         try{
01146           if(mode==OVERWRITE){
01147             fos=new FileOutputStream(_dst);
01148           }
01149           else{
01150             fos=new FileOutputStream(_dst, true); // append
01151           }
01152           // System.err.println("_get: "+_src+", "+_dst);
01153           _get(_src, fos, monitor, mode, new File(_dst).length());
01154         }
01155         finally{
01156           if(fos!=null){
01157             fos.close();
01158           }
01159         }
01160       }
01161     }
01162     catch(Exception e){
01163       if(!_dstExist && _dst!=null){
01164         File _dstFile = new File(_dst);
01165         if(_dstFile.exists() && _dstFile.length()==0){
01166           _dstFile.delete();
01167         }
01168       }
01169       if(e instanceof SftpException) throw (SftpException)e;
01170       if(e instanceof Throwable)
01171         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
01172       throw new SftpException(SSH_FX_FAILURE, "");
01173     }
01174   }
01175 
01181   public void get(String src, OutputStream dst) throws SftpException{
01182     get(src, dst, null, OVERWRITE, 0);
01183   }
01184 
01190   public void get(String src, OutputStream dst,
01191           SftpProgressMonitor monitor) throws SftpException{
01192     get(src, dst, monitor, OVERWRITE, 0);
01193   }
01194 
01211   public void get(String src, OutputStream dst,
01212            SftpProgressMonitor monitor, int mode, long skip) throws SftpException{
01213 //System.err.println("get: "+src+", "+dst);
01214     try{
01215       ((MyPipedInputStream)io_in).updateReadSide();
01216 
01217       src=remoteAbsolutePath(src);
01218       src=isUnique(src);
01219 
01220       if(monitor!=null){
01221     SftpATTRS attr=_stat(src);
01222         monitor.init(SftpProgressMonitor.GET, src, "??", attr.getSize());
01223         if(mode==RESUME){
01224           monitor.count(skip);
01225         }
01226       }
01227       _get(src, dst, monitor, mode, skip);
01228     }
01229     catch(Exception e){
01230       if(e instanceof SftpException) throw (SftpException)e;
01231       if(e instanceof Throwable)
01232         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
01233       throw new SftpException(SSH_FX_FAILURE, "");
01234     }
01235   }
01236 
01240   private void _get(String src, OutputStream dst,
01241                     SftpProgressMonitor monitor, int mode, long skip) throws SftpException{
01242     //System.err.println("_get: "+src+", "+dst);
01243 
01244     byte[] srcb=Util.str2byte(src, fEncoding);
01245     try{
01246       sendOPENR(srcb);
01247 
01248       Header header=new Header();
01249       header=header(buf, header);
01250       int length=header.length;
01251       int type=header.type;
01252 
01253       fill(buf, length);
01254 
01255       if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
01256     throw new SftpException(SSH_FX_FAILURE, "");
01257       }
01258 
01259       if(type==SSH_FXP_STATUS){
01260         int i=buf.getInt();
01261         throwStatusError(buf, i);
01262       }
01263 
01264       byte[] handle=buf.getString();         // filename
01265 
01266       long offset=0;
01267       if(mode==RESUME){
01268     offset+=skip;
01269       }
01270 
01271       int request_max=1;
01272       rq.init();
01273       long request_offset=offset;
01274 
01275       int request_len = buf.buffer.length-13;
01276       if(server_version==0){ request_len=1024; }
01277 
01278       loop:
01279       while(true){
01280 
01281         while(rq.count() < request_max){
01282           sendREAD(handle, request_offset, request_len, rq);
01283           request_offset += request_len;
01284         }
01285 
01286         header=header(buf, header);
01287         length=header.length;
01288         type=header.type;
01289 
01290         RequestQueue.Request rr = rq.get(header.rid);
01291 
01292         if(type==SSH_FXP_STATUS){
01293           fill(buf, length);
01294           int i=buf.getInt();    
01295           if(i==SSH_FX_EOF){
01296             break loop;
01297           }
01298           throwStatusError(buf, i);
01299         }
01300 
01301         if(type!=SSH_FXP_DATA){ 
01302       break loop;
01303         }
01304 
01305         buf.rewind();
01306         fill(buf.buffer, 0, 4); length-=4;
01307         int length_of_data = buf.getInt();   // length of data 
01308 
01319         int optional_data = length - length_of_data;
01320 
01321         int foo = length_of_data;
01322         while(foo>0){
01323           int bar=foo;
01324           if(bar>buf.buffer.length){
01325             bar=buf.buffer.length;
01326           }
01327           int data_len = io_in.read(buf.buffer, 0, bar);
01328           if(data_len<0){
01329             break loop;
01330       }
01331           
01332           dst.write(buf.buffer, 0, data_len);
01333 
01334           offset+=data_len;
01335           foo-=data_len;
01336 
01337           if(monitor!=null){
01338             if(!monitor.count(data_len)){
01339               skip(foo); 
01340               if(optional_data>0){
01341                 skip(optional_data);
01342               }
01343               break loop;
01344             }
01345           }
01346 
01347         }
01348     //System.err.println("length: "+length);  // length should be 0
01349 
01350         if(optional_data>0){
01351           skip(optional_data);
01352         }
01353 
01354         if(length_of_data<rr.length){  //
01355           rq.cancel(header, buf);
01356           sendREAD(handle, rr.offset+length_of_data, (int)(rr.length-length_of_data), rq);
01357           request_offset=rr.offset+rr.length;
01358         }
01359 
01360         if(request_max < rq.size()){
01361           request_max++;
01362         }
01363       }
01364       dst.flush();
01365 
01366       if(monitor!=null)monitor.end();
01367 
01368       rq.cancel(header, buf);
01369 
01370       _sendCLOSE(handle, header);
01371     }
01372     catch(Exception e){
01373       if(e instanceof SftpException) throw (SftpException)e;
01374       if(e instanceof Throwable)
01375         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
01376       throw new SftpException(SSH_FX_FAILURE, "");
01377     }
01378   }
01379 
01380 
01381   private class RequestQueue {
01382     class Request {
01383       int id;
01384       long offset;
01385       long length;
01386     }
01387 
01388     Request[] rrq=null;
01389     int head, count;
01390     RequestQueue(int size){
01391       rrq = new Request[size];
01392       for(int i=0; i<rrq.length; i++){
01393         rrq[i]=new Request();
01394       }
01395       init();
01396     }
01397 
01398     void init(){
01399       head=count=0;
01400     }
01401 
01402     void add(int id, long offset, int length){
01403       if(count == 0) head = 0;
01404       int tail = head + count;
01405       if(tail>=rrq.length) tail -= rrq.length;
01406       rrq[tail].id=id;
01407       rrq[tail].offset=offset;
01408       rrq[tail].length=length;
01409       count++;
01410     }
01411 
01412     Request get(int id){
01413       count -= 1;
01414       int i=head;
01415       head++; 
01416       if(head==rrq.length) head=0;
01417       if(rrq[i].id!=id){
01418         System.err.println("The request is not in order.");
01419       }
01420       rrq[i].id=0;
01421       return rrq[i];
01422     }
01423 
01424     int count() {
01425       return count;
01426     }
01427 
01428     int size() {
01429       return rrq.length;
01430     } 
01431 
01432     void cancel(Header header, Buffer buf) throws IOException {
01433       int _count = count;
01434       for(int i=0; i<_count; i++){
01435         header=header(buf, header);
01436         int length=header.length;
01437         get(header.rid);
01438         skip(length); 
01439       }
01440     }
01441   }
01442 
01448   public InputStream get(String src) throws SftpException{
01449     return get(src, null, 0L);
01450   }
01456   public InputStream get(String src, SftpProgressMonitor monitor) throws SftpException{
01457     return get(src, monitor, 0L);
01458   }
01459 
01467   public InputStream get(String src, int mode) throws SftpException{
01468     return get(src, null, 0L);
01469   }
01477   public InputStream get(String src, final SftpProgressMonitor monitor, final int mode) throws SftpException{
01478     return get(src, monitor, 0L);
01479   }
01480 
01494   public InputStream get(String src, final SftpProgressMonitor monitor, final long skip) throws SftpException{
01495 
01496     try{
01497       ((MyPipedInputStream)io_in).updateReadSide();
01498 
01499       src=remoteAbsolutePath(src);
01500       src=isUnique(src);
01501 
01502       byte[] srcb=Util.str2byte(src, fEncoding);
01503 
01504       SftpATTRS attr=_stat(srcb);
01505       if(monitor!=null){
01506         monitor.init(SftpProgressMonitor.GET, src, "??", attr.getSize());
01507       }
01508 
01509       sendOPENR(srcb);
01510 
01511       Header header=new Header();
01512       header=header(buf, header);
01513       int length=header.length;
01514       int type=header.type;
01515 
01516       fill(buf, length);
01517 
01518       if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
01519     throw new SftpException(SSH_FX_FAILURE, "");
01520       }
01521       if(type==SSH_FXP_STATUS){
01522         int i=buf.getInt();
01523         throwStatusError(buf, i);
01524       }
01525 
01526       final byte[] handle=buf.getString();         // handle
01527 
01528       java.io.InputStream in=new java.io.InputStream(){
01529            long offset=skip;
01530            boolean closed=false;
01531            int rest_length=0;
01532            byte[] _data=new byte[1];
01533            byte[] rest_byte=new byte[1024];
01534            Header header=new Header();
01535 
01536            public int read() throws java.io.IOException{
01537              if(closed)return -1;
01538              int i=read(_data, 0, 1);
01539              if (i==-1) { return -1; }
01540              else {
01541                return _data[0]&0xff;
01542              }
01543            }
01544            public int read(byte[] d) throws java.io.IOException{
01545              if(closed)return -1;
01546              return read(d, 0, d.length);
01547            }
01548            public int read(byte[] d, int s, int len) throws java.io.IOException{
01549              if(closed)return -1;
01550              if(d==null){throw new NullPointerException();}
01551              if(s<0 || len <0 || s+len>d.length){
01552                throw new IndexOutOfBoundsException();
01553              } 
01554              if(len==0){ return 0; }
01555 
01556              if(rest_length>0){
01557                int foo=rest_length;
01558                if(foo>len) foo=len;
01559                System.arraycopy(rest_byte, 0, d, s, foo);
01560                if(foo!=rest_length){
01561                  System.arraycopy(rest_byte, foo, 
01562                                   rest_byte, 0, rest_length-foo);
01563                }
01564 
01565                if(monitor!=null){
01566                  if(!monitor.count(foo)){
01567                    close();
01568                    return -1;
01569                  }
01570                }
01571 
01572                rest_length-=foo;
01573                return foo;
01574              }
01575 
01576              if(buf.buffer.length-13<len){
01577                len=buf.buffer.length-13;
01578              }
01579              if(server_version==0 && len>1024){
01580                len=1024; 
01581              }
01582 
01583              try{sendREAD(handle, offset, len);}
01584              catch(Exception e){ throw new IOException("error"); }
01585 
01586              header=header(buf, header);
01587              rest_length=header.length;
01588              int type=header.type;
01589              int id=header.rid;
01590 
01591              if(type!=SSH_FXP_STATUS && type!=SSH_FXP_DATA){ 
01592                throw new IOException("error");
01593              }
01594              if(type==SSH_FXP_STATUS){
01595                fill(buf, rest_length);
01596                int i=buf.getInt();    
01597                rest_length=0;
01598                if(i==SSH_FX_EOF){
01599                  close();
01600                  return -1;
01601                }
01602                //throwStatusError(buf, i);
01603                throw new IOException("error");
01604              }
01605              buf.rewind();
01606              fill(buf.buffer, 0, 4);
01607              int length_of_data = buf.getInt(); rest_length-=4;
01608 
01619              int optional_data = rest_length - length_of_data;
01620 
01621              offset += length_of_data;
01622              int foo = length_of_data;
01623              if(foo>0){
01624                int bar=foo;
01625                if(bar>len){
01626                  bar=len;
01627                }
01628                int i=io_in.read(d, s, bar);
01629                if(i<0){
01630                  return -1;
01631                }
01632                foo-=i;
01633                rest_length=foo;
01634 
01635                if(foo>0){
01636                  if(rest_byte.length<foo){
01637                    rest_byte=new byte[foo];
01638                  }
01639                  int _s=0;
01640                  int _len=foo;
01641                  int j;
01642                  while(_len>0){
01643                    j=io_in.read(rest_byte, _s, _len);
01644                    if(j<=0)break;
01645                    _s+=j;
01646                    _len-=j;
01647                  }
01648                }
01649 
01650                if(optional_data>0){
01651                  io_in.skip(optional_data);
01652                }
01653 
01654                if(monitor!=null){
01655                  if(!monitor.count(i)){
01656                    close();
01657                    return -1;
01658                  }
01659                }
01660 
01661                return i;
01662              }
01663              return 0; // ??
01664            }
01665            public void close() throws IOException{
01666              if(closed)return;
01667              closed=true;
01668              if(monitor!=null)monitor.end();
01669              try{_sendCLOSE(handle, header);}
01670              catch(Exception e){throw new IOException("error");}
01671            }
01672          };
01673        return in;
01674      }
01675      catch(Exception e){
01676        if(e instanceof SftpException) throw (SftpException)e;
01677        if(e instanceof Throwable)
01678          throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
01679        throw new SftpException(SSH_FX_FAILURE, "");
01680      }
01681    }
01682 
01691    public java.util.Vector ls(String path) throws SftpException{
01692      //System.out.println("ls: "+path);
01693      try{
01694        ((MyPipedInputStream)io_in).updateReadSide();
01695 
01696        path=remoteAbsolutePath(path);
01697        byte[] pattern=null;
01698        java.util.Vector v=new java.util.Vector();
01699 
01700        int foo=path.lastIndexOf('/');
01701        String dir=path.substring(0, ((foo==0)?1:foo));
01702        String _pattern=path.substring(foo+1);
01703        dir=Util.unquote(dir);
01704 
01705        // If pattern has included '*' or '?', we need to convert
01706        // to UTF-8 string before globbing.
01707        byte[][] _pattern_utf8=new byte[1][];
01708        boolean pattern_has_wildcard=isPattern(_pattern, _pattern_utf8);
01709 
01710        if(pattern_has_wildcard){
01711          pattern=_pattern_utf8[0];
01712        }
01713        else{
01714          String upath=Util.unquote(path);
01715          //SftpATTRS attr=_lstat(upath);
01716          SftpATTRS attr=_stat(upath);
01717          if(attr.isDir()){
01718            pattern=null;
01719            dir=upath;
01720          }
01721          else{
01722            /*
01723              // If we can generage longname by ourself,
01724              // we don't have to use openDIR.
01725            String filename=Util.unquote(_pattern);
01726            String longname=...
01727            v.addElement(new LsEntry(filename, longname, attr));
01728            return v;
01729            */
01730 
01731            if(fEncoding_is_utf8){
01732              pattern=_pattern_utf8[0];
01733              pattern=Util.unquote(pattern);
01734            }
01735            else{
01736              _pattern=Util.unquote(_pattern);
01737              pattern=Util.str2byte(_pattern, fEncoding);
01738            }
01739 
01740          }
01741        }
01742 
01743        sendOPENDIR(Util.str2byte(dir, fEncoding));
01744 
01745        Header header=new Header();
01746        header=header(buf, header);
01747        int length=header.length;
01748        int type=header.type;
01749 
01750        fill(buf, length);
01751 
01752        if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
01753          throw new SftpException(SSH_FX_FAILURE, "");
01754        }
01755        if(type==SSH_FXP_STATUS){
01756          int i=buf.getInt();
01757          throwStatusError(buf, i);
01758        }
01759 
01760        byte[] handle=buf.getString();         // handle
01761 
01762        while(true){
01763          sendREADDIR(handle);
01764 
01765          header=header(buf, header);
01766          length=header.length;
01767          type=header.type;
01768          if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
01769            throw new SftpException(SSH_FX_FAILURE, "");
01770          }
01771          if(type==SSH_FXP_STATUS){ 
01772            fill(buf, length);
01773            int i=buf.getInt();
01774            if(i==SSH_FX_EOF)
01775              break;
01776            throwStatusError(buf, i);
01777          }
01778 
01779          buf.rewind();
01780          fill(buf.buffer, 0, 4); length-=4;
01781          int count=buf.getInt();
01782 
01783          byte[] str;
01784          int flags;
01785 
01786          buf.reset();
01787          while(count>0){
01788            if(length>0){
01789              buf.shift();
01790              int j=(buf.buffer.length>(buf.index+length)) ? 
01791                length : 
01792                (buf.buffer.length-buf.index);
01793              int i=fill(buf.buffer, buf.index, j);
01794              buf.index+=i;
01795              length-=i;
01796            }
01797            byte[] filename=buf.getString();
01798            byte[] longname=null;
01799            if(server_version<=3){
01800              longname=buf.getString();
01801            }
01802            SftpATTRS attrs=SftpATTRS.getATTR(buf);
01803 
01804            boolean find=false;
01805            String f=null;
01806            if(pattern==null){
01807              find=true;
01808            }
01809            else if(!pattern_has_wildcard){
01810              find=Util.array_equals(pattern, filename);
01811            }
01812            else{
01813              byte[] _filename=filename;
01814              if(!fEncoding_is_utf8){
01815                f=Util.byte2str(_filename, fEncoding);
01816                _filename=Util.str2byte(f, UTF8);
01817              }
01818              find=Util.glob(pattern, _filename);
01819            }
01820 
01821            if(find){
01822              if(f==null){
01823                f=Util.byte2str(filename, fEncoding);
01824              }
01825              String l=null;
01826              if(longname==null){
01827                // TODO: we need to generate long name from attrs
01828                //       for the sftp protocol 4(and later).
01829                l=attrs.toString()+" "+f;
01830              }
01831              else{
01832                l=Util.byte2str(longname, fEncoding);
01833              }
01834              v.addElement(new LsEntry(f, l, attrs));
01835            }
01836 
01837            count--; 
01838          }
01839        }
01840        _sendCLOSE(handle, header);
01841 
01842        /*
01843        if(v.size()==1 && pattern_has_wildcard){
01844          LsEntry le=(LsEntry)v.elementAt(0);
01845          if(le.getAttrs().isDir()){
01846            String f=le.getFilename();
01847            if(isPattern(f)){
01848              f=Util.quote(f);
01849            }
01850            if(!dir.endsWith("/")){
01851              dir+="/";
01852            }
01853            v=null;
01854            return ls(dir+f);
01855          }
01856        }
01857        */
01858 
01859        return v;
01860      }
01861      catch(Exception e){
01862        if(e instanceof SftpException) throw (SftpException)e;
01863        if(e instanceof Throwable)
01864          throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
01865        throw new SftpException(SSH_FX_FAILURE, "");
01866      }
01867    }
01868 
01878    public String readlink(String path) throws SftpException{
01879      try{
01880        if(server_version<3){
01881          throw new SftpException(SSH_FX_OP_UNSUPPORTED, 
01882                                  "The remote sshd is too old to support symlink operation.");
01883        }
01884 
01885        ((MyPipedInputStream)io_in).updateReadSide();
01886 
01887        path=remoteAbsolutePath(path);
01888 
01889        path=isUnique(path);
01890 
01891        sendREADLINK(Util.str2byte(path, fEncoding));
01892 
01893        Header header=new Header();
01894        header=header(buf, header);
01895        int length=header.length;
01896        int type=header.type;
01897 
01898        fill(buf, length);
01899 
01900        if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
01901          throw new SftpException(SSH_FX_FAILURE, "");
01902        }
01903        if(type==SSH_FXP_NAME){
01904          int count=buf.getInt();       // count
01905          byte[] filename=null;
01906          for(int i=0; i<count; i++){
01907            filename=buf.getString();
01908            if(server_version<=3){
01909              byte[] longname=buf.getString();
01910            }
01911            SftpATTRS.getATTR(buf);
01912          }
01913          return Util.byte2str(filename, fEncoding);
01914        }
01915 
01916        int i=buf.getInt();
01917        throwStatusError(buf, i);
01918      }
01919      catch(Exception e){
01920        if(e instanceof SftpException) throw (SftpException)e;
01921        if(e instanceof Throwable)
01922          throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
01923        throw new SftpException(SSH_FX_FAILURE, "");
01924      }
01925      return null;
01926    }
01927 
01948    public void symlink(String oldpath, String newpath) throws SftpException{
01949      if(server_version<3){
01950        throw new SftpException(SSH_FX_OP_UNSUPPORTED, 
01951                                "The remote sshd is too old to support symlink operation.");
01952      }
01953 
01954      try{
01955        ((MyPipedInputStream)io_in).updateReadSide();
01956 
01957        oldpath=remoteAbsolutePath(oldpath);
01958        newpath=remoteAbsolutePath(newpath);
01959 
01960        oldpath=isUnique(oldpath);
01961 
01962        if(isPattern(newpath)){
01963          throw new SftpException(SSH_FX_FAILURE, newpath);
01964        }
01965        newpath=Util.unquote(newpath);
01966 
01967        sendSYMLINK(Util.str2byte(oldpath, fEncoding),
01968                    Util.str2byte(newpath, fEncoding));
01969 
01970        Header header=new Header();
01971        header=header(buf, header);
01972        int length=header.length;
01973        int type=header.type;
01974 
01975        fill(buf, length);
01976 
01977        if(type!=SSH_FXP_STATUS){
01978          throw new SftpException(SSH_FX_FAILURE, "");
01979        }
01980 
01981        int i=buf.getInt();
01982        if(i==SSH_FX_OK) return;
01983        throwStatusError(buf, i);
01984      }
01985      catch(Exception e){
01986        if(e instanceof SftpException) throw (SftpException)e;
01987        if(e instanceof Throwable)
01988          throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
01989        throw new SftpException(SSH_FX_FAILURE, "");
01990      }
01991    }
01992 
02001    public void rename(String oldpath, String newpath) throws SftpException{
02002      if(server_version<2){
02003        throw new SftpException(SSH_FX_OP_UNSUPPORTED, 
02004                                "The remote sshd is too old to support rename operation.");
02005      }
02006 
02007      try{
02008        ((MyPipedInputStream)io_in).updateReadSide();
02009 
02010        oldpath=remoteAbsolutePath(oldpath);
02011        newpath=remoteAbsolutePath(newpath);
02012 
02013        oldpath=isUnique(oldpath);
02014 
02015        Vector v=glob_remote(newpath);
02016        int vsize=v.size();
02017        if(vsize>=2){
02018          throw new SftpException(SSH_FX_FAILURE, v.toString());
02019        }
02020        if(vsize==1){
02021          newpath=(String)(v.elementAt(0));
02022        }
02023        else{  // vsize==0
02024          if(isPattern(newpath))
02025            throw new SftpException(SSH_FX_FAILURE, newpath);
02026          newpath=Util.unquote(newpath);
02027        }
02028 
02029        sendRENAME(Util.str2byte(oldpath, fEncoding),
02030                   Util.str2byte(newpath, fEncoding));
02031 
02032        Header header=new Header();
02033        header=header(buf, header);
02034        int length=header.length;
02035        int type=header.type;
02036 
02037        fill(buf, length);
02038 
02039        if(type!=SSH_FXP_STATUS){
02040          throw new SftpException(SSH_FX_FAILURE, "");
02041        }
02042 
02043        int i=buf.getInt();
02044        if(i==SSH_FX_OK) return;
02045        throwStatusError(buf, i);
02046     }
02047     catch(Exception e){
02048       if(e instanceof SftpException) throw (SftpException)e;
02049       if(e instanceof Throwable)
02050         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02051       throw new SftpException(SSH_FX_FAILURE, "");
02052     }
02053   }
02054 
02061   public void rm(String path) throws SftpException{
02062     try{
02063       ((MyPipedInputStream)io_in).updateReadSide();
02064 
02065       path=remoteAbsolutePath(path);
02066 
02067       Vector v=glob_remote(path);
02068       int vsize=v.size();
02069 
02070       Header header=new Header();
02071 
02072       for(int j=0; j<vsize; j++){
02073     path=(String)(v.elementAt(j));
02074         sendREMOVE(Util.str2byte(path, fEncoding));
02075 
02076         header=header(buf, header);
02077         int length=header.length;
02078         int type=header.type;
02079 
02080         fill(buf, length);
02081 
02082         if(type!=SSH_FXP_STATUS){
02083       throw new SftpException(SSH_FX_FAILURE, "");
02084         }
02085         int i=buf.getInt();
02086     if(i!=SSH_FX_OK){
02087       throwStatusError(buf, i);
02088     }
02089       }
02090     }
02091     catch(Exception e){
02092       if(e instanceof SftpException) throw (SftpException)e;
02093       if(e instanceof Throwable)
02094         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02095       throw new SftpException(SSH_FX_FAILURE, "");
02096     }
02097   }
02098 
02099   private boolean isRemoteDir(String path){
02100     try{
02101       sendSTAT(Util.str2byte(path, fEncoding));
02102 
02103       Header header=new Header();
02104       header=header(buf, header);
02105       int length=header.length;
02106       int type=header.type;
02107 
02108       fill(buf, length);
02109 
02110       if(type!=SSH_FXP_ATTRS){
02111         return false; 
02112       }
02113       SftpATTRS attr=SftpATTRS.getATTR(buf);
02114       return attr.isDir();
02115     }
02116     catch(Exception e){}
02117     return false;
02118   }
02119 
02126   public void chgrp(int gid, String path) throws SftpException{
02127     try{
02128       ((MyPipedInputStream)io_in).updateReadSide();
02129 
02130       path=remoteAbsolutePath(path);
02131 
02132       Vector v=glob_remote(path);
02133       int vsize=v.size();
02134       for(int j=0; j<vsize; j++){
02135     path=(String)(v.elementAt(j));
02136 
02137         SftpATTRS attr=_stat(path);
02138 
02139     attr.setFLAGS(0);
02140     attr.setUIDGID(attr.uid, gid); 
02141     _setStat(path, attr);
02142       }
02143     }
02144     catch(Exception e){
02145       if(e instanceof SftpException) throw (SftpException)e;
02146       if(e instanceof Throwable)
02147         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02148       throw new SftpException(SSH_FX_FAILURE, "");
02149     }
02150   }
02151 
02158   public void chown(int uid, String path) throws SftpException{
02159     try{
02160       ((MyPipedInputStream)io_in).updateReadSide();
02161 
02162       path=remoteAbsolutePath(path);
02163 
02164       Vector v=glob_remote(path);
02165       int vsize=v.size();
02166       for(int j=0; j<vsize; j++){
02167     path=(String)(v.elementAt(j));
02168 
02169         SftpATTRS attr=_stat(path);
02170 
02171     attr.setFLAGS(0);
02172     attr.setUIDGID(uid, attr.gid); 
02173     _setStat(path, attr);
02174       }
02175     }
02176     catch(Exception e){
02177       if(e instanceof SftpException) throw (SftpException)e;
02178       if(e instanceof Throwable)
02179         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02180       throw new SftpException(SSH_FX_FAILURE, "");
02181     }
02182   }
02183 
02191   public void chmod(int permissions, String path) throws SftpException{
02192     try{
02193       ((MyPipedInputStream)io_in).updateReadSide();
02194 
02195       path=remoteAbsolutePath(path);
02196 
02197       Vector v=glob_remote(path);
02198       int vsize=v.size();
02199       for(int j=0; j<vsize; j++){
02200     path=(String)(v.elementAt(j));
02201 
02202     SftpATTRS attr=_stat(path);
02203 
02204     attr.setFLAGS(0);
02205     attr.setPERMISSIONS(permissions); 
02206     _setStat(path, attr);
02207       }
02208     }
02209     catch(Exception e){
02210       if(e instanceof SftpException) throw (SftpException)e;
02211       if(e instanceof Throwable)
02212         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02213       throw new SftpException(SSH_FX_FAILURE, "");
02214     }
02215   }
02216 
02224   public void setMtime(String path, int mtime) throws SftpException{
02225     try{
02226       ((MyPipedInputStream)io_in).updateReadSide();
02227 
02228       path=remoteAbsolutePath(path);
02229 
02230       Vector v=glob_remote(path);
02231       int vsize=v.size();
02232       for(int j=0; j<vsize; j++){
02233     path=(String)(v.elementAt(j));
02234 
02235         SftpATTRS attr=_stat(path);
02236 
02237     attr.setFLAGS(0);
02238     attr.setACMODTIME(attr.getATime(), mtime);
02239     _setStat(path, attr);
02240       }
02241     }
02242     catch(Exception e){
02243       if(e instanceof SftpException) throw (SftpException)e;
02244       if(e instanceof Throwable)
02245         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02246       throw new SftpException(SSH_FX_FAILURE, "");
02247     }
02248   }
02249 
02250 
02256   public void rmdir(String path) throws SftpException{
02257     try{
02258       ((MyPipedInputStream)io_in).updateReadSide();
02259 
02260       path=remoteAbsolutePath(path);
02261 
02262       Vector v=glob_remote(path);
02263       int vsize=v.size();
02264 
02265       Header header=new Header();
02266 
02267       for(int j=0; j<vsize; j++){
02268     path=(String)(v.elementAt(j));
02269     sendRMDIR(Util.str2byte(path, fEncoding));
02270 
02271         header=header(buf, header);
02272         int length=header.length;
02273         int type=header.type;
02274 
02275         fill(buf, length);
02276 
02277     if(type!=SSH_FXP_STATUS){
02278       throw new SftpException(SSH_FX_FAILURE, "");
02279     }
02280 
02281     int i=buf.getInt();
02282     if(i!=SSH_FX_OK){
02283       throwStatusError(buf, i);
02284     }
02285       }
02286     }
02287     catch(Exception e){
02288       if(e instanceof SftpException) throw (SftpException)e;
02289       if(e instanceof Throwable)
02290         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02291       throw new SftpException(SSH_FX_FAILURE, "");
02292     }
02293   }
02294 
02295 
02301   public void mkdir(String path) throws SftpException{
02302     try{
02303       ((MyPipedInputStream)io_in).updateReadSide();
02304 
02305       path=remoteAbsolutePath(path);
02306 
02307       sendMKDIR(Util.str2byte(path, fEncoding), null);
02308 
02309       Header header=new Header();      
02310       header=header(buf, header);
02311       int length=header.length;
02312       int type=header.type;
02313 
02314       fill(buf, length);
02315 
02316       if(type!=SSH_FXP_STATUS){
02317     throw new SftpException(SSH_FX_FAILURE, "");
02318       }
02319 
02320       int i=buf.getInt();
02321       if(i==SSH_FX_OK) return;
02322       throwStatusError(buf, i);
02323     }
02324     catch(Exception e){
02325       if(e instanceof SftpException) throw (SftpException)e;
02326       if(e instanceof Throwable)
02327         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02328       throw new SftpException(SSH_FX_FAILURE, "");
02329     }
02330   }
02331 
02342   public SftpATTRS stat(String path) throws SftpException{
02343     try{
02344       ((MyPipedInputStream)io_in).updateReadSide();
02345 
02346       path=remoteAbsolutePath(path);
02347       path=isUnique(path);
02348 
02349       return _stat(path);
02350     }
02351     catch(Exception e){
02352       if(e instanceof SftpException) throw (SftpException)e;
02353       if(e instanceof Throwable)
02354         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02355       throw new SftpException(SSH_FX_FAILURE, "");
02356     }
02357     //return null;
02358   }
02359 
02360   private SftpATTRS _stat(byte[] path) throws SftpException{
02361     try{
02362 
02363       sendSTAT(path);
02364 
02365       Header header=new Header();
02366       header=header(buf, header);
02367       int length=header.length;
02368       int type=header.type;
02369 
02370       fill(buf, length);
02371 
02372       if(type!=SSH_FXP_ATTRS){
02373     if(type==SSH_FXP_STATUS){
02374       int i=buf.getInt();
02375       throwStatusError(buf, i);
02376     }
02377     throw new SftpException(SSH_FX_FAILURE, "");
02378       }
02379       SftpATTRS attr=SftpATTRS.getATTR(buf);
02380       return attr;
02381     }
02382     catch(Exception e){
02383       if(e instanceof SftpException) throw (SftpException)e;
02384       if(e instanceof Throwable)
02385         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02386       throw new SftpException(SSH_FX_FAILURE, "");
02387     }
02388     //return null;
02389   }
02390 
02391   private SftpATTRS _stat(String path) throws SftpException{
02392     return _stat(Util.str2byte(path, fEncoding));
02393   }
02394 
02405   public SftpATTRS lstat(String path) throws SftpException{
02406     try{
02407       ((MyPipedInputStream)io_in).updateReadSide();
02408 
02409       path=remoteAbsolutePath(path);
02410       path=isUnique(path);
02411 
02412       return _lstat(path);
02413     }
02414     catch(Exception e){
02415       if(e instanceof SftpException) throw (SftpException)e;
02416       if(e instanceof Throwable)
02417         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02418       throw new SftpException(SSH_FX_FAILURE, "");
02419     }
02420   }
02421 
02422   private SftpATTRS _lstat(String path) throws SftpException{
02423     try{
02424       sendLSTAT(Util.str2byte(path, fEncoding));
02425 
02426       Header header=new Header();
02427       header=header(buf, header);
02428       int length=header.length;
02429       int type=header.type;
02430 
02431       fill(buf, length);
02432 
02433       if(type!=SSH_FXP_ATTRS){
02434     if(type==SSH_FXP_STATUS){
02435       int i=buf.getInt();
02436       throwStatusError(buf, i);
02437     }
02438     throw new SftpException(SSH_FX_FAILURE, "");
02439       }
02440       SftpATTRS attr=SftpATTRS.getATTR(buf);
02441       return attr;
02442     }
02443     catch(Exception e){
02444       if(e instanceof SftpException) throw (SftpException)e;
02445       if(e instanceof Throwable)
02446         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02447       throw new SftpException(SSH_FX_FAILURE, "");
02448     }
02449   }
02450 
02451   private byte[] _realpath(String path) throws SftpException, IOException, Exception{
02452     sendREALPATH(Util.str2byte(path, fEncoding));
02453 
02454     Header header=new Header();
02455     header=header(buf, header);
02456     int length=header.length;
02457     int type=header.type;
02458 
02459     fill(buf, length);
02460 
02461     if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
02462       throw new SftpException(SSH_FX_FAILURE, "");
02463     }
02464     int i;
02465     if(type==SSH_FXP_STATUS){
02466       i=buf.getInt();
02467       throwStatusError(buf, i);
02468     }
02469     i=buf.getInt();   // count
02470 
02471     byte[] str=null;
02472     while(i-->0){
02473       str=buf.getString();  // absolute path;
02474       if(server_version<=3){
02475         byte[] lname=buf.getString();  // long filename
02476       }
02477       SftpATTRS attr=SftpATTRS.getATTR(buf);  // dummy attribute
02478     }
02479     return str;
02480   }
02481 
02488   public void setStat(String path, SftpATTRS attr) throws SftpException{
02489     try{
02490       ((MyPipedInputStream)io_in).updateReadSide();
02491 
02492       path=remoteAbsolutePath(path);
02493 
02494       Vector v=glob_remote(path);
02495       int vsize=v.size();
02496       for(int j=0; j<vsize; j++){
02497     path=(String)(v.elementAt(j));
02498     _setStat(path, attr);
02499       }
02500     }
02501     catch(Exception e){
02502       if(e instanceof SftpException) throw (SftpException)e;
02503       if(e instanceof Throwable)
02504         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02505       throw new SftpException(SSH_FX_FAILURE, "");
02506     }
02507   }
02508   private void _setStat(String path, SftpATTRS attr) throws SftpException{
02509     try{
02510       sendSETSTAT(Util.str2byte(path, fEncoding), attr);
02511 
02512       Header header=new Header();
02513       header=header(buf, header);
02514       int length=header.length;
02515       int type=header.type;
02516 
02517       fill(buf, length);
02518 
02519       if(type!=SSH_FXP_STATUS){
02520     throw new SftpException(SSH_FX_FAILURE, "");
02521       }
02522       int i=buf.getInt();
02523       if(i!=SSH_FX_OK){
02524     throwStatusError(buf, i);
02525       }
02526     }
02527     catch(Exception e){
02528       if(e instanceof SftpException) throw (SftpException)e;
02529       if(e instanceof Throwable)
02530         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02531       throw new SftpException(SSH_FX_FAILURE, "");
02532     }
02533   }
02534 
02540   public String pwd() throws SftpException{ return getCwd(); }
02546   public String lpwd(){ return lcwd; }
02550   public String version(){ return version; }
02551 
02555   public String getHome() throws SftpException {
02556     if(home==null){
02557       try{
02558         ((MyPipedInputStream)io_in).updateReadSide();
02559 
02560         byte[] _home=_realpath("");
02561         home=Util.byte2str(_home, fEncoding);
02562       }
02563       catch(Exception e){
02564         if(e instanceof SftpException) throw (SftpException)e;
02565         if(e instanceof Throwable)
02566           throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
02567         throw new SftpException(SSH_FX_FAILURE, "");
02568       }
02569     }
02570     return home; 
02571   }
02572 
02573   private String getCwd() throws SftpException{
02574     if(cwd==null)
02575       cwd=getHome();
02576     return cwd;
02577   }
02578 
02579   private void setCwd(String cwd){
02580     this.cwd=cwd;
02581   }
02582 
02583   private void read(byte[] buf, int s, int l) throws IOException, SftpException{
02584     int i=0;
02585     while(l>0){
02586       i=io_in.read(buf, s, l);
02587       if(i<=0){
02588         throw new SftpException(SSH_FX_FAILURE, "");
02589       }
02590       s+=i;
02591       l-=i;
02592     }
02593   }
02594 
02595   private boolean checkStatus(int[] ackid, Header header) throws IOException, SftpException{
02596     header=header(buf, header);
02597     int length=header.length;
02598     int type=header.type;
02599     if(ackid!=null)
02600       ackid[0]=header.rid;
02601 
02602     fill(buf, length);
02603 
02604     if(type!=SSH_FXP_STATUS){ 
02605       throw new SftpException(SSH_FX_FAILURE, "");
02606     }
02607     int i=buf.getInt();
02608     if(i!=SSH_FX_OK){
02609       throwStatusError(buf, i);
02610     }
02611     return true;
02612   }
02613   private boolean _sendCLOSE(byte[] handle, Header header) throws Exception{
02614     sendCLOSE(handle);
02615     return checkStatus(null, header);
02616   }
02617 
02618   private void sendINIT() throws Exception{
02619     packet.reset();
02620     putHEAD(SSH_FXP_INIT, 5);
02621     buf.putInt(3);                // version 3
02622     getSession().write(packet, this, 5+4);
02623   }
02624 
02625   private void sendREALPATH(byte[] path) throws Exception{
02626     sendPacketPath(SSH_FXP_REALPATH, path);
02627   }
02628   private void sendSTAT(byte[] path) throws Exception{
02629     sendPacketPath(SSH_FXP_STAT, path);
02630   }
02631   private void sendLSTAT(byte[] path) throws Exception{
02632     sendPacketPath(SSH_FXP_LSTAT, path);
02633   }
02634   private void sendFSTAT(byte[] handle) throws Exception{
02635     sendPacketPath(SSH_FXP_FSTAT, handle);
02636   }
02637   private void sendSETSTAT(byte[] path, SftpATTRS attr) throws Exception{
02638     packet.reset();
02639     putHEAD(SSH_FXP_SETSTAT, 9+path.length+attr.length());
02640     buf.putInt(seq++);
02641     buf.putString(path);             // path
02642     attr.dump(buf);
02643     getSession().write(packet, this, 9+path.length+attr.length()+4);
02644   }
02645   private void sendREMOVE(byte[] path) throws Exception{
02646     sendPacketPath(SSH_FXP_REMOVE, path);
02647   }
02648   private void sendMKDIR(byte[] path, SftpATTRS attr) throws Exception{
02649     packet.reset();
02650     putHEAD(SSH_FXP_MKDIR, 9+path.length+(attr!=null?attr.length():4));
02651     buf.putInt(seq++);
02652     buf.putString(path);             // path
02653     if(attr!=null) attr.dump(buf);
02654     else buf.putInt(0);
02655     getSession().write(packet, this, 9+path.length+(attr!=null?attr.length():4)+4);
02656   }
02657   private void sendRMDIR(byte[] path) throws Exception{
02658     sendPacketPath(SSH_FXP_RMDIR, path);
02659   }
02660   private void sendSYMLINK(byte[] p1, byte[] p2) throws Exception{
02661     sendPacketPath(SSH_FXP_SYMLINK, p1, p2);
02662   }
02663   private void sendREADLINK(byte[] path) throws Exception{
02664     sendPacketPath(SSH_FXP_READLINK, path);
02665   }
02666   private void sendOPENDIR(byte[] path) throws Exception{
02667     sendPacketPath(SSH_FXP_OPENDIR, path);
02668   }
02669   private void sendREADDIR(byte[] path) throws Exception{
02670     sendPacketPath(SSH_FXP_READDIR, path);
02671   }
02672   private void sendRENAME(byte[] p1, byte[] p2) throws Exception{
02673     sendPacketPath(SSH_FXP_RENAME, p1, p2);
02674   }
02675   private void sendCLOSE(byte[] path) throws Exception{
02676     sendPacketPath(SSH_FXP_CLOSE, path);
02677   }
02678   private void sendOPENR(byte[] path) throws Exception{
02679     sendOPEN(path, SSH_FXF_READ);
02680   }
02681   private void sendOPENW(byte[] path) throws Exception{
02682     sendOPEN(path, SSH_FXF_WRITE|SSH_FXF_CREAT|SSH_FXF_TRUNC);
02683   }
02684   private void sendOPENA(byte[] path) throws Exception{
02685     sendOPEN(path, SSH_FXF_WRITE|/*SSH_FXF_APPEND|*/SSH_FXF_CREAT);
02686   }
02687   private void sendOPEN(byte[] path, int mode) throws Exception{
02688     packet.reset();
02689     putHEAD(SSH_FXP_OPEN, 17+path.length);
02690     buf.putInt(seq++);
02691     buf.putString(path);
02692     buf.putInt(mode);
02693     buf.putInt(0);           // attrs
02694     getSession().write(packet, this, 17+path.length+4);
02695   }
02696   private void sendPacketPath(byte fxp, byte[] path) throws Exception{
02697     packet.reset();
02698     putHEAD(fxp, 9+path.length);
02699     buf.putInt(seq++);
02700     buf.putString(path);             // path
02701     getSession().write(packet, this, 9+path.length+4);
02702   }
02703   private void sendPacketPath(byte fxp, byte[] p1, byte[] p2) throws Exception{
02704     packet.reset();
02705     putHEAD(fxp, 13+p1.length+p2.length);
02706     buf.putInt(seq++);
02707     buf.putString(p1);
02708     buf.putString(p2);
02709     getSession().write(packet, this, 13+p1.length+p2.length+4);
02710   }
02711 
02712   private int sendWRITE(byte[] handle, long offset, 
02713                         byte[] data, int start, int length) throws Exception{
02714     int _length=length;
02715     opacket.reset();
02716     if(obuf.buffer.length<obuf.index+13+21+handle.length+length+Session.buffer_margin){
02717       _length=obuf.buffer.length-(obuf.index+13+21+handle.length+Session.buffer_margin);
02718       // System.err.println("_length="+_length+" length="+length);
02719     }
02720 
02721     putHEAD(obuf, SSH_FXP_WRITE, 21+handle.length+_length);       // 14
02722     obuf.putInt(seq++);                                      //  4
02723     obuf.putString(handle);                                  //  4+handle.length
02724     obuf.putLong(offset);                                    //  8
02725     if(obuf.buffer!=data){
02726       obuf.putString(data, start, _length);                    //  4+_length
02727     }
02728     else{
02729       obuf.putInt(_length);
02730       obuf.skip(_length);
02731     }
02732     getSession().write(opacket, this, 21+handle.length+_length+4);
02733     return _length;
02734   }
02735   private void sendREAD(byte[] handle, long offset, int length) throws Exception{
02736     sendREAD(handle, offset, length, null);
02737   }
02738   private void sendREAD(byte[] handle, long offset, int length,
02739                         RequestQueue rrq) throws Exception{
02740     packet.reset();
02741     putHEAD(SSH_FXP_READ, 21+handle.length);
02742     buf.putInt(seq++);
02743     buf.putString(handle);
02744     buf.putLong(offset);
02745     buf.putInt(length);
02746     getSession().write(packet, this, 21+handle.length+4);
02747     if(rrq!=null){
02748       rrq.add(seq-1, offset, length);
02749     }
02750   }
02751 
02752   private void putHEAD(Buffer buf, byte type, int length) throws Exception{
02753     buf.putByte((byte)Session.SSH_MSG_CHANNEL_DATA);
02754     buf.putInt(recipient);
02755     buf.putInt(length+4);
02756     buf.putInt(length);
02757     buf.putByte(type);
02758   }
02759 
02760   private void putHEAD(byte type, int length) throws Exception{
02761     putHEAD(buf, type, length);
02762   }
02763 
02764   private Vector glob_remote(String _path) throws Exception{
02765     Vector v=new Vector();
02766     int i=0;
02767 
02768     int foo=_path.lastIndexOf('/');
02769     if(foo<0){  // it is not absolute path.
02770       v.addElement(Util.unquote(_path)); 
02771       return v;
02772     }
02773 
02774     String dir=_path.substring(0, ((foo==0)?1:foo));
02775     String _pattern=_path.substring(foo+1);
02776 
02777     dir=Util.unquote(dir);
02778 
02779     byte[] pattern=null;
02780     byte[][] _pattern_utf8=new byte[1][];
02781     boolean pattern_has_wildcard=isPattern(_pattern, _pattern_utf8);
02782 
02783     if(!pattern_has_wildcard){
02784       if(!dir.equals("/"))
02785         dir+="/";
02786       v.addElement(dir+Util.unquote(_pattern));
02787       return v;
02788     }
02789 
02790     pattern=_pattern_utf8[0];
02791 
02792     sendOPENDIR(Util.str2byte(dir, fEncoding));
02793 
02794     Header header=new Header();
02795     header=header(buf, header);
02796     int length=header.length;
02797     int type=header.type;
02798 
02799     fill(buf, length);
02800 
02801     if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
02802       throw new SftpException(SSH_FX_FAILURE, "");
02803     }
02804     if(type==SSH_FXP_STATUS){
02805       i=buf.getInt();
02806       throwStatusError(buf, i);
02807     }
02808 
02809     byte[] handle=buf.getString();         // filename
02810     String pdir=null;                      // parent directory
02811 
02812     while(true){
02813       sendREADDIR(handle);
02814       header=header(buf, header);
02815       length=header.length;
02816       type=header.type;
02817 
02818       if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
02819     throw new SftpException(SSH_FX_FAILURE, "");
02820       }
02821       if(type==SSH_FXP_STATUS){ 
02822         fill(buf, length);
02823     break;
02824       }
02825 
02826       buf.rewind();
02827       fill(buf.buffer, 0, 4); length-=4;
02828       int count=buf.getInt();
02829 
02830       byte[] str;
02831       int flags;
02832 
02833       buf.reset();
02834       while(count>0){
02835     if(length>0){
02836       buf.shift();
02837           int j=(buf.buffer.length>(buf.index+length)) ? length : (buf.buffer.length-buf.index);
02838       i=io_in.read(buf.buffer, buf.index, j);
02839       if(i<=0)break;
02840       buf.index+=i;
02841       length-=i;
02842     }
02843 
02844     byte[] filename=buf.getString();
02845     //System.err.println("filename: "+new String(filename));
02846         if(server_version<=3){
02847           str=buf.getString();  // longname
02848         }
02849     SftpATTRS attrs=SftpATTRS.getATTR(buf);
02850 
02851         byte[] _filename=filename;
02852         String f=null;
02853         boolean found=false;
02854 
02855         if(!fEncoding_is_utf8){
02856           f=Util.byte2str(filename, fEncoding);
02857           _filename=Util.str2byte(f, UTF8);
02858         }
02859         found=Util.glob(pattern, _filename);
02860 
02861     if(found){
02862           if(f==null){
02863             f=Util.byte2str(filename, fEncoding);
02864           }
02865           if(pdir==null){
02866             pdir=dir;
02867             if(!pdir.endsWith("/")){
02868               pdir+="/";
02869             }
02870           }
02871       v.addElement(pdir+f);
02872     }
02873     count--; 
02874       }
02875     }
02876     if(_sendCLOSE(handle, header)) 
02877       return v;
02878     return null;
02879   }
02880 
02881   private boolean isPattern(byte[] path){
02882     int length=path.length;
02883     int i=0;
02884     while(i<length){
02885       if(path[i]=='*' || path[i]=='?')
02886         return true;
02887       if(path[i]=='\\' && (i+1)<length)
02888         i++;
02889       i++;
02890     }
02891     return false;
02892   }
02893 
02894   private Vector glob_local(String _path) throws Exception{
02895 //System.err.println("glob_local: "+_path);
02896     Vector v=new Vector();
02897     byte[] path=Util.str2byte(_path, UTF8);
02898     int i=path.length-1;
02899     while(i>=0){
02900       if(path[i]!='*' && path[i]!='?'){
02901         i--;
02902         continue;
02903       }
02904       if(!fs_is_bs &&
02905          i>0 && path[i-1]=='\\'){
02906         i--;
02907         if(i>0 && path[i-1]=='\\'){
02908           i--;
02909           i--;
02910           continue;
02911         }
02912       }
02913       break;
02914     }
02915 
02916     if(i<0){ v.addElement(fs_is_bs ? _path : Util.unquote(_path)); return v;}
02917 
02918     while(i>=0){
02919       if(path[i]==file_separatorc ||
02920          (fs_is_bs && path[i]=='/')){ // On Windows, '/' is also the separator.
02921         break;
02922       }
02923       i--;
02924     }
02925 
02926     if(i<0){ v.addElement(fs_is_bs ? _path : Util.unquote(_path)); return v;}
02927 
02928     byte[] dir;
02929     if(i==0){dir=new byte[]{(byte)file_separatorc};}
02930     else{ 
02931       dir=new byte[i];
02932       System.arraycopy(path, 0, dir, 0, i);
02933     }
02934 
02935     byte[] pattern=new byte[path.length-i-1];
02936     System.arraycopy(path, i+1, pattern, 0, pattern.length);
02937 
02938 //System.err.println("dir: "+new String(dir)+" pattern: "+new String(pattern));
02939     try{
02940       String[] children=(new File(Util.byte2str(dir, UTF8))).list();
02941       String pdir=Util.byte2str(dir)+file_separator;
02942       for(int j=0; j<children.length; j++){
02943 //System.err.println("children: "+children[j]);
02944     if(Util.glob(pattern, Util.str2byte(children[j], UTF8))){
02945       v.addElement(pdir+children[j]);
02946     }
02947       }
02948     }
02949     catch(Exception e){
02950     }
02951     return v;
02952   }
02953 
02954   private void throwStatusError(Buffer buf, int i) throws SftpException{
02955     if(server_version>=3 &&   // WindRiver's sftp will send invalid 
02956        buf.getLength()>=4){   // SSH_FXP_STATUS packet.
02957       byte[] str=buf.getString();
02958       //byte[] tag=buf.getString();
02959       throw new SftpException(i, Util.byte2str(str, UTF8));
02960     }
02961     else{
02962       throw new SftpException(i, "Failure");
02963     }
02964   }
02965 
02966   private static boolean isLocalAbsolutePath(String path){
02967     return (new File(path)).isAbsolute();
02968   }
02969 
02973   public void disconnect(){
02974     super.disconnect();
02975   }
02976 
02977   private boolean isPattern(String path, byte[][] utf8){
02978     byte[] _path=Util.str2byte(path, UTF8);
02979     if(utf8!=null)
02980       utf8[0]=_path;
02981     return isPattern(_path);
02982   }
02983 
02984   private boolean isPattern(String path){
02985     return isPattern(path, null);
02986   }
02987 
02988   private void fill(Buffer buf, int len)  throws IOException{
02989     buf.reset();
02990     fill(buf.buffer, 0, len);
02991     buf.skip(len);
02992   }
02993 
02994   private int fill(byte[] buf, int s, int len) throws IOException{
02995     int i=0;
02996     int foo=s;
02997     while(len>0){
02998       i=io_in.read(buf, s, len);
02999       if(i<=0){
03000         throw new IOException("inputstream is closed");
03001         //return (s-foo)==0 ? i : s-foo;
03002       }
03003       s+=i;
03004       len-=i;
03005     }
03006     return s-foo;
03007   }
03008   private void skip(long foo) throws IOException{
03009     while(foo>0){
03010       long bar=io_in.skip(foo);
03011       if(bar<=0) 
03012         break;
03013       foo-=bar;
03014     }
03015   }
03016 
03017   class Header{
03018     int length;
03019     int type;
03020     int rid;
03021   }
03022   private Header header(Buffer buf, Header header) throws IOException{
03023     buf.rewind();
03024     int i=fill(buf.buffer, 0, 9);
03025     header.length=buf.getInt()-5;
03026     header.type=buf.getByte()&0xff;
03027     header.rid=buf.getInt();  
03028     return header;
03029   }
03030 
03031   private String remoteAbsolutePath(String path) throws SftpException{
03032     if(path.charAt(0)=='/') return path;
03033     String cwd=getCwd();
03034 //    if(cwd.equals(getHome())) return path;
03035     if(cwd.endsWith("/")) return cwd+path;
03036     return cwd+"/"+path;
03037   }
03038 
03039   private String localAbsolutePath(String path){
03040     if(isLocalAbsolutePath(path)) return path;
03041     if(lcwd.endsWith(file_separator)) return lcwd+path;
03042     return lcwd+file_separator+path;
03043   }
03044 
03051   private String isUnique(String path) throws SftpException, Exception{
03052     Vector v=glob_remote(path);
03053     if(v.size()!=1){
03054       throw new SftpException(SSH_FX_FAILURE, path+" is not unique: "+v.toString());
03055     }
03056     return (String)(v.elementAt(0));
03057   }
03058 
03062   public int getServerVersion() throws SftpException{
03063     if(!isConnected()){
03064       throw new SftpException(SSH_FX_FAILURE, "The channel is not connected.");
03065     }
03066     return server_version;
03067   }
03068 
03079   public void setFilenameEncoding(String encoding) throws SftpException{
03080     int sversion=getServerVersion();
03081     if(3 <= sversion && sversion <= 5 &&
03082        !encoding.equals(UTF8)){
03083       throw new SftpException(SSH_FX_FAILURE,
03084                               "The encoding can not be changed for this sftp server.");
03085     }
03086     if(encoding.equals(UTF8)){
03087       encoding=UTF8;
03088     }
03089     fEncoding=encoding;
03090     fEncoding_is_utf8=fEncoding.equals(UTF8);
03091   }
03092 
03099   public String getExtension(String key){
03100     if(extensions==null)
03101       return null;
03102     return (String)extensions.get(key);
03103   }
03104 
03113   public String realpath(String path) throws SftpException{
03114     try{
03115       byte[] _path=_realpath(remoteAbsolutePath(path));
03116       return Util.byte2str(_path, fEncoding);
03117     }
03118     catch(Exception e){
03119       if(e instanceof SftpException) throw (SftpException)e;
03120       if(e instanceof Throwable)
03121         throw new SftpException(SSH_FX_FAILURE, "", (Throwable)e);
03122       throw new SftpException(SSH_FX_FAILURE, "");
03123     }
03124   }
03125 
03132   public class LsEntry implements Comparable{
03133     private  String filename;
03134     private  String longname;
03135     private  SftpATTRS attrs;
03136     LsEntry(String filename, String longname, SftpATTRS attrs){
03137       setFilename(filename);
03138       setLongname(longname);
03139       setAttrs(attrs);
03140     }
03144     public String getFilename(){return filename;};
03145     void setFilename(String filename){this.filename = filename;};
03151     public String getLongname(){return longname;};
03152     void setLongname(String longname){this.longname = longname;};
03156     public SftpATTRS getAttrs(){return attrs;};
03157     void setAttrs(SftpATTRS attrs) {this.attrs = attrs;};
03161     public String toString(){ return longname; }
03166     public int compareTo(Object o) throws ClassCastException{
03167       if(o instanceof LsEntry){
03168         return filename.compareTo(((LsEntry)o).getFilename());
03169       }
03170       throw new ClassCastException("a decendent of LsEntry must be given.");
03171     }
03172   }
03173 }

Generated on 5 May 2015 for HPCVIEWER by  doxygen 1.6.1