0001: /* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
0002: /*
0003: Copyright (c) 2002-2008 ymnk, JCraft,Inc. All rights reserved.
0004:
0005: Redistribution and use in source and binary forms, with or without
0006: modification, are permitted provided that the following conditions are met:
0007:
0008: 1. Redistributions of source code must retain the above copyright notice,
0009: this list of conditions and the following disclaimer.
0010:
0011: 2. Redistributions in binary form must reproduce the above copyright
0012: notice, this list of conditions and the following disclaimer in
0013: the documentation and/or other materials provided with the distribution.
0014:
0015: 3. The names of the authors may not be used to endorse or promote products
0016: derived from this software without specific prior written permission.
0017:
0018: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
0019: INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
0020: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
0021: INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
0022: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0023: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
0024: OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0025: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0026: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0027: EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0028: */
0029:
0030: package com.jcraft.jsch;
0031:
0032: import java.io.*;
0033:
0034: import java.util.Vector;
0035:
0036: public class ChannelSftp extends ChannelSession {
0037:
0038: private static final byte SSH_FXP_INIT = 1;
0039: private static final byte SSH_FXP_VERSION = 2;
0040: private static final byte SSH_FXP_OPEN = 3;
0041: private static final byte SSH_FXP_CLOSE = 4;
0042: private static final byte SSH_FXP_READ = 5;
0043: private static final byte SSH_FXP_WRITE = 6;
0044: private static final byte SSH_FXP_LSTAT = 7;
0045: private static final byte SSH_FXP_FSTAT = 8;
0046: private static final byte SSH_FXP_SETSTAT = 9;
0047: private static final byte SSH_FXP_FSETSTAT = 10;
0048: private static final byte SSH_FXP_OPENDIR = 11;
0049: private static final byte SSH_FXP_READDIR = 12;
0050: private static final byte SSH_FXP_REMOVE = 13;
0051: private static final byte SSH_FXP_MKDIR = 14;
0052: private static final byte SSH_FXP_RMDIR = 15;
0053: private static final byte SSH_FXP_REALPATH = 16;
0054: private static final byte SSH_FXP_STAT = 17;
0055: private static final byte SSH_FXP_RENAME = 18;
0056: private static final byte SSH_FXP_READLINK = 19;
0057: private static final byte SSH_FXP_SYMLINK = 20;
0058: private static final byte SSH_FXP_STATUS = 101;
0059: private static final byte SSH_FXP_HANDLE = 102;
0060: private static final byte SSH_FXP_DATA = 103;
0061: private static final byte SSH_FXP_NAME = 104;
0062: private static final byte SSH_FXP_ATTRS = 105;
0063: private static final byte SSH_FXP_EXTENDED = (byte) 200;
0064: private static final byte SSH_FXP_EXTENDED_REPLY = (byte) 201;
0065:
0066: // pflags
0067: private static final int SSH_FXF_READ = 0x00000001;
0068: private static final int SSH_FXF_WRITE = 0x00000002;
0069: private static final int SSH_FXF_APPEND = 0x00000004;
0070: private static final int SSH_FXF_CREAT = 0x00000008;
0071: private static final int SSH_FXF_TRUNC = 0x00000010;
0072: private static final int SSH_FXF_EXCL = 0x00000020;
0073:
0074: private static final int SSH_FILEXFER_ATTR_SIZE = 0x00000001;
0075: private static final int SSH_FILEXFER_ATTR_UIDGID = 0x00000002;
0076: private static final int SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004;
0077: private static final int SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008;
0078: private static final int SSH_FILEXFER_ATTR_EXTENDED = 0x80000000;
0079:
0080: public static final int SSH_FX_OK = 0;
0081: public static final int SSH_FX_EOF = 1;
0082: public static final int SSH_FX_NO_SUCH_FILE = 2;
0083: public static final int SSH_FX_PERMISSION_DENIED = 3;
0084: public static final int SSH_FX_FAILURE = 4;
0085: public static final int SSH_FX_BAD_MESSAGE = 5;
0086: public static final int SSH_FX_NO_CONNECTION = 6;
0087: public static final int SSH_FX_CONNECTION_LOST = 7;
0088: public static final int SSH_FX_OP_UNSUPPORTED = 8;
0089: /*
0090: SSH_FX_OK
0091: Indicates successful completion of the operation.
0092: SSH_FX_EOF
0093: indicates end-of-file condition; for SSH_FX_READ it means that no
0094: more data is available in the file, and for SSH_FX_READDIR it
0095: indicates that no more files are contained in the directory.
0096: SSH_FX_NO_SUCH_FILE
0097: is returned when a reference is made to a file which should exist
0098: but doesn't.
0099: SSH_FX_PERMISSION_DENIED
0100: is returned when the authenticated user does not have sufficient
0101: permissions to perform the operation.
0102: SSH_FX_FAILURE
0103: is a generic catch-all error message; it should be returned if an
0104: error occurs for which there is no more specific error code
0105: defined.
0106: SSH_FX_BAD_MESSAGE
0107: may be returned if a badly formatted packet or protocol
0108: incompatibility is detected.
0109: SSH_FX_NO_CONNECTION
0110: is a pseudo-error which indicates that the client has no
0111: connection to the server (it can only be generated locally by the
0112: client, and MUST NOT be returned by servers).
0113: SSH_FX_CONNECTION_LOST
0114: is a pseudo-error which indicates that the connection to the
0115: server has been lost (it can only be generated locally by the
0116: client, and MUST NOT be returned by servers).
0117: SSH_FX_OP_UNSUPPORTED
0118: indicates that an attempt was made to perform an operation which
0119: is not supported for the server (it may be generated locally by
0120: the client if e.g. the version number exchange indicates that a
0121: required feature is not supported by the server, or it may be
0122: returned by the server if the server does not implement an
0123: operation).
0124: */
0125: private static final int MAX_MSG_LENGTH = 256 * 1024;
0126:
0127: public static final int OVERWRITE = 0;
0128: public static final int RESUME = 1;
0129: public static final int APPEND = 2;
0130:
0131: private boolean interactive = false;
0132: private int seq = 1;
0133: private int[] ackid = new int[1];
0134: private Buffer buf;
0135: private Packet packet = new Packet(buf);
0136:
0137: private int client_version = 3;
0138: private int server_version = 3;
0139: private String version = String.valueOf(client_version);
0140:
0141: private java.util.Hashtable extensions = null;
0142:
0143: /*
0144: 10. Changes from previous protocol versions
0145: The SSH File Transfer Protocol has changed over time, before it's
0146: standardization. The following is a description of the incompatible
0147: changes between different versions.
0148: 10.1 Changes between versions 3 and 2
0149: o The SSH_FXP_READLINK and SSH_FXP_SYMLINK messages were added.
0150: o The SSH_FXP_EXTENDED and SSH_FXP_EXTENDED_REPLY messages were added.
0151: o The SSH_FXP_STATUS message was changed to include fields `error
0152: message' and `language tag'.
0153: 10.2 Changes between versions 2 and 1
0154: o The SSH_FXP_RENAME message was added.
0155: 10.3 Changes between versions 1 and 0
0156: o Implementation changes, no actual protocol changes.
0157: */
0158:
0159: private static final String file_separator = java.io.File.separator;
0160: private static final char file_separatorc = java.io.File.separatorChar;
0161: private static boolean fs_is_bs = (byte) java.io.File.separatorChar == '\\';
0162:
0163: private String cwd;
0164: private String home;
0165: private String lcwd;
0166:
0167: private static final String UTF8 = "UTF-8";
0168: private String fEncoding = UTF8;
0169: private boolean fEncoding_is_utf8 = true;
0170:
0171: public void init() {
0172: }
0173:
0174: public void start() throws JSchException {
0175: try {
0176:
0177: PipedOutputStream pos = new PipedOutputStream();
0178: io.setOutputStream(pos);
0179: PipedInputStream pis = new MyPipedInputStream(pos,
0180: 32 * 1024);
0181: io.setInputStream(pis);
0182:
0183: Request request = new RequestSftp();
0184: request.request(session, this );
0185:
0186: /*
0187: System.err.println("lmpsize: "+lmpsize);
0188: System.err.println("lwsize: "+lwsize);
0189: System.err.println("rmpsize: "+rmpsize);
0190: System.err.println("rwsize: "+rwsize);
0191: */
0192:
0193: buf = new Buffer(rmpsize);
0194: packet = new Packet(buf);
0195: int i = 0;
0196: int length;
0197: int type;
0198: byte[] str;
0199:
0200: // send SSH_FXP_INIT
0201: sendINIT();
0202:
0203: // receive SSH_FXP_VERSION
0204: Header header = new Header();
0205: header = header(buf, header);
0206: length = header.length;
0207: if (length > MAX_MSG_LENGTH) {
0208: throw new SftpException(SSH_FX_FAILURE,
0209: "Received message is too long: " + length);
0210: }
0211: type = header.type; // 2 -> SSH_FXP_VERSION
0212: server_version = header.rid;
0213: //System.err.println("SFTP protocol server-version="+server_version);
0214: if (length > 0) {
0215: extensions = new java.util.Hashtable();
0216: // extension data
0217: fill(buf, length);
0218: byte[] extension_name = null;
0219: byte[] extension_data = null;
0220: while (length > 0) {
0221: extension_name = buf.getString();
0222: length -= (4 + extension_name.length);
0223: extension_data = buf.getString();
0224: length -= (4 + extension_data.length);
0225: extensions.put(new String(extension_name),
0226: new String(extension_data));
0227: }
0228: }
0229:
0230: lcwd = new File(".").getCanonicalPath();
0231: } catch (Exception e) {
0232: //System.err.println(e);
0233: if (e instanceof JSchException)
0234: throw (JSchException) e;
0235: if (e instanceof Throwable)
0236: throw new JSchException(e.toString(), (Throwable) e);
0237: throw new JSchException(e.toString());
0238: }
0239: }
0240:
0241: public void quit() {
0242: disconnect();
0243: }
0244:
0245: public void exit() {
0246: disconnect();
0247: }
0248:
0249: public void lcd(String path) throws SftpException {
0250: path = localAbsolutePath(path);
0251: if ((new File(path)).isDirectory()) {
0252: try {
0253: path = (new File(path)).getCanonicalPath();
0254: } catch (Exception e) {
0255: }
0256: lcwd = path;
0257: return;
0258: }
0259: throw new SftpException(SSH_FX_NO_SUCH_FILE,
0260: "No such directory");
0261: }
0262:
0263: public void cd(String path) throws SftpException {
0264: try {
0265: path = remoteAbsolutePath(path);
0266:
0267: path = isUnique(path);
0268:
0269: byte[] str = _realpath(path);
0270: SftpATTRS attr = _stat(str);
0271:
0272: if ((attr.getFlags() & SftpATTRS.SSH_FILEXFER_ATTR_PERMISSIONS) == 0) {
0273: throw new SftpException(SSH_FX_FAILURE,
0274: "Can't change directory: " + path);
0275: }
0276: if (!attr.isDir()) {
0277: throw new SftpException(SSH_FX_FAILURE,
0278: "Can't change directory: " + path);
0279: }
0280:
0281: setCwd(Util.byte2str(str, fEncoding));
0282: } catch (Exception e) {
0283: if (e instanceof SftpException)
0284: throw (SftpException) e;
0285: if (e instanceof Throwable)
0286: throw new SftpException(SSH_FX_FAILURE, "",
0287: (Throwable) e);
0288: throw new SftpException(SSH_FX_FAILURE, "");
0289: }
0290: }
0291:
0292: public void put(String src, String dst) throws SftpException {
0293: put(src, dst, null, OVERWRITE);
0294: }
0295:
0296: public void put(String src, String dst, int mode)
0297: throws SftpException {
0298: put(src, dst, null, mode);
0299: }
0300:
0301: public void put(String src, String dst, SftpProgressMonitor monitor)
0302: throws SftpException {
0303: put(src, dst, monitor, OVERWRITE);
0304: }
0305:
0306: public void put(String src, String dst,
0307: SftpProgressMonitor monitor, int mode) throws SftpException {
0308: src = localAbsolutePath(src);
0309: dst = remoteAbsolutePath(dst);
0310:
0311: //System.err.println("src: "+src+", "+dst);
0312: try {
0313:
0314: Vector v = glob_remote(dst);
0315: int vsize = v.size();
0316: if (vsize != 1) {
0317: if (vsize == 0) {
0318: if (isPattern(dst))
0319: throw new SftpException(SSH_FX_FAILURE, dst);
0320: else
0321: dst = Util.unquote(dst);
0322: }
0323: throw new SftpException(SSH_FX_FAILURE, v.toString());
0324: } else {
0325: dst = (String) (v.elementAt(0));
0326: }
0327:
0328: boolean isRemoteDir = isRemoteDir(dst);
0329:
0330: v = glob_local(src);
0331: vsize = v.size();
0332:
0333: StringBuffer dstsb = null;
0334: if (isRemoteDir) {
0335: if (!dst.endsWith("/")) {
0336: dst += "/";
0337: }
0338: dstsb = new StringBuffer(dst);
0339: } else if (vsize > 1) {
0340: throw new SftpException(SSH_FX_FAILURE,
0341: "Copying multiple files, but the destination is missing or a file.");
0342: }
0343:
0344: for (int j = 0; j < vsize; j++) {
0345: String _src = (String) (v.elementAt(j));
0346: String _dst = null;
0347: if (isRemoteDir) {
0348: int i = _src.lastIndexOf(file_separatorc);
0349: if (fs_is_bs) {
0350: int ii = _src.lastIndexOf('/');
0351: if (ii != -1 && ii > i)
0352: i = ii;
0353: }
0354: if (i == -1)
0355: dstsb.append(_src);
0356: else
0357: dstsb.append(_src.substring(i + 1));
0358: _dst = dstsb.toString();
0359: dstsb.delete(dst.length(), _dst.length());
0360: } else {
0361: _dst = dst;
0362: }
0363: //System.err.println("_dst "+_dst);
0364:
0365: long size_of_dst = 0;
0366: if (mode == RESUME) {
0367: try {
0368: SftpATTRS attr = _stat(_dst);
0369: size_of_dst = attr.getSize();
0370: } catch (Exception eee) {
0371: //System.err.println(eee);
0372: }
0373: long size_of_src = new File(_src).length();
0374: if (size_of_src < size_of_dst) {
0375: throw new SftpException(SSH_FX_FAILURE,
0376: "failed to resume for " + _dst);
0377: }
0378: if (size_of_src == size_of_dst) {
0379: return;
0380: }
0381: }
0382:
0383: if (monitor != null) {
0384: monitor.init(SftpProgressMonitor.PUT, _src, _dst,
0385: (new File(_src)).length());
0386: if (mode == RESUME) {
0387: monitor.count(size_of_dst);
0388: }
0389: }
0390: FileInputStream fis = null;
0391: try {
0392: fis = new FileInputStream(_src);
0393: _put(fis, _dst, monitor, mode);
0394: } finally {
0395: if (fis != null) {
0396: // try{
0397: fis.close();
0398: // }catch(Exception ee){};
0399: }
0400: }
0401: }
0402: } catch (Exception e) {
0403: if (e instanceof SftpException)
0404: throw (SftpException) e;
0405: if (e instanceof Throwable)
0406: throw new SftpException(SSH_FX_FAILURE, e.toString(),
0407: (Throwable) e);
0408: throw new SftpException(SSH_FX_FAILURE, e.toString());
0409: }
0410: }
0411:
0412: public void put(InputStream src, String dst) throws SftpException {
0413: put(src, dst, null, OVERWRITE);
0414: }
0415:
0416: public void put(InputStream src, String dst, int mode)
0417: throws SftpException {
0418: put(src, dst, null, mode);
0419: }
0420:
0421: public void put(InputStream src, String dst,
0422: SftpProgressMonitor monitor) throws SftpException {
0423: put(src, dst, monitor, OVERWRITE);
0424: }
0425:
0426: public void put(InputStream src, String dst,
0427: SftpProgressMonitor monitor, int mode) throws SftpException {
0428: try {
0429: dst = remoteAbsolutePath(dst);
0430:
0431: Vector v = glob_remote(dst);
0432: int vsize = v.size();
0433: if (vsize != 1) {
0434: if (vsize == 0) {
0435: if (isPattern(dst))
0436: throw new SftpException(SSH_FX_FAILURE, dst);
0437: else
0438: dst = Util.unquote(dst);
0439: }
0440: throw new SftpException(SSH_FX_FAILURE, v.toString());
0441: } else {
0442: dst = (String) (v.elementAt(0));
0443: }
0444:
0445: if (isRemoteDir(dst)) {
0446: throw new SftpException(SSH_FX_FAILURE, dst
0447: + " is a directory");
0448: }
0449:
0450: _put(src, dst, monitor, mode);
0451: } catch (Exception e) {
0452: if (e instanceof SftpException)
0453: throw (SftpException) e;
0454: if (e instanceof Throwable)
0455: throw new SftpException(SSH_FX_FAILURE, e.toString(),
0456: (Throwable) e);
0457: throw new SftpException(SSH_FX_FAILURE, e.toString());
0458: }
0459: }
0460:
0461: public void _put(InputStream src, String dst,
0462: SftpProgressMonitor monitor, int mode) throws SftpException {
0463: try {
0464: byte[] dstb = Util.str2byte(dst, fEncoding);
0465: long skip = 0;
0466: if (mode == RESUME || mode == APPEND) {
0467: try {
0468: SftpATTRS attr = _stat(dstb);
0469: skip = attr.getSize();
0470: } catch (Exception eee) {
0471: //System.err.println(eee);
0472: }
0473: }
0474: if (mode == RESUME && skip > 0) {
0475: long skipped = src.skip(skip);
0476: if (skipped < skip) {
0477: throw new SftpException(SSH_FX_FAILURE,
0478: "failed to resume for " + dst);
0479: }
0480: }
0481:
0482: if (mode == OVERWRITE) {
0483: sendOPENW(dstb);
0484: } else {
0485: sendOPENA(dstb);
0486: }
0487:
0488: Header header = new Header();
0489: header = header(buf, header);
0490: int length = header.length;
0491: int type = header.type;
0492:
0493: fill(buf, length);
0494:
0495: if (type != SSH_FXP_STATUS && type != SSH_FXP_HANDLE) {
0496: throw new SftpException(SSH_FX_FAILURE, "invalid type="
0497: + type);
0498: }
0499: if (type == SSH_FXP_STATUS) {
0500: int i = buf.getInt();
0501: throwStatusError(buf, i);
0502: }
0503: byte[] handle = buf.getString(); // handle
0504: byte[] data = null;
0505:
0506: boolean dontcopy = true;
0507:
0508: if (!dontcopy) {
0509: data = new byte[buf.buffer.length
0510: - (5 + 13 + 21 + handle.length + 32 + 20 // padding and mac
0511: )];
0512: }
0513:
0514: long offset = 0;
0515: if (mode == RESUME || mode == APPEND) {
0516: offset += skip;
0517: }
0518:
0519: int startid = seq;
0520: int _ackid = seq;
0521: int ackcount = 0;
0522: while (true) {
0523: int nread = 0;
0524: int s = 0;
0525: int datalen = 0;
0526: int count = 0;
0527:
0528: if (!dontcopy) {
0529: datalen = data.length - s;
0530: } else {
0531: data = buf.buffer;
0532: s = 5 + 13 + 21 + handle.length;
0533: datalen = buf.buffer.length - s - 32 - 20; // padding and mac
0534: }
0535:
0536: do {
0537: nread = src.read(data, s, datalen);
0538: if (nread > 0) {
0539: s += nread;
0540: datalen -= nread;
0541: count += nread;
0542: }
0543: } while (datalen > 0 && nread > 0);
0544: if (count <= 0)
0545: break;
0546:
0547: int _i = count;
0548: while (_i > 0) {
0549: _i -= sendWRITE(handle, offset, data, 0, _i);
0550: if ((seq - 1) == startid
0551: || io.in.available() >= 1024) {
0552: while (io.in.available() > 0) {
0553: if (checkStatus(ackid, header)) {
0554: _ackid = ackid[0];
0555: if (startid > _ackid
0556: || _ackid > seq - 1) {
0557: if (_ackid == seq) {
0558: System.err
0559: .println("ack error: startid="
0560: + startid
0561: + " seq="
0562: + seq
0563: + " _ackid="
0564: + _ackid);
0565: } else {
0566: //throw new SftpException(SSH_FX_FAILURE, "ack error:");
0567: throw new SftpException(
0568: SSH_FX_FAILURE,
0569: "ack error: startid="
0570: + startid
0571: + " seq=" + seq
0572: + " _ackid="
0573: + _ackid);
0574: }
0575: }
0576: ackcount++;
0577: } else {
0578: break;
0579: }
0580: }
0581: }
0582: }
0583: offset += count;
0584: if (monitor != null && !monitor.count(count)) {
0585: break;
0586: }
0587: }
0588: int _ackcount = seq - startid;
0589: while (_ackcount > ackcount) {
0590: if (!checkStatus(null, header)) {
0591: break;
0592: }
0593: ackcount++;
0594: }
0595: if (monitor != null)
0596: monitor.end();
0597: _sendCLOSE(handle, header);
0598: //System.err.println("start end "+startid+" "+endid);
0599: } catch (Exception e) {
0600: if (e instanceof SftpException)
0601: throw (SftpException) e;
0602: if (e instanceof Throwable)
0603: throw new SftpException(SSH_FX_FAILURE, e.toString(),
0604: (Throwable) e);
0605: throw new SftpException(SSH_FX_FAILURE, e.toString());
0606: }
0607: }
0608:
0609: public OutputStream put(String dst) throws SftpException {
0610: return put(dst, (SftpProgressMonitor) null, OVERWRITE);
0611: }
0612:
0613: public OutputStream put(String dst, final int mode)
0614: throws SftpException {
0615: return put(dst, (SftpProgressMonitor) null, mode);
0616: }
0617:
0618: public OutputStream put(String dst,
0619: final SftpProgressMonitor monitor, final int mode)
0620: throws SftpException {
0621: return put(dst, monitor, mode, 0);
0622: }
0623:
0624: public OutputStream put(String dst,
0625: final SftpProgressMonitor monitor, final int mode,
0626: long offset) throws SftpException {
0627: dst = remoteAbsolutePath(dst);
0628: try {
0629:
0630: dst = isUnique(dst);
0631:
0632: if (isRemoteDir(dst)) {
0633: throw new SftpException(SSH_FX_FAILURE, dst
0634: + " is a directory");
0635: }
0636:
0637: byte[] dstb = Util.str2byte(dst, fEncoding);
0638:
0639: long skip = 0;
0640: if (mode == RESUME || mode == APPEND) {
0641: try {
0642: SftpATTRS attr = _stat(dstb);
0643: skip = attr.getSize();
0644: } catch (Exception eee) {
0645: //System.err.println(eee);
0646: }
0647: }
0648:
0649: if (mode == OVERWRITE) {
0650: sendOPENW(dstb);
0651: } else {
0652: sendOPENA(dstb);
0653: }
0654:
0655: Header header = new Header();
0656: header = header(buf, header);
0657: int length = header.length;
0658: int type = header.type;
0659:
0660: fill(buf, length);
0661:
0662: if (type != SSH_FXP_STATUS && type != SSH_FXP_HANDLE) {
0663: throw new SftpException(SSH_FX_FAILURE, "");
0664: }
0665: if (type == SSH_FXP_STATUS) {
0666: int i = buf.getInt();
0667: throwStatusError(buf, i);
0668: }
0669: final byte[] handle = buf.getString(); // handle
0670:
0671: //long offset=0;
0672: if (mode == RESUME || mode == APPEND) {
0673: offset += skip;
0674: }
0675:
0676: final long[] _offset = new long[1];
0677: _offset[0] = offset;
0678: OutputStream out = new OutputStream() {
0679: private boolean init = true;
0680: private boolean isClosed = false;
0681: private int[] ackid = new int[1];
0682: private int startid = 0;
0683: private int _ackid = 0;
0684: private int ackcount = 0;
0685: private int writecount = 0;
0686: private Header header = new Header();
0687:
0688: public void write(byte[] d) throws java.io.IOException {
0689: write(d, 0, d.length);
0690: }
0691:
0692: public void write(byte[] d, int s, int len)
0693: throws java.io.IOException {
0694: if (init) {
0695: startid = seq;
0696: _ackid = seq;
0697: init = false;
0698: }
0699:
0700: if (isClosed) {
0701: throw new IOException("stream already closed");
0702: }
0703:
0704: try {
0705: int _len = len;
0706: while (_len > 0) {
0707: int sent = sendWRITE(handle, _offset[0], d,
0708: s, _len);
0709: writecount++;
0710: _offset[0] += sent;
0711: s += sent;
0712: _len -= sent;
0713: if ((seq - 1) == startid
0714: || io.in.available() >= 1024) {
0715: while (io.in.available() > 0) {
0716: if (checkStatus(ackid, header)) {
0717: _ackid = ackid[0];
0718: if (startid > _ackid
0719: || _ackid > seq - 1) {
0720: throw new SftpException(
0721: SSH_FX_FAILURE, "");
0722: }
0723: ackcount++;
0724: } else {
0725: break;
0726: }
0727: }
0728: }
0729: }
0730: if (monitor != null && !monitor.count(len)) {
0731: close();
0732: throw new IOException("canceled");
0733: }
0734: } catch (IOException e) {
0735: throw e;
0736: } catch (Exception e) {
0737: throw new IOException(e.toString());
0738: }
0739: }
0740:
0741: byte[] _data = new byte[1];
0742:
0743: public void write(int foo) throws java.io.IOException {
0744: _data[0] = (byte) foo;
0745: write(_data, 0, 1);
0746: }
0747:
0748: public void flush() throws java.io.IOException {
0749:
0750: if (isClosed) {
0751: throw new IOException("stream already closed");
0752: }
0753:
0754: if (!init) {
0755: try {
0756: while (writecount > ackcount) {
0757: if (!checkStatus(null, header)) {
0758: break;
0759: }
0760: ackcount++;
0761: }
0762: } catch (SftpException e) {
0763: throw new IOException(e.toString());
0764: }
0765: }
0766: }
0767:
0768: public void close() throws java.io.IOException {
0769: if (isClosed) {
0770: return;
0771: }
0772: flush();
0773: if (monitor != null)
0774: monitor.end();
0775: try {
0776: _sendCLOSE(handle, header);
0777: } catch (IOException e) {
0778: throw e;
0779: } catch (Exception e) {
0780: throw new IOException(e.toString());
0781: }
0782: isClosed = true;
0783: }
0784: };
0785: return out;
0786: } catch (Exception e) {
0787: if (e instanceof SftpException)
0788: throw (SftpException) e;
0789: if (e instanceof Throwable)
0790: throw new SftpException(SSH_FX_FAILURE, "",
0791: (Throwable) e);
0792: throw new SftpException(SSH_FX_FAILURE, "");
0793: }
0794: }
0795:
0796: public void get(String src, String dst) throws SftpException {
0797: get(src, dst, null, OVERWRITE);
0798: }
0799:
0800: public void get(String src, String dst, SftpProgressMonitor monitor)
0801: throws SftpException {
0802: get(src, dst, monitor, OVERWRITE);
0803: }
0804:
0805: public void get(String src, String dst,
0806: SftpProgressMonitor monitor, int mode) throws SftpException {
0807: // System.out.println("get: "+src+" "+dst);
0808:
0809: src = remoteAbsolutePath(src);
0810: dst = localAbsolutePath(dst);
0811:
0812: try {
0813: Vector v = glob_remote(src);
0814: int vsize = v.size();
0815: if (vsize == 0) {
0816: throw new SftpException(SSH_FX_NO_SUCH_FILE,
0817: "No such file");
0818: }
0819:
0820: File dstFile = new File(dst);
0821: boolean isDstDir = dstFile.isDirectory();
0822: StringBuffer dstsb = null;
0823: if (isDstDir) {
0824: if (!dst.endsWith(file_separator)) {
0825: dst += file_separator;
0826: }
0827: dstsb = new StringBuffer(dst);
0828: } else if (vsize > 1) {
0829: throw new SftpException(SSH_FX_FAILURE,
0830: "Copying multiple files, but destination is missing or a file.");
0831: }
0832:
0833: for (int j = 0; j < vsize; j++) {
0834: String _src = (String) (v.elementAt(j));
0835: SftpATTRS attr = _stat(_src);
0836: if (attr.isDir()) {
0837: throw new SftpException(SSH_FX_FAILURE,
0838: "not supported to get directory " + _src);
0839: }
0840:
0841: String _dst = null;
0842: if (isDstDir) {
0843: int i = _src.lastIndexOf('/');
0844: if (i == -1)
0845: dstsb.append(_src);
0846: else
0847: dstsb.append(_src.substring(i + 1));
0848: _dst = dstsb.toString();
0849: dstsb.delete(dst.length(), _dst.length());
0850: } else {
0851: _dst = dst;
0852: }
0853:
0854: if (mode == RESUME) {
0855: long size_of_src = attr.getSize();
0856: long size_of_dst = new File(_dst).length();
0857: if (size_of_dst > size_of_src) {
0858: throw new SftpException(SSH_FX_FAILURE,
0859: "failed to resume for " + _dst);
0860: }
0861: if (size_of_dst == size_of_src) {
0862: return;
0863: }
0864: }
0865:
0866: if (monitor != null) {
0867: monitor.init(SftpProgressMonitor.GET, _src, _dst,
0868: attr.getSize());
0869: if (mode == RESUME) {
0870: monitor.count(new File(_dst).length());
0871: }
0872: }
0873:
0874: FileOutputStream fos = null;
0875: if (mode == OVERWRITE) {
0876: fos = new FileOutputStream(_dst);
0877: } else {
0878: fos = new FileOutputStream(_dst, true); // append
0879: }
0880: // System.err.println("_get: "+_src+", "+_dst);
0881: _get(_src, fos, monitor, mode, new File(_dst).length());
0882: fos.close();
0883: }
0884: } catch (Exception e) {
0885: if (e instanceof SftpException)
0886: throw (SftpException) e;
0887: if (e instanceof Throwable)
0888: throw new SftpException(SSH_FX_FAILURE, "",
0889: (Throwable) e);
0890: throw new SftpException(SSH_FX_FAILURE, "");
0891: }
0892: }
0893:
0894: public void get(String src, OutputStream dst) throws SftpException {
0895: get(src, dst, null, OVERWRITE, 0);
0896: }
0897:
0898: public void get(String src, OutputStream dst,
0899: SftpProgressMonitor monitor) throws SftpException {
0900: get(src, dst, monitor, OVERWRITE, 0);
0901: }
0902:
0903: public void get(String src, OutputStream dst,
0904: SftpProgressMonitor monitor, int mode, long skip)
0905: throws SftpException {
0906: //System.err.println("get: "+src+", "+dst);
0907: try {
0908: src = remoteAbsolutePath(src);
0909:
0910: src = isUnique(src);
0911:
0912: if (monitor != null) {
0913: SftpATTRS attr = _stat(src);
0914: monitor.init(SftpProgressMonitor.GET, src, "??", attr
0915: .getSize());
0916: if (mode == RESUME) {
0917: monitor.count(skip);
0918: }
0919: }
0920: _get(src, dst, monitor, mode, skip);
0921: } catch (Exception e) {
0922: if (e instanceof SftpException)
0923: throw (SftpException) e;
0924: if (e instanceof Throwable)
0925: throw new SftpException(SSH_FX_FAILURE, "",
0926: (Throwable) e);
0927: throw new SftpException(SSH_FX_FAILURE, "");
0928: }
0929: }
0930:
0931: private void _get(String src, OutputStream dst,
0932: SftpProgressMonitor monitor, int mode, long skip)
0933: throws SftpException {
0934: //System.err.println("_get: "+src+", "+dst);
0935:
0936: byte[] srcb = Util.str2byte(src, fEncoding);
0937: try {
0938: sendOPENR(srcb);
0939:
0940: Header header = new Header();
0941: header = header(buf, header);
0942: int length = header.length;
0943: int type = header.type;
0944:
0945: fill(buf, length);
0946:
0947: if (type != SSH_FXP_STATUS && type != SSH_FXP_HANDLE) {
0948: throw new SftpException(SSH_FX_FAILURE, "");
0949: }
0950:
0951: if (type == SSH_FXP_STATUS) {
0952: int i = buf.getInt();
0953: throwStatusError(buf, i);
0954: }
0955:
0956: byte[] handle = buf.getString(); // filename
0957:
0958: long offset = 0;
0959: if (mode == RESUME) {
0960: offset += skip;
0961: }
0962:
0963: int request_len = 0;
0964: loop: while (true) {
0965:
0966: request_len = buf.buffer.length - 13;
0967: if (server_version == 0) {
0968: request_len = 1024;
0969: }
0970: sendREAD(handle, offset, request_len);
0971:
0972: header = header(buf, header);
0973: length = header.length;
0974: type = header.type;
0975:
0976: if (type == SSH_FXP_STATUS) {
0977: fill(buf, length);
0978: int i = buf.getInt();
0979: if (i == SSH_FX_EOF) {
0980: break loop;
0981: }
0982: throwStatusError(buf, i);
0983: }
0984:
0985: if (type != SSH_FXP_DATA) {
0986: break loop;
0987: }
0988:
0989: buf.rewind();
0990: fill(buf.buffer, 0, 4);
0991: length -= 4;
0992: int i = buf.getInt(); // length of data
0993: int foo = i;
0994:
0995: while (foo > 0) {
0996: int bar = foo;
0997: if (bar > buf.buffer.length) {
0998: bar = buf.buffer.length;
0999: }
1000: i = io.in.read(buf.buffer, 0, bar);
1001: if (i < 0) {
1002: break loop;
1003: }
1004: int data_len = i;
1005: dst.write(buf.buffer, 0, data_len);
1006:
1007: offset += data_len;
1008: foo -= data_len;
1009:
1010: if (monitor != null) {
1011: if (!monitor.count(data_len)) {
1012: while (foo > 0) {
1013: i = io.in
1014: .read(
1015: buf.buffer,
1016: 0,
1017: (buf.buffer.length < foo ? buf.buffer.length
1018: : foo));
1019: if (i <= 0)
1020: break;
1021: foo -= i;
1022: }
1023: break loop;
1024: }
1025: }
1026:
1027: }
1028: //System.err.println("length: "+length); // length should be 0
1029: }
1030: dst.flush();
1031:
1032: if (monitor != null)
1033: monitor.end();
1034: _sendCLOSE(handle, header);
1035: } catch (Exception e) {
1036: if (e instanceof SftpException)
1037: throw (SftpException) e;
1038: if (e instanceof Throwable)
1039: throw new SftpException(SSH_FX_FAILURE, "",
1040: (Throwable) e);
1041: throw new SftpException(SSH_FX_FAILURE, "");
1042: }
1043: }
1044:
1045: public InputStream get(String src) throws SftpException {
1046: return get(src, null, 0L);
1047: }
1048:
1049: public InputStream get(String src, SftpProgressMonitor monitor)
1050: throws SftpException {
1051: return get(src, monitor, 0L);
1052: }
1053:
1054: /**
1055: * @deprecated This method will be deleted in the future.
1056: */
1057: public InputStream get(String src, int mode) throws SftpException {
1058: return get(src, null, 0L);
1059: }
1060:
1061: /**
1062: * @deprecated This method will be deleted in the future.
1063: */
1064: public InputStream get(String src,
1065: final SftpProgressMonitor monitor, final int mode)
1066: throws SftpException {
1067: return get(src, monitor, 0L);
1068: }
1069:
1070: public InputStream get(String src,
1071: final SftpProgressMonitor monitor, final long skip)
1072: throws SftpException {
1073: src = remoteAbsolutePath(src);
1074: try {
1075: src = isUnique(src);
1076:
1077: byte[] srcb = Util.str2byte(src, fEncoding);
1078:
1079: SftpATTRS attr = _stat(srcb);
1080: if (monitor != null) {
1081: monitor.init(SftpProgressMonitor.GET, src, "??", attr
1082: .getSize());
1083: }
1084:
1085: sendOPENR(srcb);
1086:
1087: Header header = new Header();
1088: header = header(buf, header);
1089: int length = header.length;
1090: int type = header.type;
1091:
1092: fill(buf, length);
1093:
1094: if (type != SSH_FXP_STATUS && type != SSH_FXP_HANDLE) {
1095: throw new SftpException(SSH_FX_FAILURE, "");
1096: }
1097: if (type == SSH_FXP_STATUS) {
1098: int i = buf.getInt();
1099: throwStatusError(buf, i);
1100: }
1101:
1102: final byte[] handle = buf.getString(); // handle
1103:
1104: java.io.InputStream in = new java.io.InputStream() {
1105: long offset = skip;
1106: boolean closed = false;
1107: int rest_length = 0;
1108: byte[] _data = new byte[1];
1109: byte[] rest_byte = new byte[1024];
1110: Header header = new Header();
1111:
1112: public int read() throws java.io.IOException {
1113: if (closed)
1114: return -1;
1115: int i = read(_data, 0, 1);
1116: if (i == -1) {
1117: return -1;
1118: } else {
1119: return _data[0] & 0xff;
1120: }
1121: }
1122:
1123: public int read(byte[] d) throws java.io.IOException {
1124: if (closed)
1125: return -1;
1126: return read(d, 0, d.length);
1127: }
1128:
1129: public int read(byte[] d, int s, int len)
1130: throws java.io.IOException {
1131: if (closed)
1132: return -1;
1133: if (d == null) {
1134: throw new NullPointerException();
1135: }
1136: if (s < 0 || len < 0 || s + len > d.length) {
1137: throw new IndexOutOfBoundsException();
1138: }
1139: if (len == 0) {
1140: return 0;
1141: }
1142:
1143: if (rest_length > 0) {
1144: int foo = rest_length;
1145: if (foo > len)
1146: foo = len;
1147: System.arraycopy(rest_byte, 0, d, s, foo);
1148: if (foo != rest_length) {
1149: System.arraycopy(rest_byte, foo, rest_byte,
1150: 0, rest_length - foo);
1151: }
1152:
1153: if (monitor != null) {
1154: if (!monitor.count(foo)) {
1155: close();
1156: return -1;
1157: }
1158: }
1159:
1160: rest_length -= foo;
1161: return foo;
1162: }
1163:
1164: if (buf.buffer.length - 13 < len) {
1165: len = buf.buffer.length - 13;
1166: }
1167: if (server_version == 0 && len > 1024) {
1168: len = 1024;
1169: }
1170:
1171: try {
1172: sendREAD(handle, offset, len);
1173: } catch (Exception e) {
1174: throw new IOException("error");
1175: }
1176:
1177: header = header(buf, header);
1178: rest_length = header.length;
1179: int type = header.type;
1180: int id = header.rid;
1181:
1182: if (type != SSH_FXP_STATUS && type != SSH_FXP_DATA) {
1183: throw new IOException("error");
1184: }
1185: if (type == SSH_FXP_STATUS) {
1186: fill(buf, rest_length);
1187: int i = buf.getInt();
1188: rest_length = 0;
1189: if (i == SSH_FX_EOF) {
1190: close();
1191: return -1;
1192: }
1193: //throwStatusError(buf, i);
1194: throw new IOException("error");
1195: }
1196: buf.rewind();
1197: fill(buf.buffer, 0, 4);
1198: int i = buf.getInt();
1199: rest_length -= 4;
1200:
1201: offset += rest_length;
1202: int foo = i;
1203: if (foo > 0) {
1204: int bar = rest_length;
1205: if (bar > len) {
1206: bar = len;
1207: }
1208: i = io.in.read(d, s, bar);
1209: if (i < 0) {
1210: return -1;
1211: }
1212: rest_length -= i;
1213:
1214: if (rest_length > 0) {
1215: if (rest_byte.length < rest_length) {
1216: rest_byte = new byte[rest_length];
1217: }
1218: int _s = 0;
1219: int _len = rest_length;
1220: int j;
1221: while (_len > 0) {
1222: j = io.in.read(rest_byte, _s, _len);
1223: if (j <= 0)
1224: break;
1225: _s += j;
1226: _len -= j;
1227: }
1228: }
1229:
1230: if (monitor != null) {
1231: if (!monitor.count(i)) {
1232: close();
1233: return -1;
1234: }
1235: }
1236:
1237: return i;
1238: }
1239: return 0; // ??
1240: }
1241:
1242: public void close() throws IOException {
1243: if (closed)
1244: return;
1245: closed = true;
1246: /*
1247: while(rest_length>0){
1248: int foo=rest_length;
1249: if(foo>buf.buffer.length){
1250: foo=buf.buffer.length;
1251: }
1252: io.in.read(buf.buffer, 0, foo);
1253: rest_length-=foo;
1254: }
1255: */
1256: if (monitor != null)
1257: monitor.end();
1258: try {
1259: _sendCLOSE(handle, header);
1260: } catch (Exception e) {
1261: throw new IOException("error");
1262: }
1263: }
1264: };
1265: return in;
1266: } catch (Exception e) {
1267: if (e instanceof SftpException)
1268: throw (SftpException) e;
1269: if (e instanceof Throwable)
1270: throw new SftpException(SSH_FX_FAILURE, "",
1271: (Throwable) e);
1272: throw new SftpException(SSH_FX_FAILURE, "");
1273: }
1274: }
1275:
1276: public java.util.Vector ls(String path) throws SftpException {
1277: //System.out.println("ls: "+path);
1278: try {
1279: path = remoteAbsolutePath(path);
1280: byte[] pattern = null;
1281: java.util.Vector v = new java.util.Vector();
1282:
1283: int foo = path.lastIndexOf('/');
1284: String dir = path.substring(0, ((foo == 0) ? 1 : foo));
1285: String _pattern = path.substring(foo + 1);
1286: dir = Util.unquote(dir);
1287:
1288: // If pattern has included '*' or '?', we need to convert
1289: // to UTF-8 string before globbing.
1290: byte[][] _pattern_utf8 = new byte[1][];
1291: boolean pattern_has_wildcard = isPattern(_pattern,
1292: _pattern_utf8);
1293:
1294: if (pattern_has_wildcard) {
1295: pattern = _pattern_utf8[0];
1296: } else {
1297: String upath = Util.unquote(path);
1298: //SftpATTRS attr=_lstat(upath);
1299: SftpATTRS attr = _stat(upath);
1300: if (attr.isDir()) {
1301: pattern = null;
1302: dir = upath;
1303: } else {
1304: /*
1305: // If we can generage longname by ourself,
1306: // we don't have to use openDIR.
1307: String filename=Util.unquote(_pattern);
1308: String longname=...
1309: v.addElement(new LsEntry(filename, longname, attr));
1310: return v;
1311: */
1312:
1313: if (fEncoding_is_utf8) {
1314: pattern = _pattern_utf8[0];
1315: pattern = Util.unquote(pattern);
1316: } else {
1317: _pattern = Util.unquote(_pattern);
1318: pattern = Util.str2byte(_pattern, fEncoding);
1319: }
1320:
1321: }
1322: }
1323:
1324: sendOPENDIR(Util.str2byte(dir, fEncoding));
1325:
1326: Header header = new Header();
1327: header = header(buf, header);
1328: int length = header.length;
1329: int type = header.type;
1330:
1331: fill(buf, length);
1332:
1333: if (type != SSH_FXP_STATUS && type != SSH_FXP_HANDLE) {
1334: throw new SftpException(SSH_FX_FAILURE, "");
1335: }
1336: if (type == SSH_FXP_STATUS) {
1337: int i = buf.getInt();
1338: throwStatusError(buf, i);
1339: }
1340:
1341: byte[] handle = buf.getString(); // handle
1342:
1343: while (true) {
1344: sendREADDIR(handle);
1345:
1346: header = header(buf, header);
1347: length = header.length;
1348: type = header.type;
1349: if (type != SSH_FXP_STATUS && type != SSH_FXP_NAME) {
1350: throw new SftpException(SSH_FX_FAILURE, "");
1351: }
1352: if (type == SSH_FXP_STATUS) {
1353: fill(buf, length);
1354: int i = buf.getInt();
1355: if (i == SSH_FX_EOF)
1356: break;
1357: throwStatusError(buf, i);
1358: }
1359:
1360: buf.rewind();
1361: fill(buf.buffer, 0, 4);
1362: length -= 4;
1363: int count = buf.getInt();
1364:
1365: byte[] str;
1366: int flags;
1367:
1368: buf.reset();
1369: while (count > 0) {
1370: if (length > 0) {
1371: buf.shift();
1372: int j = (buf.buffer.length > (buf.index + length)) ? length
1373: : (buf.buffer.length - buf.index);
1374: int i = fill(buf.buffer, buf.index, j);
1375: buf.index += i;
1376: length -= i;
1377: }
1378: byte[] filename = buf.getString();
1379: byte[] longname = null;
1380: if (server_version <= 3) {
1381: longname = buf.getString();
1382: }
1383: SftpATTRS attrs = SftpATTRS.getATTR(buf);
1384:
1385: boolean find = false;
1386: String f = null;
1387: if (pattern == null) {
1388: find = true;
1389: } else if (!pattern_has_wildcard) {
1390: find = Util.array_equals(pattern, filename);
1391: } else {
1392: byte[] _filename = filename;
1393: if (!fEncoding_is_utf8) {
1394: f = Util.byte2str(_filename, fEncoding);
1395: _filename = Util.str2byte(f, UTF8);
1396: }
1397: find = Util.glob(pattern, _filename);
1398: }
1399:
1400: if (find) {
1401: if (f == null) {
1402: f = Util.byte2str(filename, fEncoding);
1403: }
1404: String l = null;
1405: if (longname == null) {
1406: // TODO: we need to generate long name from attrs
1407: // for the sftp protocol 4(and later).
1408: l = attrs.toString() + " " + f;
1409: } else {
1410: l = Util.byte2str(longname, fEncoding);
1411: }
1412: v.addElement(new LsEntry(f, l, attrs));
1413: }
1414:
1415: count--;
1416: }
1417: }
1418: _sendCLOSE(handle, header);
1419:
1420: if (v.size() == 0) {
1421: throw new SftpException(SSH_FX_NO_SUCH_FILE,
1422: "No such file: " + path);
1423: }
1424:
1425: /*
1426: if(v.size()==1 && pattern_has_wildcard){
1427: LsEntry le=(LsEntry)v.elementAt(0);
1428: if(le.getAttrs().isDir()){
1429: String f=le.getFilename();
1430: if(isPattern(f)){
1431: f=Util.quote(f);
1432: }
1433: if(!dir.endsWith("/")){
1434: dir+="/";
1435: }
1436: v=null;
1437: return ls(dir+f);
1438: }
1439: }
1440: */
1441:
1442: return v;
1443: } catch (Exception e) {
1444: if (e instanceof SftpException)
1445: throw (SftpException) e;
1446: if (e instanceof Throwable)
1447: throw new SftpException(SSH_FX_FAILURE, "",
1448: (Throwable) e);
1449: throw new SftpException(SSH_FX_FAILURE, "");
1450: }
1451: }
1452:
1453: public String readlink(String path) throws SftpException {
1454: try {
1455:
1456: if (server_version < 3) {
1457: throw new SftpException(SSH_FX_OP_UNSUPPORTED,
1458: "The remote sshd is too old to support symlink operation.");
1459: }
1460:
1461: path = remoteAbsolutePath(path);
1462:
1463: path = isUnique(path);
1464:
1465: sendREADLINK(Util.str2byte(path, 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 && type != SSH_FXP_NAME) {
1475: throw new SftpException(SSH_FX_FAILURE, "");
1476: }
1477: if (type == SSH_FXP_NAME) {
1478: int count = buf.getInt(); // count
1479: byte[] filename = null;
1480: for (int i = 0; i < count; i++) {
1481: filename = buf.getString();
1482: if (server_version <= 3) {
1483: byte[] longname = buf.getString();
1484: }
1485: SftpATTRS.getATTR(buf);
1486: }
1487: return Util.byte2str(filename, fEncoding);
1488: }
1489:
1490: int i = buf.getInt();
1491: throwStatusError(buf, i);
1492: } catch (Exception e) {
1493: if (e instanceof SftpException)
1494: throw (SftpException) e;
1495: if (e instanceof Throwable)
1496: throw new SftpException(SSH_FX_FAILURE, "",
1497: (Throwable) e);
1498: throw new SftpException(SSH_FX_FAILURE, "");
1499: }
1500: return null;
1501: }
1502:
1503: public void symlink(String oldpath, String newpath)
1504: throws SftpException {
1505: if (server_version < 3) {
1506: throw new SftpException(SSH_FX_OP_UNSUPPORTED,
1507: "The remote sshd is too old to support symlink operation.");
1508: }
1509:
1510: try {
1511: oldpath = remoteAbsolutePath(oldpath);
1512: newpath = remoteAbsolutePath(newpath);
1513:
1514: oldpath = isUnique(oldpath);
1515:
1516: if (isPattern(newpath)) {
1517: throw new SftpException(SSH_FX_FAILURE, newpath);
1518: }
1519: newpath = Util.unquote(newpath);
1520:
1521: sendSYMLINK(Util.str2byte(oldpath, fEncoding), Util
1522: .str2byte(newpath, fEncoding));
1523:
1524: Header header = new Header();
1525: header = header(buf, header);
1526: int length = header.length;
1527: int type = header.type;
1528:
1529: fill(buf, length);
1530:
1531: if (type != SSH_FXP_STATUS) {
1532: throw new SftpException(SSH_FX_FAILURE, "");
1533: }
1534:
1535: int i = buf.getInt();
1536: if (i == SSH_FX_OK)
1537: return;
1538: throwStatusError(buf, i);
1539: } catch (Exception e) {
1540: if (e instanceof SftpException)
1541: throw (SftpException) e;
1542: if (e instanceof Throwable)
1543: throw new SftpException(SSH_FX_FAILURE, "",
1544: (Throwable) e);
1545: throw new SftpException(SSH_FX_FAILURE, "");
1546: }
1547: }
1548:
1549: public void rename(String oldpath, String newpath)
1550: throws SftpException {
1551: if (server_version < 2) {
1552: throw new SftpException(SSH_FX_OP_UNSUPPORTED,
1553: "The remote sshd is too old to support rename operation.");
1554: }
1555:
1556: try {
1557: oldpath = remoteAbsolutePath(oldpath);
1558: newpath = remoteAbsolutePath(newpath);
1559:
1560: oldpath = isUnique(oldpath);
1561:
1562: Vector v = glob_remote(newpath);
1563: int vsize = v.size();
1564: if (vsize >= 2) {
1565: throw new SftpException(SSH_FX_FAILURE, v.toString());
1566: }
1567: if (vsize == 1) {
1568: newpath = (String) (v.elementAt(0));
1569: } else { // vsize==0
1570: if (isPattern(newpath))
1571: throw new SftpException(SSH_FX_FAILURE, newpath);
1572: newpath = Util.unquote(newpath);
1573: }
1574:
1575: sendRENAME(Util.str2byte(oldpath, fEncoding), Util
1576: .str2byte(newpath, fEncoding));
1577:
1578: Header header = new Header();
1579: header = header(buf, header);
1580: int length = header.length;
1581: int type = header.type;
1582:
1583: fill(buf, length);
1584:
1585: if (type != SSH_FXP_STATUS) {
1586: throw new SftpException(SSH_FX_FAILURE, "");
1587: }
1588:
1589: int i = buf.getInt();
1590: if (i == SSH_FX_OK)
1591: return;
1592: throwStatusError(buf, i);
1593: } catch (Exception e) {
1594: if (e instanceof SftpException)
1595: throw (SftpException) e;
1596: if (e instanceof Throwable)
1597: throw new SftpException(SSH_FX_FAILURE, "",
1598: (Throwable) e);
1599: throw new SftpException(SSH_FX_FAILURE, "");
1600: }
1601: }
1602:
1603: public void rm(String path) throws SftpException {
1604: try {
1605: path = remoteAbsolutePath(path);
1606:
1607: Vector v = glob_remote(path);
1608: int vsize = v.size();
1609:
1610: Header header = new Header();
1611:
1612: for (int j = 0; j < vsize; j++) {
1613: path = (String) (v.elementAt(j));
1614: sendREMOVE(Util.str2byte(path, fEncoding));
1615:
1616: header = header(buf, header);
1617: int length = header.length;
1618: int type = header.type;
1619:
1620: fill(buf, length);
1621:
1622: if (type != SSH_FXP_STATUS) {
1623: throw new SftpException(SSH_FX_FAILURE, "");
1624: }
1625: int i = buf.getInt();
1626: if (i != SSH_FX_OK) {
1627: throwStatusError(buf, i);
1628: }
1629: }
1630: } catch (Exception e) {
1631: if (e instanceof SftpException)
1632: throw (SftpException) e;
1633: if (e instanceof Throwable)
1634: throw new SftpException(SSH_FX_FAILURE, "",
1635: (Throwable) e);
1636: throw new SftpException(SSH_FX_FAILURE, "");
1637: }
1638: }
1639:
1640: private boolean isRemoteDir(String path) {
1641: try {
1642: sendSTAT(Util.str2byte(path, fEncoding));
1643:
1644: Header header = new Header();
1645: header = header(buf, header);
1646: int length = header.length;
1647: int type = header.type;
1648:
1649: fill(buf, length);
1650:
1651: if (type != SSH_FXP_ATTRS) {
1652: return false;
1653: }
1654: SftpATTRS attr = SftpATTRS.getATTR(buf);
1655: return attr.isDir();
1656: } catch (Exception e) {
1657: }
1658: return false;
1659: }
1660:
1661: public void chgrp(int gid, String path) throws SftpException {
1662: try {
1663: path = remoteAbsolutePath(path);
1664:
1665: Vector v = glob_remote(path);
1666: int vsize = v.size();
1667: for (int j = 0; j < vsize; j++) {
1668: path = (String) (v.elementAt(j));
1669:
1670: SftpATTRS attr = _stat(path);
1671:
1672: attr.setFLAGS(0);
1673: attr.setUIDGID(attr.uid, gid);
1674: _setStat(path, attr);
1675: }
1676: } catch (Exception e) {
1677: if (e instanceof SftpException)
1678: throw (SftpException) e;
1679: if (e instanceof Throwable)
1680: throw new SftpException(SSH_FX_FAILURE, "",
1681: (Throwable) e);
1682: throw new SftpException(SSH_FX_FAILURE, "");
1683: }
1684: }
1685:
1686: public void chown(int uid, String path) throws SftpException {
1687: try {
1688: path = remoteAbsolutePath(path);
1689:
1690: Vector v = glob_remote(path);
1691: int vsize = v.size();
1692: for (int j = 0; j < vsize; j++) {
1693: path = (String) (v.elementAt(j));
1694:
1695: SftpATTRS attr = _stat(path);
1696:
1697: attr.setFLAGS(0);
1698: attr.setUIDGID(uid, attr.gid);
1699: _setStat(path, attr);
1700: }
1701: } catch (Exception e) {
1702: if (e instanceof SftpException)
1703: throw (SftpException) e;
1704: if (e instanceof Throwable)
1705: throw new SftpException(SSH_FX_FAILURE, "",
1706: (Throwable) e);
1707: throw new SftpException(SSH_FX_FAILURE, "");
1708: }
1709: }
1710:
1711: public void chmod(int permissions, String path)
1712: throws SftpException {
1713: try {
1714: path = remoteAbsolutePath(path);
1715:
1716: Vector v = glob_remote(path);
1717: int vsize = v.size();
1718: for (int j = 0; j < vsize; j++) {
1719: path = (String) (v.elementAt(j));
1720:
1721: SftpATTRS attr = _stat(path);
1722:
1723: attr.setFLAGS(0);
1724: attr.setPERMISSIONS(permissions);
1725: _setStat(path, attr);
1726: }
1727: } catch (Exception e) {
1728: if (e instanceof SftpException)
1729: throw (SftpException) e;
1730: if (e instanceof Throwable)
1731: throw new SftpException(SSH_FX_FAILURE, "",
1732: (Throwable) e);
1733: throw new SftpException(SSH_FX_FAILURE, "");
1734: }
1735: }
1736:
1737: public void setMtime(String path, int mtime) throws SftpException {
1738: try {
1739: path = remoteAbsolutePath(path);
1740:
1741: Vector v = glob_remote(path);
1742: int vsize = v.size();
1743: for (int j = 0; j < vsize; j++) {
1744: path = (String) (v.elementAt(j));
1745:
1746: SftpATTRS attr = _stat(path);
1747:
1748: attr.setFLAGS(0);
1749: attr.setACMODTIME(attr.getATime(), mtime);
1750: _setStat(path, attr);
1751: }
1752: } catch (Exception e) {
1753: if (e instanceof SftpException)
1754: throw (SftpException) e;
1755: if (e instanceof Throwable)
1756: throw new SftpException(SSH_FX_FAILURE, "",
1757: (Throwable) e);
1758: throw new SftpException(SSH_FX_FAILURE, "");
1759: }
1760: }
1761:
1762: public void rmdir(String path) throws SftpException {
1763: try {
1764: path = remoteAbsolutePath(path);
1765:
1766: Vector v = glob_remote(path);
1767: int vsize = v.size();
1768:
1769: Header header = new Header();
1770:
1771: for (int j = 0; j < vsize; j++) {
1772: path = (String) (v.elementAt(j));
1773: sendRMDIR(Util.str2byte(path, fEncoding));
1774:
1775: header = header(buf, header);
1776: int length = header.length;
1777: int type = header.type;
1778:
1779: fill(buf, length);
1780:
1781: if (type != SSH_FXP_STATUS) {
1782: throw new SftpException(SSH_FX_FAILURE, "");
1783: }
1784:
1785: int i = buf.getInt();
1786: if (i != SSH_FX_OK) {
1787: throwStatusError(buf, i);
1788: }
1789: }
1790: } catch (Exception e) {
1791: if (e instanceof SftpException)
1792: throw (SftpException) e;
1793: if (e instanceof Throwable)
1794: throw new SftpException(SSH_FX_FAILURE, "",
1795: (Throwable) e);
1796: throw new SftpException(SSH_FX_FAILURE, "");
1797: }
1798: }
1799:
1800: public void mkdir(String path) throws SftpException {
1801: try {
1802: path = remoteAbsolutePath(path);
1803:
1804: sendMKDIR(Util.str2byte(path, fEncoding), null);
1805:
1806: Header header = new Header();
1807: header = header(buf, header);
1808: int length = header.length;
1809: int type = header.type;
1810:
1811: fill(buf, length);
1812:
1813: if (type != SSH_FXP_STATUS) {
1814: throw new SftpException(SSH_FX_FAILURE, "");
1815: }
1816:
1817: int i = buf.getInt();
1818: if (i == SSH_FX_OK)
1819: return;
1820: throwStatusError(buf, i);
1821: } catch (Exception e) {
1822: if (e instanceof SftpException)
1823: throw (SftpException) e;
1824: if (e instanceof Throwable)
1825: throw new SftpException(SSH_FX_FAILURE, "",
1826: (Throwable) e);
1827: throw new SftpException(SSH_FX_FAILURE, "");
1828: }
1829: }
1830:
1831: public SftpATTRS stat(String path) throws SftpException {
1832: try {
1833: path = remoteAbsolutePath(path);
1834:
1835: path = isUnique(path);
1836:
1837: return _stat(path);
1838: } catch (Exception e) {
1839: if (e instanceof SftpException)
1840: throw (SftpException) e;
1841: if (e instanceof Throwable)
1842: throw new SftpException(SSH_FX_FAILURE, "",
1843: (Throwable) e);
1844: throw new SftpException(SSH_FX_FAILURE, "");
1845: }
1846: //return null;
1847: }
1848:
1849: private SftpATTRS _stat(byte[] path) throws SftpException {
1850: try {
1851:
1852: sendSTAT(path);
1853:
1854: Header header = new Header();
1855: header = header(buf, header);
1856: int length = header.length;
1857: int type = header.type;
1858:
1859: fill(buf, length);
1860:
1861: if (type != SSH_FXP_ATTRS) {
1862: if (type == SSH_FXP_STATUS) {
1863: int i = buf.getInt();
1864: throwStatusError(buf, i);
1865: }
1866: throw new SftpException(SSH_FX_FAILURE, "");
1867: }
1868: SftpATTRS attr = SftpATTRS.getATTR(buf);
1869: return attr;
1870: } catch (Exception e) {
1871: if (e instanceof SftpException)
1872: throw (SftpException) e;
1873: if (e instanceof Throwable)
1874: throw new SftpException(SSH_FX_FAILURE, "",
1875: (Throwable) e);
1876: throw new SftpException(SSH_FX_FAILURE, "");
1877: }
1878: //return null;
1879: }
1880:
1881: private SftpATTRS _stat(String path) throws SftpException {
1882: return _stat(Util.str2byte(path, fEncoding));
1883: }
1884:
1885: public SftpATTRS lstat(String path) throws SftpException {
1886: try {
1887: path = remoteAbsolutePath(path);
1888:
1889: path = isUnique(path);
1890:
1891: return _lstat(path);
1892: } catch (Exception e) {
1893: if (e instanceof SftpException)
1894: throw (SftpException) e;
1895: if (e instanceof Throwable)
1896: throw new SftpException(SSH_FX_FAILURE, "",
1897: (Throwable) e);
1898: throw new SftpException(SSH_FX_FAILURE, "");
1899: }
1900: }
1901:
1902: private SftpATTRS _lstat(String path) throws SftpException {
1903: try {
1904: sendLSTAT(Util.str2byte(path, fEncoding));
1905:
1906: Header header = new Header();
1907: header = header(buf, header);
1908: int length = header.length;
1909: int type = header.type;
1910:
1911: fill(buf, length);
1912:
1913: if (type != SSH_FXP_ATTRS) {
1914: if (type == SSH_FXP_STATUS) {
1915: int i = buf.getInt();
1916: throwStatusError(buf, i);
1917: }
1918: throw new SftpException(SSH_FX_FAILURE, "");
1919: }
1920: SftpATTRS attr = SftpATTRS.getATTR(buf);
1921: return attr;
1922: } catch (Exception e) {
1923: if (e instanceof SftpException)
1924: throw (SftpException) e;
1925: if (e instanceof Throwable)
1926: throw new SftpException(SSH_FX_FAILURE, "",
1927: (Throwable) e);
1928: throw new SftpException(SSH_FX_FAILURE, "");
1929: }
1930: }
1931:
1932: private byte[] _realpath(String path) throws SftpException,
1933: IOException, Exception {
1934: sendREALPATH(Util.str2byte(path, fEncoding));
1935:
1936: Header header = new Header();
1937: header = header(buf, header);
1938: int length = header.length;
1939: int type = header.type;
1940:
1941: fill(buf, length);
1942:
1943: if (type != SSH_FXP_STATUS && type != SSH_FXP_NAME) {
1944: throw new SftpException(SSH_FX_FAILURE, "");
1945: }
1946: int i;
1947: if (type == SSH_FXP_STATUS) {
1948: i = buf.getInt();
1949: throwStatusError(buf, i);
1950: }
1951: i = buf.getInt(); // count
1952:
1953: byte[] str = null;
1954: while (i-- > 0) {
1955: str = buf.getString(); // absolute path;
1956: if (server_version <= 3) {
1957: byte[] lname = buf.getString(); // long filename
1958: }
1959: SftpATTRS attr = SftpATTRS.getATTR(buf); // dummy attribute
1960: }
1961: return str;
1962: }
1963:
1964: public void setStat(String path, SftpATTRS attr)
1965: throws SftpException {
1966: try {
1967: path = remoteAbsolutePath(path);
1968:
1969: Vector v = glob_remote(path);
1970: int vsize = v.size();
1971: for (int j = 0; j < vsize; j++) {
1972: path = (String) (v.elementAt(j));
1973: _setStat(path, attr);
1974: }
1975: } catch (Exception e) {
1976: if (e instanceof SftpException)
1977: throw (SftpException) e;
1978: if (e instanceof Throwable)
1979: throw new SftpException(SSH_FX_FAILURE, "",
1980: (Throwable) e);
1981: throw new SftpException(SSH_FX_FAILURE, "");
1982: }
1983: }
1984:
1985: private void _setStat(String path, SftpATTRS attr)
1986: throws SftpException {
1987: try {
1988: sendSETSTAT(Util.str2byte(path, fEncoding), attr);
1989:
1990: Header header = new Header();
1991: header = header(buf, header);
1992: int length = header.length;
1993: int type = header.type;
1994:
1995: fill(buf, length);
1996:
1997: if (type != SSH_FXP_STATUS) {
1998: throw new SftpException(SSH_FX_FAILURE, "");
1999: }
2000: int i = buf.getInt();
2001: if (i != SSH_FX_OK) {
2002: throwStatusError(buf, i);
2003: }
2004: } catch (Exception e) {
2005: if (e instanceof SftpException)
2006: throw (SftpException) e;
2007: if (e instanceof Throwable)
2008: throw new SftpException(SSH_FX_FAILURE, "",
2009: (Throwable) e);
2010: throw new SftpException(SSH_FX_FAILURE, "");
2011: }
2012: }
2013:
2014: public String pwd() throws SftpException {
2015: return getCwd();
2016: }
2017:
2018: public String lpwd() {
2019: return lcwd;
2020: }
2021:
2022: public String version() {
2023: return version;
2024: }
2025:
2026: public String getHome() throws SftpException {
2027: if (home == null) {
2028: try {
2029: byte[] _home = _realpath("");
2030: home = Util.byte2str(_home, fEncoding);
2031: } catch (Exception e) {
2032: if (e instanceof SftpException)
2033: throw (SftpException) e;
2034: if (e instanceof Throwable)
2035: throw new SftpException(SSH_FX_FAILURE, "",
2036: (Throwable) e);
2037: throw new SftpException(SSH_FX_FAILURE, "");
2038: }
2039: }
2040: return home;
2041: }
2042:
2043: private String getCwd() throws SftpException {
2044: if (cwd == null)
2045: cwd = getHome();
2046: return cwd;
2047: }
2048:
2049: private void setCwd(String cwd) {
2050: this .cwd = cwd;
2051: }
2052:
2053: private void read(byte[] buf, int s, int l) throws IOException,
2054: SftpException {
2055: int i = 0;
2056: while (l > 0) {
2057: i = io.in.read(buf, s, l);
2058: if (i <= 0) {
2059: throw new SftpException(SSH_FX_FAILURE, "");
2060: }
2061: s += i;
2062: l -= i;
2063: }
2064: }
2065:
2066: private boolean checkStatus(int[] ackid, Header header)
2067: throws IOException, SftpException {
2068: header = header(buf, header);
2069: int length = header.length;
2070: int type = header.type;
2071: if (ackid != null)
2072: ackid[0] = header.rid;
2073:
2074: fill(buf, length);
2075:
2076: if (type != SSH_FXP_STATUS) {
2077: throw new SftpException(SSH_FX_FAILURE, "");
2078: }
2079: int i = buf.getInt();
2080: if (i != SSH_FX_OK) {
2081: throwStatusError(buf, i);
2082: }
2083: return true;
2084: }
2085:
2086: private boolean _sendCLOSE(byte[] handle, Header header)
2087: throws Exception {
2088: sendCLOSE(handle);
2089: return checkStatus(null, header);
2090: }
2091:
2092: private void sendINIT() throws Exception {
2093: packet.reset();
2094: putHEAD(SSH_FXP_INIT, 5);
2095: buf.putInt(3); // version 3
2096: session.write(packet, this , 5 + 4);
2097: }
2098:
2099: private void sendREALPATH(byte[] path) throws Exception {
2100: sendPacketPath(SSH_FXP_REALPATH, path);
2101: }
2102:
2103: private void sendSTAT(byte[] path) throws Exception {
2104: sendPacketPath(SSH_FXP_STAT, path);
2105: }
2106:
2107: private void sendLSTAT(byte[] path) throws Exception {
2108: sendPacketPath(SSH_FXP_LSTAT, path);
2109: }
2110:
2111: private void sendFSTAT(byte[] handle) throws Exception {
2112: sendPacketPath(SSH_FXP_FSTAT, handle);
2113: }
2114:
2115: private void sendSETSTAT(byte[] path, SftpATTRS attr)
2116: throws Exception {
2117: packet.reset();
2118: putHEAD(SSH_FXP_SETSTAT, 9 + path.length + attr.length());
2119: buf.putInt(seq++);
2120: buf.putString(path); // path
2121: attr.dump(buf);
2122: session
2123: .write(packet, this , 9 + path.length + attr.length()
2124: + 4);
2125: }
2126:
2127: private void sendREMOVE(byte[] path) throws Exception {
2128: sendPacketPath(SSH_FXP_REMOVE, path);
2129: }
2130:
2131: private void sendMKDIR(byte[] path, SftpATTRS attr)
2132: throws Exception {
2133: packet.reset();
2134: putHEAD(SSH_FXP_MKDIR, 9 + path.length
2135: + (attr != null ? attr.length() : 4));
2136: buf.putInt(seq++);
2137: buf.putString(path); // path
2138: if (attr != null)
2139: attr.dump(buf);
2140: else
2141: buf.putInt(0);
2142: session.write(packet, this , 9 + path.length
2143: + (attr != null ? attr.length() : 4) + 4);
2144: }
2145:
2146: private void sendRMDIR(byte[] path) throws Exception {
2147: sendPacketPath(SSH_FXP_RMDIR, path);
2148: }
2149:
2150: private void sendSYMLINK(byte[] p1, byte[] p2) throws Exception {
2151: sendPacketPath(SSH_FXP_SYMLINK, p1, p2);
2152: }
2153:
2154: private void sendREADLINK(byte[] path) throws Exception {
2155: sendPacketPath(SSH_FXP_READLINK, path);
2156: }
2157:
2158: private void sendOPENDIR(byte[] path) throws Exception {
2159: sendPacketPath(SSH_FXP_OPENDIR, path);
2160: }
2161:
2162: private void sendREADDIR(byte[] path) throws Exception {
2163: sendPacketPath(SSH_FXP_READDIR, path);
2164: }
2165:
2166: private void sendRENAME(byte[] p1, byte[] p2) throws Exception {
2167: sendPacketPath(SSH_FXP_RENAME, p1, p2);
2168: }
2169:
2170: private void sendCLOSE(byte[] path) throws Exception {
2171: sendPacketPath(SSH_FXP_CLOSE, path);
2172: }
2173:
2174: private void sendOPENR(byte[] path) throws Exception {
2175: sendOPEN(path, SSH_FXF_READ);
2176: }
2177:
2178: private void sendOPENW(byte[] path) throws Exception {
2179: sendOPEN(path, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC);
2180: }
2181:
2182: private void sendOPENA(byte[] path) throws Exception {
2183: sendOPEN(path, SSH_FXF_WRITE
2184: | /*SSH_FXF_APPEND|*/SSH_FXF_CREAT);
2185: }
2186:
2187: private void sendOPEN(byte[] path, int mode) throws Exception {
2188: packet.reset();
2189: putHEAD(SSH_FXP_OPEN, 17 + path.length);
2190: buf.putInt(seq++);
2191: buf.putString(path);
2192: buf.putInt(mode);
2193: buf.putInt(0); // attrs
2194: session.write(packet, this , 17 + path.length + 4);
2195: }
2196:
2197: private void sendPacketPath(byte fxp, byte[] path) throws Exception {
2198: packet.reset();
2199: putHEAD(fxp, 9 + path.length);
2200: buf.putInt(seq++);
2201: buf.putString(path); // path
2202: session.write(packet, this , 9 + path.length + 4);
2203: }
2204:
2205: private void sendPacketPath(byte fxp, byte[] p1, byte[] p2)
2206: throws Exception {
2207: packet.reset();
2208: putHEAD(fxp, 13 + p1.length + p2.length);
2209: buf.putInt(seq++);
2210: buf.putString(p1);
2211: buf.putString(p2);
2212: session.write(packet, this , 13 + p1.length + p2.length + 4);
2213: }
2214:
2215: private int sendWRITE(byte[] handle, long offset, byte[] data,
2216: int start, int length) throws Exception {
2217: int _length = length;
2218: packet.reset();
2219: if (buf.buffer.length < buf.index + 13 + 21 + handle.length
2220: + length + 32 + 20 // padding and mac
2221: ) {
2222: _length = buf.buffer.length
2223: - (buf.index + 13 + 21 + handle.length + 32 + 20 // padding and mac
2224: );
2225: //System.err.println("_length="+_length+" length="+length);
2226: }
2227:
2228: putHEAD(SSH_FXP_WRITE, 21 + handle.length + _length); // 14
2229: buf.putInt(seq++); // 4
2230: buf.putString(handle); // 4+handle.length
2231: buf.putLong(offset); // 8
2232: if (buf.buffer != data) {
2233: buf.putString(data, start, _length); // 4+_length
2234: } else {
2235: buf.putInt(_length);
2236: buf.skip(_length);
2237: }
2238: session.write(packet, this , 21 + handle.length + _length + 4);
2239: return _length;
2240: }
2241:
2242: private void sendREAD(byte[] handle, long offset, int length)
2243: throws Exception {
2244: packet.reset();
2245: putHEAD(SSH_FXP_READ, 21 + handle.length);
2246: buf.putInt(seq++);
2247: buf.putString(handle);
2248: buf.putLong(offset);
2249: buf.putInt(length);
2250: session.write(packet, this , 21 + handle.length + 4);
2251: }
2252:
2253: private void putHEAD(byte type, int length) throws Exception {
2254: buf.putByte((byte) Session.SSH_MSG_CHANNEL_DATA);
2255: buf.putInt(recipient);
2256: buf.putInt(length + 4);
2257: buf.putInt(length);
2258: buf.putByte(type);
2259: }
2260:
2261: private Vector glob_remote(String _path) throws Exception {
2262:
2263: Vector v = new Vector();
2264: int i = 0;
2265:
2266: int foo = _path.lastIndexOf('/');
2267: if (foo < 0) { // it is not absolute path.
2268: v.addElement(Util.unquote(_path));
2269: return v;
2270: }
2271:
2272: String dir = _path.substring(0, ((foo == 0) ? 1 : foo));
2273: String _pattern = _path.substring(foo + 1);
2274:
2275: dir = Util.unquote(dir);
2276:
2277: byte[] pattern = null;
2278: byte[][] _pattern_utf8 = new byte[1][];
2279: boolean pattern_has_wildcard = isPattern(_pattern,
2280: _pattern_utf8);
2281:
2282: if (!pattern_has_wildcard) {
2283: if (dir.length() != 1) // not equal to "/"
2284: dir += "/";
2285: v.addElement(dir + Util.unquote(_pattern));
2286: return v;
2287: }
2288:
2289: pattern = _pattern_utf8[0];
2290:
2291: sendOPENDIR(Util.str2byte(dir, fEncoding));
2292:
2293: Header header = new Header();
2294: header = header(buf, header);
2295: int length = header.length;
2296: int type = header.type;
2297:
2298: fill(buf, length);
2299:
2300: if (type != SSH_FXP_STATUS && type != SSH_FXP_HANDLE) {
2301: throw new SftpException(SSH_FX_FAILURE, "");
2302: }
2303: if (type == SSH_FXP_STATUS) {
2304: i = buf.getInt();
2305: throwStatusError(buf, i);
2306: }
2307:
2308: byte[] handle = buf.getString(); // filename
2309: String pdir = null; // parent directory
2310:
2311: while (true) {
2312: sendREADDIR(handle);
2313: header = header(buf, header);
2314: length = header.length;
2315: type = header.type;
2316:
2317: if (type != SSH_FXP_STATUS && type != SSH_FXP_NAME) {
2318: throw new SftpException(SSH_FX_FAILURE, "");
2319: }
2320: if (type == SSH_FXP_STATUS) {
2321: fill(buf, length);
2322: break;
2323: }
2324:
2325: buf.rewind();
2326: fill(buf.buffer, 0, 4);
2327: length -= 4;
2328: int count = buf.getInt();
2329:
2330: byte[] str;
2331: int flags;
2332:
2333: buf.reset();
2334: while (count > 0) {
2335: if (length > 0) {
2336: buf.shift();
2337: int j = (buf.buffer.length > (buf.index + length)) ? length
2338: : (buf.buffer.length - buf.index);
2339: i = io.in.read(buf.buffer, buf.index, j);
2340: if (i <= 0)
2341: break;
2342: buf.index += i;
2343: length -= i;
2344: }
2345:
2346: byte[] filename = buf.getString();
2347: //System.err.println("filename: "+new String(filename));
2348: if (server_version <= 3) {
2349: str = buf.getString(); // longname
2350: }
2351: SftpATTRS attrs = SftpATTRS.getATTR(buf);
2352:
2353: byte[] _filename = filename;
2354: String f = null;
2355: boolean found = false;
2356:
2357: if (!fEncoding_is_utf8) {
2358: f = Util.byte2str(filename, fEncoding);
2359: _filename = Util.str2byte(f, UTF8);
2360: }
2361: found = Util.glob(pattern, _filename);
2362:
2363: if (found) {
2364: if (f == null) {
2365: f = Util.byte2str(filename, fEncoding);
2366: }
2367: if (pdir == null) {
2368: pdir = dir;
2369: if (!pdir.endsWith("/")) {
2370: pdir += "/";
2371: }
2372: }
2373: v.addElement(pdir + f);
2374: }
2375: count--;
2376: }
2377: }
2378: if (_sendCLOSE(handle, header))
2379: return v;
2380: return null;
2381: }
2382:
2383: private boolean isPattern(byte[] path) {
2384: int i = path.length - 1;
2385: while (i >= 0) {
2386: if (path[i] == '*' || path[i] == '?') {
2387: if (i > 0 && path[i - 1] == '\\') {
2388: i--;
2389: if (i > 0 && path[i - 1] == '\\') { // \\* or \\?
2390: break;
2391: }
2392: } else {
2393: break;
2394: }
2395: }
2396: i--;
2397: }
2398: // System.err.println("isPattern: ["+(new String(path))+"] "+(!(i<0)));
2399: return !(i < 0);
2400: }
2401:
2402: private Vector glob_local(String _path) throws Exception {
2403: //System.err.println("glob_local: "+_path);
2404: Vector v = new Vector();
2405: byte[] path = Util.str2byte(_path, UTF8);
2406: int i = path.length - 1;
2407: while (i >= 0) {
2408: if (path[i] != '*' && path[i] != '?') {
2409: i--;
2410: continue;
2411: }
2412: if (!fs_is_bs && i > 0 && path[i - 1] == '\\') {
2413: i--;
2414: if (i > 0 && path[i - 1] == '\\') {
2415: i--;
2416: i--;
2417: continue;
2418: }
2419: }
2420: break;
2421: }
2422:
2423: if (i < 0) {
2424: v.addElement(fs_is_bs ? _path : Util.unquote(_path));
2425: return v;
2426: }
2427:
2428: while (i >= 0) {
2429: if (path[i] == file_separatorc
2430: || (fs_is_bs && path[i] == '/')) { // On Windows, '/' is also the separator.
2431: break;
2432: }
2433: i--;
2434: }
2435:
2436: if (i < 0) {
2437: v.addElement(fs_is_bs ? _path : Util.unquote(_path));
2438: return v;
2439: }
2440:
2441: byte[] dir;
2442: if (i == 0) {
2443: dir = new byte[] { (byte) file_separatorc };
2444: } else {
2445: dir = new byte[i];
2446: System.arraycopy(path, 0, dir, 0, i);
2447: }
2448:
2449: byte[] pattern = new byte[path.length - i - 1];
2450: System.arraycopy(path, i + 1, pattern, 0, pattern.length);
2451:
2452: //System.err.println("dir: "+new String(dir)+" pattern: "+new String(pattern));
2453: try {
2454: String[] children = (new File(Util.byte2str(dir, UTF8)))
2455: .list();
2456: String pdir = Util.byte2str(dir) + file_separator;
2457: for (int j = 0; j < children.length; j++) {
2458: //System.err.println("children: "+children[j]);
2459: if (Util
2460: .glob(pattern, Util.str2byte(children[j], UTF8))) {
2461: v.addElement(pdir + children[j]);
2462: }
2463: }
2464: } catch (Exception e) {
2465: }
2466: return v;
2467: }
2468:
2469: private void throwStatusError(Buffer buf, int i)
2470: throws SftpException {
2471: if (server_version >= 3 && // WindRiver's sftp will send invalid
2472: buf.getLength() >= 4) { // SSH_FXP_STATUS packet.
2473: byte[] str = buf.getString();
2474: //byte[] tag=buf.getString();
2475: throw new SftpException(i, Util.byte2str(str, UTF8));
2476: } else {
2477: throw new SftpException(i, "Failure");
2478: }
2479: }
2480:
2481: private static boolean isLocalAbsolutePath(String path) {
2482: return (new File(path)).isAbsolute();
2483: }
2484:
2485: public void disconnect() {
2486: super .disconnect();
2487: }
2488:
2489: private boolean isPattern(String path, byte[][] utf8) {
2490: byte[] _path = Util.str2byte(path, UTF8);
2491: if (utf8 != null)
2492: utf8[0] = _path;
2493: return isPattern(_path);
2494: }
2495:
2496: private boolean isPattern(String path) {
2497: return isPattern(path, null);
2498: }
2499:
2500: private void fill(Buffer buf, int len) throws IOException {
2501: buf.reset();
2502: fill(buf.buffer, 0, len);
2503: buf.skip(len);
2504: }
2505:
2506: private int fill(byte[] buf, int s, int len) throws IOException {
2507: int i = 0;
2508: int foo = s;
2509: while (len > 0) {
2510: i = io.in.read(buf, s, len);
2511: if (i <= 0) {
2512: throw new IOException("inputstream is closed");
2513: //return (s-foo)==0 ? i : s-foo;
2514: }
2515: s += i;
2516: len -= i;
2517: }
2518: return s - foo;
2519: }
2520:
2521: private void skip(long foo) throws IOException {
2522: while (foo > 0) {
2523: long bar = io.in.skip(foo);
2524: if (bar <= 0)
2525: break;
2526: foo -= bar;
2527: }
2528: }
2529:
2530: class Header {
2531: int length;
2532: int type;
2533: int rid;
2534: }
2535:
2536: private Header header(Buffer buf, Header header) throws IOException {
2537: buf.rewind();
2538: int i = fill(buf.buffer, 0, 9);
2539: header.length = buf.getInt() - 5;
2540: header.type = buf.getByte() & 0xff;
2541: header.rid = buf.getInt();
2542: return header;
2543: }
2544:
2545: private String remoteAbsolutePath(String path) throws SftpException {
2546: if (path.charAt(0) == '/')
2547: return path;
2548: String cwd = getCwd();
2549: if (cwd.endsWith("/"))
2550: return cwd + path;
2551: return cwd + "/" + path;
2552: }
2553:
2554: private String localAbsolutePath(String path) {
2555: if (isLocalAbsolutePath(path))
2556: return path;
2557: if (lcwd.endsWith(file_separator))
2558: return lcwd + path;
2559: return lcwd + file_separator + path;
2560: }
2561:
2562: /**
2563: * This method will check if the given string can be expanded to the
2564: * unique string. If it can be expanded to mutiple files, SftpException
2565: * will be thrown.
2566: * @return the returned string is unquoted.
2567: */
2568: private String isUnique(String path) throws SftpException,
2569: Exception {
2570: Vector v = glob_remote(path);
2571: if (v.size() != 1) {
2572: throw new SftpException(SSH_FX_FAILURE, path
2573: + " is not unique: " + v.toString());
2574: }
2575: return (String) (v.elementAt(0));
2576: }
2577:
2578: public int getServerVersion() throws SftpException {
2579: if (!isConnected()) {
2580: throw new SftpException(SSH_FX_FAILURE,
2581: "The channel is not connected.");
2582: }
2583: return server_version;
2584: }
2585:
2586: public void setFilenameEncoding(String encoding)
2587: throws SftpException {
2588: int sversion = getServerVersion();
2589: if (sversion > 3 && !encoding.equals(UTF8)) {
2590: throw new SftpException(SSH_FX_FAILURE,
2591: "The encoding can not be changed for this sftp server.");
2592: }
2593: if (encoding.equals(UTF8)) {
2594: encoding = UTF8;
2595: }
2596: fEncoding = encoding;
2597: fEncoding_is_utf8 = fEncoding.equals(UTF8);
2598: }
2599:
2600: public String getExtension(String key) {
2601: if (extensions == null)
2602: return null;
2603: return (String) extensions.get(key);
2604: }
2605:
2606: public class LsEntry {
2607: private String filename;
2608: private String longname;
2609: private SftpATTRS attrs;
2610:
2611: LsEntry(String filename, String longname, SftpATTRS attrs) {
2612: setFilename(filename);
2613: setLongname(longname);
2614: setAttrs(attrs);
2615: }
2616:
2617: public String getFilename() {
2618: return filename;
2619: };
2620:
2621: void setFilename(String filename) {
2622: this .filename = filename;
2623: };
2624:
2625: public String getLongname() {
2626: return longname;
2627: };
2628:
2629: void setLongname(String longname) {
2630: this .longname = longname;
2631: };
2632:
2633: public SftpATTRS getAttrs() {
2634: return attrs;
2635: };
2636:
2637: void setAttrs(SftpATTRS attrs) {
2638: this .attrs = attrs;
2639: };
2640:
2641: public String toString() {
2642: return longname;
2643: }
2644: }
2645: }
|