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