1 /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
3 Copyright (c) 2002-2010 ymnk, JCraft,Inc. All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
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.
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.
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.
30 package com.jcraft.jsch;
34 import java.util.Vector;
36 public class ChannelSftp extends ChannelSession{
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;
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;
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;
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;
91 Indicates successful completion of the operation.
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.
97 is returned when a reference is made to a file which should exist
99 SSH_FX_PERMISSION_DENIED
100 is returned when the authenticated user does not have sufficient
101 permissions to perform the operation.
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
107 may be returned if a badly formatted packet or protocol
108 incompatibility is detected.
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
125 private static final int MAX_MSG_LENGTH = 256* 1024;
127 public static final int OVERWRITE=0;
128 public static final int RESUME=1;
129 public static final int APPEND=2;
131 private boolean interactive=false;
133 private int[] ackid=new int[1];
135 private Packet packet=new Packet(buf);
137 private int client_version=3;
138 private int server_version=3;
139 private String version=String.valueOf(client_version);
141 private java.util.Hashtable extensions=null;
142 private InputStream io_in=null;
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.
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 == '\\';
168 private static final String UTF8="UTF-8";
169 private String fEncoding=UTF8;
170 private boolean fEncoding_is_utf8=true;
175 public void start() throws JSchException{
178 PipedOutputStream pos=new PipedOutputStream();
179 io.setOutputStream(pos);
180 PipedInputStream pis=new MyPipedInputStream(pos, 32*1024);
181 io.setInputStream(pis);
186 throw new JSchException("channel is down");
189 Request request=new RequestSftp();
190 request.request(getSession(), this);
193 System.err.println("lmpsize: "+lmpsize);
194 System.err.println("lwsize: "+lwsize);
195 System.err.println("rmpsize: "+rmpsize);
196 System.err.println("rwsize: "+rwsize);
199 buf=new Buffer(rmpsize);
200 packet=new Packet(buf);
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);
217 type=header.type; // 2 -> SSH_FXP_VERSION
218 server_version=header.rid;
219 //System.err.println("SFTP protocol server-version="+server_version);
221 extensions=new java.util.Hashtable();
224 byte[] extension_name=null;
225 byte[] extension_data=null;
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));
236 lcwd=new File(".").getCanonicalPath();
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());
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()){
253 path=(new File(path)).getCanonicalPath();
259 throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such directory");
262 public void cd(String path) throws SftpException{
264 path=remoteAbsolutePath(path);
268 byte[] str=_realpath(path);
269 SftpATTRS attr=_stat(str);
271 if((attr.getFlags()&SftpATTRS.SSH_FILEXFER_ATTR_PERMISSIONS)==0){
272 throw new SftpException(SSH_FX_FAILURE,
273 "Can't change directory: "+path);
276 throw new SftpException(SSH_FX_FAILURE,
277 "Can't change directory: "+path);
280 setCwd(Util.byte2str(str, fEncoding));
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, "");
290 public void put(String src, String dst) throws SftpException{
291 put(src, dst, null, OVERWRITE);
293 public void put(String src, String dst, int mode) throws SftpException{
294 put(src, dst, null, mode);
296 public void put(String src, String dst,
297 SftpProgressMonitor monitor) throws SftpException{
298 put(src, dst, monitor, OVERWRITE);
300 public void put(String src, String dst,
301 SftpProgressMonitor monitor, int mode) throws SftpException{
302 src=localAbsolutePath(src);
303 dst=remoteAbsolutePath(dst);
307 Vector v=glob_remote(dst);
312 throw new SftpException(SSH_FX_FAILURE, dst);
314 dst=Util.unquote(dst);
316 throw new SftpException(SSH_FX_FAILURE, v.toString());
319 dst=(String)(v.elementAt(0));
322 boolean isRemoteDir=isRemoteDir(dst);
327 StringBuffer dstsb=null;
329 if(!dst.endsWith("/")){
332 dstsb=new StringBuffer(dst);
335 throw new SftpException(SSH_FX_FAILURE,
336 "Copying multiple files, but the destination is missing or a file.");
339 for(int j=0; j<vsize; j++){
340 String _src=(String)(v.elementAt(j));
343 int i=_src.lastIndexOf(file_separatorc);
345 int ii=_src.lastIndexOf('/');
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());
357 //System.err.println("_dst "+_dst);
362 SftpATTRS attr=_stat(_dst);
363 size_of_dst=attr.getSize();
365 catch(Exception eee){
366 //System.err.println(eee);
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);
373 if(size_of_src==size_of_dst){
379 monitor.init(SftpProgressMonitor.PUT, _src, _dst,
380 (new File(_src)).length());
382 monitor.count(size_of_dst);
385 FileInputStream fis=null;
387 fis=new FileInputStream(_src);
388 _put(fis, _dst, monitor, mode);
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());
404 public void put(InputStream src, String dst) throws SftpException{
405 put(src, dst, null, OVERWRITE);
407 public void put(InputStream src, String dst, int mode) throws SftpException{
408 put(src, dst, null, mode);
410 public void put(InputStream src, String dst,
411 SftpProgressMonitor monitor) throws SftpException{
412 put(src, dst, monitor, OVERWRITE);
414 public void put(InputStream src, String dst,
415 SftpProgressMonitor monitor, int mode) throws SftpException{
417 dst=remoteAbsolutePath(dst);
419 Vector v=glob_remote(dst);
424 throw new SftpException(SSH_FX_FAILURE, dst);
426 dst=Util.unquote(dst);
428 throw new SftpException(SSH_FX_FAILURE, v.toString());
431 dst=(String)(v.elementAt(0));
434 if(isRemoteDir(dst)){
435 throw new SftpException(SSH_FX_FAILURE, dst+" is a directory");
438 _put(src, dst, monitor, mode);
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());
448 public void _put(InputStream src, String dst,
449 SftpProgressMonitor monitor, int mode) throws SftpException{
451 byte[] dstb=Util.str2byte(dst, fEncoding);
453 if(mode==RESUME || mode==APPEND){
455 SftpATTRS attr=_stat(dstb);
458 catch(Exception eee){
459 //System.err.println(eee);
462 if(mode==RESUME && skip>0){
463 long skipped=src.skip(skip);
465 throw new SftpException(SSH_FX_FAILURE, "failed to resume for "+dst);
469 if(mode==OVERWRITE){ sendOPENW(dstb); }
470 else{ sendOPENA(dstb); }
472 Header header=new Header();
473 header=header(buf, header);
474 int length=header.length;
475 int type=header.type;
479 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
480 throw new SftpException(SSH_FX_FAILURE, "invalid type="+type);
482 if(type==SSH_FXP_STATUS){
484 throwStatusError(buf, i);
486 byte[] handle=buf.getString(); // handle
489 boolean dontcopy=true;
492 data=new byte[buf.buffer.length
493 -(5+13+21+handle.length
494 +32 +20 // padding and mac
500 if(mode==RESUME || mode==APPEND){
514 datalen=data.length-s;
518 s=5+13+21+handle.length;
519 datalen=buf.buffer.length -s
520 -32 -20; // padding and mac
524 nread=src.read(data, s, datalen);
531 while(datalen>0 && nread>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)){
542 if(startid>_ackid || _ackid>seq-1){
544 System.err.println("ack error: startid="+startid+" seq="+seq+" _ackid="+_ackid);
547 //throw new SftpException(SSH_FX_FAILURE, "ack error:");
548 throw new SftpException(SSH_FX_FAILURE, "ack error: startid="+startid+" seq="+seq+" _ackid="+_ackid);
560 if(monitor!=null && !monitor.count(count)){
564 int _ackcount=seq-startid;
565 while(_ackcount>ackcount){
566 if(!checkStatus(null, header)){
571 if(monitor!=null)monitor.end();
572 _sendCLOSE(handle, header);
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());
582 public OutputStream put(String dst) throws SftpException{
583 return put(dst, (SftpProgressMonitor)null, OVERWRITE);
585 public OutputStream put(String dst, final int mode) throws SftpException{
586 return put(dst, (SftpProgressMonitor)null, mode);
588 public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode) throws SftpException{
589 return put(dst, monitor, mode, 0);
591 public OutputStream put(String dst, final SftpProgressMonitor monitor, final int mode, long offset) throws SftpException{
592 dst=remoteAbsolutePath(dst);
597 if(isRemoteDir(dst)){
598 throw new SftpException(SSH_FX_FAILURE, dst+" is a directory");
601 byte[] dstb=Util.str2byte(dst, fEncoding);
604 if(mode==RESUME || mode==APPEND){
606 SftpATTRS attr=_stat(dstb);
609 catch(Exception eee){
610 //System.err.println(eee);
614 if(mode==OVERWRITE){ sendOPENW(dstb); }
615 else{ sendOPENA(dstb); }
617 Header header=new Header();
618 header=header(buf, header);
619 int length=header.length;
620 int type=header.type;
624 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
625 throw new SftpException(SSH_FX_FAILURE, "");
627 if(type==SSH_FXP_STATUS){
629 throwStatusError(buf, i);
631 final byte[] handle=buf.getString(); // handle
633 if(mode==RESUME || mode==APPEND){
637 final long[] _offset=new long[1];
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();
649 public void write(byte[] d) throws java.io.IOException{
650 write(d, 0, d.length);
653 public void write(byte[] d, int s, int len) throws java.io.IOException{
661 throw new IOException("stream already closed");
667 int sent=sendWRITE(handle, _offset[0], d, s, _len);
672 if((seq-1)==startid ||
673 io_in.available()>=1024){
674 while(io_in.available()>0){
675 if(checkStatus(ackid, header)){
677 if(startid>_ackid || _ackid>seq-1){
678 throw new SftpException(SSH_FX_FAILURE, "");
688 if(monitor!=null && !monitor.count(len)){
690 throw new IOException("canceled");
693 catch(IOException e){ throw e; }
694 catch(Exception e){ throw new IOException(e.toString()); }
697 byte[] _data=new byte[1];
698 public void write(int foo) throws java.io.IOException{
703 public void flush() throws java.io.IOException{
706 throw new IOException("stream already closed");
711 while(writecount>ackcount){
712 if(!checkStatus(null, header)){
718 catch(SftpException e){
719 throw new IOException(e.toString());
724 public void close() throws java.io.IOException{
729 if(monitor!=null)monitor.end();
730 try{ _sendCLOSE(handle, header); }
731 catch(IOException e){ throw e; }
733 throw new IOException(e.toString());
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, "");
748 public void get(String src, String dst) throws SftpException{
749 get(src, dst, null, OVERWRITE);
751 public void get(String src, String dst,
752 SftpProgressMonitor monitor) throws SftpException{
753 get(src, dst, monitor, OVERWRITE);
755 public void get(String src, String dst,
756 SftpProgressMonitor monitor, int mode) throws SftpException{
757 // System.out.println("get: "+src+" "+dst);
759 src=remoteAbsolutePath(src);
760 dst=localAbsolutePath(dst);
763 Vector v=glob_remote(src);
766 throw new SftpException(SSH_FX_NO_SUCH_FILE, "No such file");
769 File dstFile=new File(dst);
770 boolean isDstDir=dstFile.isDirectory();
771 StringBuffer dstsb=null;
773 if(!dst.endsWith(file_separator)){
776 dstsb=new StringBuffer(dst);
779 throw new SftpException(SSH_FX_FAILURE,
780 "Copying multiple files, but destination is missing or a file.");
783 for(int j=0; j<vsize; j++){
784 String _src=(String)(v.elementAt(j));
785 SftpATTRS attr=_stat(_src);
787 throw new SftpException(SSH_FX_FAILURE,
788 "not supported to get directory "+_src);
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());
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);
810 if(size_of_dst==size_of_src){
816 monitor.init(SftpProgressMonitor.GET, _src, _dst, attr.getSize());
818 monitor.count(new File(_dst).length());
822 FileOutputStream fos=null;
825 fos=new FileOutputStream(_dst);
828 fos=new FileOutputStream(_dst, true); // append
830 // System.err.println("_get: "+_src+", "+_dst);
831 _get(_src, fos, monitor, mode, new File(_dst).length());
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, "");
847 public void get(String src, OutputStream dst) throws SftpException{
848 get(src, dst, null, OVERWRITE, 0);
850 public void get(String src, OutputStream dst,
851 SftpProgressMonitor monitor) throws SftpException{
852 get(src, dst, monitor, OVERWRITE, 0);
854 public void get(String src, OutputStream dst,
855 SftpProgressMonitor monitor, int mode, long skip) throws SftpException{
856 //System.err.println("get: "+src+", "+dst);
858 src=remoteAbsolutePath(src);
863 SftpATTRS attr=_stat(src);
864 monitor.init(SftpProgressMonitor.GET, src, "??", attr.getSize());
869 _get(src, dst, monitor, mode, skip);
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, "");
879 private void _get(String src, OutputStream dst,
880 SftpProgressMonitor monitor, int mode, long skip) throws SftpException{
881 //System.err.println("_get: "+src+", "+dst);
883 byte[] srcb=Util.str2byte(src, fEncoding);
887 Header header=new Header();
888 header=header(buf, header);
889 int length=header.length;
890 int type=header.type;
894 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
895 throw new SftpException(SSH_FX_FAILURE, "");
898 if(type==SSH_FXP_STATUS){
900 throwStatusError(buf, i);
903 byte[] handle=buf.getString(); // filename
914 request_len=buf.buffer.length-13;
915 if(server_version==0){ request_len=1024; }
916 sendREAD(handle, offset, request_len);
918 header=header(buf, header);
919 length=header.length;
922 if(type==SSH_FXP_STATUS){
928 throwStatusError(buf, i);
931 if(type!=SSH_FXP_DATA){
936 fill(buf.buffer, 0, 4); length-=4;
937 int i=buf.getInt(); // length of data
942 if(bar>buf.buffer.length){
943 bar=buf.buffer.length;
945 i=io_in.read(buf.buffer, 0, bar);
950 dst.write(buf.buffer, 0, data_len);
956 if(!monitor.count(data_len)){
958 i=io_in.read(buf.buffer,
960 (buf.buffer.length<foo?buf.buffer.length:foo));
969 //System.err.println("length: "+length); // length should be 0
973 if(monitor!=null)monitor.end();
974 _sendCLOSE(handle, header);
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, "");
984 public InputStream get(String src) throws SftpException{
985 return get(src, null, 0L);
987 public InputStream get(String src, SftpProgressMonitor monitor) throws SftpException{
988 return get(src, monitor, 0L);
992 * @deprecated This method will be deleted in the future.
994 public InputStream get(String src, int mode) throws SftpException{
995 return get(src, null, 0L);
998 * @deprecated This method will be deleted in the future.
1000 public InputStream get(String src, final SftpProgressMonitor monitor, final int mode) throws SftpException{
1001 return get(src, monitor, 0L);
1003 public InputStream get(String src, final SftpProgressMonitor monitor, final long skip) throws SftpException{
1004 src=remoteAbsolutePath(src);
1008 byte[] srcb=Util.str2byte(src, fEncoding);
1010 SftpATTRS attr=_stat(srcb);
1012 monitor.init(SftpProgressMonitor.GET, src, "??", attr.getSize());
1017 Header header=new Header();
1018 header=header(buf, header);
1019 int length=header.length;
1020 int type=header.type;
1024 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
1025 throw new SftpException(SSH_FX_FAILURE, "");
1027 if(type==SSH_FXP_STATUS){
1029 throwStatusError(buf, i);
1032 final byte[] handle=buf.getString(); // handle
1034 java.io.InputStream in=new java.io.InputStream(){
1036 boolean closed=false;
1038 byte[] _data=new byte[1];
1039 byte[] rest_byte=new byte[1024];
1040 Header header=new Header();
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; }
1047 return _data[0]&0xff;
1050 public int read(byte[] d) throws java.io.IOException{
1051 if(closed)return -1;
1052 return read(d, 0, d.length);
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();
1060 if(len==0){ return 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);
1072 if(!monitor.count(foo)){
1082 if(buf.buffer.length-13<len){
1083 len=buf.buffer.length-13;
1085 if(server_version==0 && len>1024){
1089 try{sendREAD(handle, offset, len);}
1090 catch(Exception e){ throw new IOException("error"); }
1092 header=header(buf, header);
1093 rest_length=header.length;
1094 int type=header.type;
1097 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_DATA){
1098 throw new IOException("error");
1100 if(type==SSH_FXP_STATUS){
1101 fill(buf, rest_length);
1108 //throwStatusError(buf, i);
1109 throw new IOException("error");
1112 fill(buf.buffer, 0, 4);
1113 int i=buf.getInt(); rest_length-=4;
1115 offset+=rest_length;
1118 int bar=rest_length;
1122 i=io_in.read(d, s, bar);
1129 if(rest_byte.length<rest_length){
1130 rest_byte=new byte[rest_length];
1133 int _len=rest_length;
1136 j=io_in.read(rest_byte, _s, _len);
1144 if(!monitor.count(i)){
1154 public void close() throws IOException{
1157 if(monitor!=null)monitor.end();
1158 try{_sendCLOSE(handle, header);}
1159 catch(Exception e){throw new IOException("error");}
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, "");
1172 public java.util.Vector ls(String path) throws SftpException{
1173 //System.out.println("ls: "+path);
1175 path=remoteAbsolutePath(path);
1176 byte[] pattern=null;
1177 java.util.Vector v=new java.util.Vector();
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);
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);
1189 if(pattern_has_wildcard){
1190 pattern=_pattern_utf8[0];
1193 String upath=Util.unquote(path);
1194 //SftpATTRS attr=_lstat(upath);
1195 SftpATTRS attr=_stat(upath);
1202 // If we can generage longname by ourself,
1203 // we don't have to use openDIR.
1204 String filename=Util.unquote(_pattern);
1206 v.addElement(new LsEntry(filename, longname, attr));
1210 if(fEncoding_is_utf8){
1211 pattern=_pattern_utf8[0];
1212 pattern=Util.unquote(pattern);
1215 _pattern=Util.unquote(_pattern);
1216 pattern=Util.str2byte(_pattern, fEncoding);
1222 sendOPENDIR(Util.str2byte(dir, fEncoding));
1224 Header header=new Header();
1225 header=header(buf, header);
1226 int length=header.length;
1227 int type=header.type;
1231 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
1232 throw new SftpException(SSH_FX_FAILURE, "");
1234 if(type==SSH_FXP_STATUS){
1236 throwStatusError(buf, i);
1239 byte[] handle=buf.getString(); // handle
1242 sendREADDIR(handle);
1244 header=header(buf, header);
1245 length=header.length;
1247 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
1248 throw new SftpException(SSH_FX_FAILURE, "");
1250 if(type==SSH_FXP_STATUS){
1255 throwStatusError(buf, i);
1259 fill(buf.buffer, 0, 4); length-=4;
1260 int count=buf.getInt();
1269 int j=(buf.buffer.length>(buf.index+length)) ?
1271 (buf.buffer.length-buf.index);
1272 int i=fill(buf.buffer, buf.index, j);
1276 byte[] filename=buf.getString();
1277 byte[] longname=null;
1278 if(server_version<=3){
1279 longname=buf.getString();
1281 SftpATTRS attrs=SftpATTRS.getATTR(buf);
1288 else if(!pattern_has_wildcard){
1289 find=Util.array_equals(pattern, filename);
1292 byte[] _filename=filename;
1293 if(!fEncoding_is_utf8){
1294 f=Util.byte2str(_filename, fEncoding);
1295 _filename=Util.str2byte(f, UTF8);
1297 find=Util.glob(pattern, _filename);
1302 f=Util.byte2str(filename, fEncoding);
1306 // TODO: we need to generate long name from attrs
1307 // for the sftp protocol 4(and later).
1308 l=attrs.toString()+" "+f;
1311 l=Util.byte2str(longname, fEncoding);
1313 v.addElement(new LsEntry(f, l, attrs));
1319 _sendCLOSE(handle, header);
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();
1329 if(!dir.endsWith("/")){
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, "");
1347 public String readlink(String path) throws SftpException{
1350 if(server_version<3){
1351 throw new SftpException(SSH_FX_OP_UNSUPPORTED,
1352 "The remote sshd is too old to support symlink operation.");
1355 path=remoteAbsolutePath(path);
1357 path=isUnique(path);
1359 sendREADLINK(Util.str2byte(path, fEncoding));
1361 Header header=new Header();
1362 header=header(buf, header);
1363 int length=header.length;
1364 int type=header.type;
1368 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
1369 throw new SftpException(SSH_FX_FAILURE, "");
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();
1379 SftpATTRS.getATTR(buf);
1381 return Util.byte2str(filename, fEncoding);
1385 throwStatusError(buf, i);
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, "");
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.");
1402 oldpath=remoteAbsolutePath(oldpath);
1403 newpath=remoteAbsolutePath(newpath);
1405 oldpath=isUnique(oldpath);
1407 if(isPattern(newpath)){
1408 throw new SftpException(SSH_FX_FAILURE, newpath);
1410 newpath=Util.unquote(newpath);
1412 sendSYMLINK(Util.str2byte(oldpath, fEncoding),
1413 Util.str2byte(newpath, fEncoding));
1415 Header header=new Header();
1416 header=header(buf, header);
1417 int length=header.length;
1418 int type=header.type;
1422 if(type!=SSH_FXP_STATUS){
1423 throw new SftpException(SSH_FX_FAILURE, "");
1427 if(i==SSH_FX_OK) return;
1428 throwStatusError(buf, i);
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, "");
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.");
1445 oldpath=remoteAbsolutePath(oldpath);
1446 newpath=remoteAbsolutePath(newpath);
1448 oldpath=isUnique(oldpath);
1450 Vector v=glob_remote(newpath);
1453 throw new SftpException(SSH_FX_FAILURE, v.toString());
1456 newpath=(String)(v.elementAt(0));
1459 if(isPattern(newpath))
1460 throw new SftpException(SSH_FX_FAILURE, newpath);
1461 newpath=Util.unquote(newpath);
1464 sendRENAME(Util.str2byte(oldpath, fEncoding),
1465 Util.str2byte(newpath, fEncoding));
1467 Header header=new Header();
1468 header=header(buf, header);
1469 int length=header.length;
1470 int type=header.type;
1474 if(type!=SSH_FXP_STATUS){
1475 throw new SftpException(SSH_FX_FAILURE, "");
1479 if(i==SSH_FX_OK) return;
1480 throwStatusError(buf, i);
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, "");
1489 public void rm(String path) throws SftpException{
1491 path=remoteAbsolutePath(path);
1493 Vector v=glob_remote(path);
1496 Header header=new Header();
1498 for(int j=0; j<vsize; j++){
1499 path=(String)(v.elementAt(j));
1500 sendREMOVE(Util.str2byte(path, fEncoding));
1502 header=header(buf, header);
1503 int length=header.length;
1504 int type=header.type;
1508 if(type!=SSH_FXP_STATUS){
1509 throw new SftpException(SSH_FX_FAILURE, "");
1513 throwStatusError(buf, i);
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, "");
1525 private boolean isRemoteDir(String path){
1527 sendSTAT(Util.str2byte(path, fEncoding));
1529 Header header=new Header();
1530 header=header(buf, header);
1531 int length=header.length;
1532 int type=header.type;
1536 if(type!=SSH_FXP_ATTRS){
1539 SftpATTRS attr=SftpATTRS.getATTR(buf);
1540 return attr.isDir();
1542 catch(Exception e){}
1546 public void chgrp(int gid, String path) throws SftpException{
1548 path=remoteAbsolutePath(path);
1550 Vector v=glob_remote(path);
1552 for(int j=0; j<vsize; j++){
1553 path=(String)(v.elementAt(j));
1555 SftpATTRS attr=_stat(path);
1558 attr.setUIDGID(attr.uid, gid);
1559 _setStat(path, attr);
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, "");
1570 public void chown(int uid, String path) throws SftpException{
1572 path=remoteAbsolutePath(path);
1574 Vector v=glob_remote(path);
1576 for(int j=0; j<vsize; j++){
1577 path=(String)(v.elementAt(j));
1579 SftpATTRS attr=_stat(path);
1582 attr.setUIDGID(uid, attr.gid);
1583 _setStat(path, attr);
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, "");
1594 public void chmod(int permissions, String path) throws SftpException{
1596 path=remoteAbsolutePath(path);
1598 Vector v=glob_remote(path);
1600 for(int j=0; j<vsize; j++){
1601 path=(String)(v.elementAt(j));
1603 SftpATTRS attr=_stat(path);
1606 attr.setPERMISSIONS(permissions);
1607 _setStat(path, attr);
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, "");
1618 public void setMtime(String path, int mtime) throws SftpException{
1620 path=remoteAbsolutePath(path);
1622 Vector v=glob_remote(path);
1624 for(int j=0; j<vsize; j++){
1625 path=(String)(v.elementAt(j));
1627 SftpATTRS attr=_stat(path);
1630 attr.setACMODTIME(attr.getATime(), mtime);
1631 _setStat(path, attr);
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, "");
1642 public void rmdir(String path) throws SftpException{
1644 path=remoteAbsolutePath(path);
1646 Vector v=glob_remote(path);
1649 Header header=new Header();
1651 for(int j=0; j<vsize; j++){
1652 path=(String)(v.elementAt(j));
1653 sendRMDIR(Util.str2byte(path, fEncoding));
1655 header=header(buf, header);
1656 int length=header.length;
1657 int type=header.type;
1661 if(type!=SSH_FXP_STATUS){
1662 throw new SftpException(SSH_FX_FAILURE, "");
1667 throwStatusError(buf, i);
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, "");
1679 public void mkdir(String path) throws SftpException{
1681 path=remoteAbsolutePath(path);
1683 sendMKDIR(Util.str2byte(path, fEncoding), null);
1685 Header header=new Header();
1686 header=header(buf, header);
1687 int length=header.length;
1688 int type=header.type;
1692 if(type!=SSH_FXP_STATUS){
1693 throw new SftpException(SSH_FX_FAILURE, "");
1697 if(i==SSH_FX_OK) return;
1698 throwStatusError(buf, i);
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, "");
1708 public SftpATTRS stat(String path) throws SftpException{
1710 path=remoteAbsolutePath(path);
1712 path=isUnique(path);
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, "");
1725 private SftpATTRS _stat(byte[] path) throws SftpException{
1730 Header header=new Header();
1731 header=header(buf, header);
1732 int length=header.length;
1733 int type=header.type;
1737 if(type!=SSH_FXP_ATTRS){
1738 if(type==SSH_FXP_STATUS){
1740 throwStatusError(buf, i);
1742 throw new SftpException(SSH_FX_FAILURE, "");
1744 SftpATTRS attr=SftpATTRS.getATTR(buf);
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, "");
1756 private SftpATTRS _stat(String path) throws SftpException{
1757 return _stat(Util.str2byte(path, fEncoding));
1760 public SftpATTRS lstat(String path) throws SftpException{
1762 path=remoteAbsolutePath(path);
1764 path=isUnique(path);
1766 return _lstat(path);
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, "");
1776 private SftpATTRS _lstat(String path) throws SftpException{
1778 sendLSTAT(Util.str2byte(path, fEncoding));
1780 Header header=new Header();
1781 header=header(buf, header);
1782 int length=header.length;
1783 int type=header.type;
1787 if(type!=SSH_FXP_ATTRS){
1788 if(type==SSH_FXP_STATUS){
1790 throwStatusError(buf, i);
1792 throw new SftpException(SSH_FX_FAILURE, "");
1794 SftpATTRS attr=SftpATTRS.getATTR(buf);
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, "");
1805 private byte[] _realpath(String path) throws SftpException, IOException, Exception{
1806 sendREALPATH(Util.str2byte(path, fEncoding));
1808 Header header=new Header();
1809 header=header(buf, header);
1810 int length=header.length;
1811 int type=header.type;
1815 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
1816 throw new SftpException(SSH_FX_FAILURE, "");
1819 if(type==SSH_FXP_STATUS){
1821 throwStatusError(buf, i);
1823 i=buf.getInt(); // count
1827 str=buf.getString(); // absolute path;
1828 if(server_version<=3){
1829 byte[] lname=buf.getString(); // long filename
1831 SftpATTRS attr=SftpATTRS.getATTR(buf); // dummy attribute
1836 public void setStat(String path, SftpATTRS attr) throws SftpException{
1838 path=remoteAbsolutePath(path);
1840 Vector v=glob_remote(path);
1842 for(int j=0; j<vsize; j++){
1843 path=(String)(v.elementAt(j));
1844 _setStat(path, attr);
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, "");
1854 private void _setStat(String path, SftpATTRS attr) throws SftpException{
1856 sendSETSTAT(Util.str2byte(path, fEncoding), attr);
1858 Header header=new Header();
1859 header=header(buf, header);
1860 int length=header.length;
1861 int type=header.type;
1865 if(type!=SSH_FXP_STATUS){
1866 throw new SftpException(SSH_FX_FAILURE, "");
1870 throwStatusError(buf, i);
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, "");
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 {
1887 byte[] _home=_realpath("");
1888 home=Util.byte2str(_home, fEncoding);
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, "");
1900 private String getCwd() throws SftpException{
1906 private void setCwd(String cwd){
1910 private void read(byte[] buf, int s, int l) throws IOException, SftpException{
1913 i=io_in.read(buf, s, l);
1915 throw new SftpException(SSH_FX_FAILURE, "");
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;
1927 ackid[0]=header.rid;
1931 if(type!=SSH_FXP_STATUS){
1932 throw new SftpException(SSH_FX_FAILURE, "");
1936 throwStatusError(buf, i);
1940 private boolean _sendCLOSE(byte[] handle, Header header) throws Exception{
1942 return checkStatus(null, header);
1945 private void sendINIT() throws Exception{
1947 putHEAD(SSH_FXP_INIT, 5);
1948 buf.putInt(3); // version 3
1949 getSession().write(packet, this, 5+4);
1952 private void sendREALPATH(byte[] path) throws Exception{
1953 sendPacketPath(SSH_FXP_REALPATH, path);
1955 private void sendSTAT(byte[] path) throws Exception{
1956 sendPacketPath(SSH_FXP_STAT, path);
1958 private void sendLSTAT(byte[] path) throws Exception{
1959 sendPacketPath(SSH_FXP_LSTAT, path);
1961 private void sendFSTAT(byte[] handle) throws Exception{
1962 sendPacketPath(SSH_FXP_FSTAT, handle);
1964 private void sendSETSTAT(byte[] path, SftpATTRS attr) throws Exception{
1966 putHEAD(SSH_FXP_SETSTAT, 9+path.length+attr.length());
1968 buf.putString(path); // path
1970 getSession().write(packet, this, 9+path.length+attr.length()+4);
1972 private void sendREMOVE(byte[] path) throws Exception{
1973 sendPacketPath(SSH_FXP_REMOVE, path);
1975 private void sendMKDIR(byte[] path, SftpATTRS attr) throws Exception{
1977 putHEAD(SSH_FXP_MKDIR, 9+path.length+(attr!=null?attr.length():4));
1979 buf.putString(path); // path
1980 if(attr!=null) attr.dump(buf);
1982 getSession().write(packet, this, 9+path.length+(attr!=null?attr.length():4)+4);
1984 private void sendRMDIR(byte[] path) throws Exception{
1985 sendPacketPath(SSH_FXP_RMDIR, path);
1987 private void sendSYMLINK(byte[] p1, byte[] p2) throws Exception{
1988 sendPacketPath(SSH_FXP_SYMLINK, p1, p2);
1990 private void sendREADLINK(byte[] path) throws Exception{
1991 sendPacketPath(SSH_FXP_READLINK, path);
1993 private void sendOPENDIR(byte[] path) throws Exception{
1994 sendPacketPath(SSH_FXP_OPENDIR, path);
1996 private void sendREADDIR(byte[] path) throws Exception{
1997 sendPacketPath(SSH_FXP_READDIR, path);
1999 private void sendRENAME(byte[] p1, byte[] p2) throws Exception{
2000 sendPacketPath(SSH_FXP_RENAME, p1, p2);
2002 private void sendCLOSE(byte[] path) throws Exception{
2003 sendPacketPath(SSH_FXP_CLOSE, path);
2005 private void sendOPENR(byte[] path) throws Exception{
2006 sendOPEN(path, SSH_FXF_READ);
2008 private void sendOPENW(byte[] path) throws Exception{
2009 sendOPEN(path, SSH_FXF_WRITE|SSH_FXF_CREAT|SSH_FXF_TRUNC);
2011 private void sendOPENA(byte[] path) throws Exception{
2012 sendOPEN(path, SSH_FXF_WRITE|/*SSH_FXF_APPEND|*/SSH_FXF_CREAT);
2014 private void sendOPEN(byte[] path, int mode) throws Exception{
2016 putHEAD(SSH_FXP_OPEN, 17+path.length);
2018 buf.putString(path);
2020 buf.putInt(0); // attrs
2021 getSession().write(packet, this, 17+path.length+4);
2023 private void sendPacketPath(byte fxp, byte[] path) throws Exception{
2025 putHEAD(fxp, 9+path.length);
2027 buf.putString(path); // path
2028 getSession().write(packet, this, 9+path.length+4);
2030 private void sendPacketPath(byte fxp, byte[] p1, byte[] p2) throws Exception{
2032 putHEAD(fxp, 13+p1.length+p2.length);
2036 getSession().write(packet, this, 13+p1.length+p2.length+4);
2039 private int sendWRITE(byte[] handle, long offset,
2040 byte[] data, int start, int length) throws Exception{
2043 if(buf.buffer.length<buf.index+13+21+handle.length+length
2044 +32 +20 // padding and mac
2046 _length=buf.buffer.length-(buf.index+13+21+handle.length
2047 +32 +20 // padding and mac
2049 //System.err.println("_length="+_length+" length="+length);
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
2060 buf.putInt(_length);
2063 getSession().write(packet, this, 21+handle.length+_length+4);
2067 private void sendREAD(byte[] handle, long offset, int length) throws Exception{
2069 putHEAD(SSH_FXP_READ, 21+handle.length);
2071 buf.putString(handle);
2072 buf.putLong(offset);
2074 getSession().write(packet, this, 21+handle.length+4);
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);
2085 private Vector glob_remote(String _path) throws Exception{
2086 Vector v=new Vector();
2089 int foo=_path.lastIndexOf('/');
2090 if(foo<0){ // it is not absolute path.
2091 v.addElement(Util.unquote(_path));
2095 String dir=_path.substring(0, ((foo==0)?1:foo));
2096 String _pattern=_path.substring(foo+1);
2098 dir=Util.unquote(dir);
2100 byte[] pattern=null;
2101 byte[][] _pattern_utf8=new byte[1][];
2102 boolean pattern_has_wildcard=isPattern(_pattern, _pattern_utf8);
2104 if(!pattern_has_wildcard){
2105 if(!dir.equals("/"))
2107 v.addElement(dir+Util.unquote(_pattern));
2111 pattern=_pattern_utf8[0];
2113 sendOPENDIR(Util.str2byte(dir, fEncoding));
2115 Header header=new Header();
2116 header=header(buf, header);
2117 int length=header.length;
2118 int type=header.type;
2122 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_HANDLE){
2123 throw new SftpException(SSH_FX_FAILURE, "");
2125 if(type==SSH_FXP_STATUS){
2127 throwStatusError(buf, i);
2130 byte[] handle=buf.getString(); // filename
2131 String pdir=null; // parent directory
2134 sendREADDIR(handle);
2135 header=header(buf, header);
2136 length=header.length;
2139 if(type!=SSH_FXP_STATUS && type!=SSH_FXP_NAME){
2140 throw new SftpException(SSH_FX_FAILURE, "");
2142 if(type==SSH_FXP_STATUS){
2148 fill(buf.buffer, 0, 4); length-=4;
2149 int count=buf.getInt();
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);
2165 byte[] filename=buf.getString();
2166 //System.err.println("filename: "+new String(filename));
2167 if(server_version<=3){
2168 str=buf.getString(); // longname
2170 SftpATTRS attrs=SftpATTRS.getATTR(buf);
2172 byte[] _filename=filename;
2174 boolean found=false;
2176 if(!fEncoding_is_utf8){
2177 f=Util.byte2str(filename, fEncoding);
2178 _filename=Util.str2byte(f, UTF8);
2180 found=Util.glob(pattern, _filename);
2184 f=Util.byte2str(filename, fEncoding);
2188 if(!pdir.endsWith("/")){
2192 v.addElement(pdir+f);
2197 if(_sendCLOSE(handle, header))
2202 private boolean isPattern(byte[] path){
2203 int i=path.length-1;
2205 if(path[i]=='*' || path[i]=='?'){
2206 if(i>0 && path[i-1]=='\\'){
2208 if(i>0 && path[i-1]=='\\'){ // \\* or \\?
2218 // System.err.println("isPattern: ["+(new String(path))+"] "+(!(i<0)));
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;
2228 if(path[i]!='*' && path[i]!='?'){
2233 i>0 && path[i-1]=='\\'){
2235 if(i>0 && path[i-1]=='\\'){
2244 if(i<0){ v.addElement(fs_is_bs ? _path : Util.unquote(_path)); return v;}
2247 if(path[i]==file_separatorc ||
2248 (fs_is_bs && path[i]=='/')){ // On Windows, '/' is also the separator.
2254 if(i<0){ v.addElement(fs_is_bs ? _path : Util.unquote(_path)); return v;}
2257 if(i==0){dir=new byte[]{(byte)file_separatorc};}
2260 System.arraycopy(path, 0, dir, 0, i);
2263 byte[] pattern=new byte[path.length-i-1];
2264 System.arraycopy(path, i+1, pattern, 0, pattern.length);
2266 //System.err.println("dir: "+new String(dir)+" pattern: "+new String(pattern));
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]);
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));
2290 throw new SftpException(i, "Failure");
2294 private static boolean isLocalAbsolutePath(String path){
2295 return (new File(path)).isAbsolute();
2298 public void disconnect(){
2302 private boolean isPattern(String path, byte[][] utf8){
2303 byte[] _path=Util.str2byte(path, UTF8);
2306 return isPattern(_path);
2309 private boolean isPattern(String path){
2310 return isPattern(path, null);
2313 private void fill(Buffer buf, int len) throws IOException{
2315 fill(buf.buffer, 0, len);
2319 private int fill(byte[] buf, int s, int len) throws IOException{
2323 i=io_in.read(buf, s, len);
2325 throw new IOException("inputstream is closed");
2326 //return (s-foo)==0 ? i : s-foo;
2333 private void skip(long foo) throws IOException{
2335 long bar=io_in.skip(foo);
2347 private Header header(Buffer buf, Header header) throws IOException{
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();
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;
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;
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
2374 * @return the returned string is unquoted.
2376 private String isUnique(String path) throws SftpException, Exception{
2377 Vector v=glob_remote(path);
2379 throw new SftpException(SSH_FX_FAILURE, path+" is not unique: "+v.toString());
2381 return (String)(v.elementAt(0));
2384 public int getServerVersion() throws SftpException{
2386 throw new SftpException(SSH_FX_FAILURE, "The channel is not connected.");
2388 return server_version;
2391 public void setFilenameEncoding(String encoding) throws SftpException{
2392 int sversion=getServerVersion();
2394 !encoding.equals(UTF8)){
2395 throw new SftpException(SSH_FX_FAILURE,
2396 "The encoding can not be changed for this sftp server.");
2398 if(encoding.equals(UTF8)){
2402 fEncoding_is_utf8=fEncoding.equals(UTF8);
2405 public String getExtension(String key){
2406 if(extensions==null)
2408 return (String)extensions.get(key);
2411 public String realpath(String path) throws SftpException{
2413 byte[] _path=_realpath(remoteAbsolutePath(path));
2414 return Util.byte2str(_path, fEncoding);
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, "");
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);
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());
2444 throw new ClassCastException("a decendent of LsEntry must be given.");