Source Code Cross Referenced for SFTPv3Client.java in  » Net » Ganymed-SSH-2 » ch » ethz » ssh2 » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » Ganymed SSH 2 » ch.ethz.ssh2 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package ch.ethz.ssh2;
0002:
0003:        import java.io.BufferedOutputStream;
0004:        import java.io.IOException;
0005:        import java.io.InputStream;
0006:        import java.io.OutputStream;
0007:        import java.io.PrintStream;
0008:        import java.nio.charset.Charset;
0009:        import java.util.HashMap;
0010:        import java.util.Vector;
0011:
0012:        import ch.ethz.ssh2.packets.TypesReader;
0013:        import ch.ethz.ssh2.packets.TypesWriter;
0014:        import ch.ethz.ssh2.sftp.AttribFlags;
0015:        import ch.ethz.ssh2.sftp.ErrorCodes;
0016:        import ch.ethz.ssh2.sftp.Packet;
0017:
0018:        /**
0019:         * A <code>SFTPv3Client</code> represents a SFTP (protocol version 3)
0020:         * client connection tunnelled over a SSH-2 connection. This is a very simple
0021:         * (synchronous) implementation.
0022:         * <p>
0023:         * Basically, most methods in this class map directly to one of
0024:         * the packet types described in draft-ietf-secsh-filexfer-02.txt.
0025:         * <p>
0026:         * Note: this is experimental code.
0027:         * <p>
0028:         * Error handling: the methods of this class throw IOExceptions. However, unless
0029:         * there is catastrophic failure, exceptions of the type {@link SFTPv3Client} will
0030:         * be thrown (a subclass of IOException). Therefore, you can implement more verbose
0031:         * behavior by checking if a thrown exception if of this type. If yes, then you
0032:         * can cast the exception and access detailed information about the failure. 
0033:         * <p>
0034:         * Notes about file names, directory names and paths, copy-pasted
0035:         * from the specs:
0036:         * <ul>
0037:         * <li>SFTP v3 represents file names as strings. File names are
0038:         * assumed to use the slash ('/') character as a directory separator.</li>
0039:         * <li>File names starting with a slash are "absolute", and are relative to
0040:         * the root of the file system.  Names starting with any other character
0041:         * are relative to the user's default directory (home directory).</li>
0042:         * <li>Servers SHOULD interpret a path name component ".." as referring to
0043:         * the parent directory, and "." as referring to the current directory.
0044:         * If the server implementation limits access to certain parts of the
0045:         * file system, it must be extra careful in parsing file names when
0046:         * enforcing such restrictions.  There have been numerous reported
0047:         * security bugs where a ".." in a path name has allowed access outside
0048:         * the intended area.</li>
0049:         * <li>An empty path name is valid, and it refers to the user's default
0050:         * directory (usually the user's home directory).</li>
0051:         * </ul>
0052:         * <p>
0053:         * If you are still not tired then please go on and read the comment for
0054:         * {@link #setCharset(String)}.
0055:         * 
0056:         * @author Christian Plattner, plattner@inf.ethz.ch
0057:         * @version $Id: SFTPv3Client.java,v 1.9 2006/09/20 12:51:37 cplattne Exp $
0058:         */
0059:        public class SFTPv3Client {
0060:            final Connection conn;
0061:            final Session sess;
0062:            final PrintStream debug;
0063:
0064:            boolean flag_closed = false;
0065:
0066:            InputStream is;
0067:            OutputStream os;
0068:
0069:            int protocol_version = 0;
0070:            HashMap server_extensions = new HashMap();
0071:
0072:            int next_request_id = 1000;
0073:
0074:            String charsetName = null;
0075:
0076:            /**
0077:             * Create a SFTP v3 client.
0078:             * 
0079:             * @param conn The underlying SSH-2 connection to be used.
0080:             * @param debug
0081:             * @throws IOException
0082:             * 
0083:             * @deprecated this constructor (debug version) will disappear in the future,
0084:             *             use {@link #SFTPv3Client(Connection)} instead.
0085:             */
0086:            public SFTPv3Client(Connection conn, PrintStream debug)
0087:                    throws IOException {
0088:                if (conn == null)
0089:                    throw new IllegalArgumentException(
0090:                            "Cannot accept null argument!");
0091:
0092:                this .conn = conn;
0093:                this .debug = debug;
0094:
0095:                if (debug != null)
0096:                    debug
0097:                            .println("Opening session and starting SFTP subsystem.");
0098:
0099:                sess = conn.openSession();
0100:                sess.startSubSystem("sftp");
0101:
0102:                is = sess.getStdout();
0103:                os = new BufferedOutputStream(sess.getStdin(), 2048);
0104:
0105:                if ((is == null) || (os == null))
0106:                    throw new IOException(
0107:                            "There is a problem with the streams of the underlying channel.");
0108:
0109:                init();
0110:            }
0111:
0112:            /**
0113:             * Create a SFTP v3 client.
0114:             * 
0115:             * @param conn The underlying SSH-2 connection to be used.
0116:             * @throws IOException
0117:             */
0118:            public SFTPv3Client(Connection conn) throws IOException {
0119:                this (conn, null);
0120:            }
0121:
0122:            /**
0123:             * Set the charset used to convert between Java Unicode Strings and byte encodings
0124:             * used by the server for paths and file names. Unfortunately, the SFTP v3 draft
0125:             * says NOTHING about such conversions (well, with the exception of error messages
0126:             * which have to be in UTF-8). Newer drafts specify to use UTF-8 for file names
0127:             * (if I remember correctly). However, a quick test using OpenSSH serving a EXT-3
0128:             * filesystem has shown that UTF-8 seems to be a bad choice for SFTP v3 (tested with
0129:             * filenames containing german umlauts). "windows-1252" seems to work better for Europe.
0130:             * Luckily, "windows-1252" is the platform default in my case =).
0131:             * <p>
0132:             * If you don't set anything, then the platform default will be used (this is the default
0133:             * behavior).
0134:             * 
0135:             * @see #getCharset()
0136:             * 
0137:             * @param charset the name of the charset to be used or <code>null</code> to use the platform's
0138:             *        default encoding.
0139:             * @throws IOException
0140:             */
0141:            public void setCharset(String charset) throws IOException {
0142:                if (charset == null) {
0143:                    charsetName = charset;
0144:                    return;
0145:                }
0146:
0147:                try {
0148:                    Charset.forName(charset);
0149:                } catch (Exception e) {
0150:                    throw (IOException) new IOException(
0151:                            "This charset is not supported").initCause(e);
0152:                }
0153:                charsetName = charset;
0154:            }
0155:
0156:            /**
0157:             * The currently used charset for filename encoding/decoding.
0158:             * 
0159:             * @see #setCharset(String)
0160:             * 
0161:             * @return The name of the charset (<code>null</code> if the platform's default charset is being used)
0162:             */
0163:            public String getCharset() {
0164:                return charsetName;
0165:            }
0166:
0167:            private final void checkHandleValidAndOpen(SFTPv3FileHandle handle)
0168:                    throws IOException {
0169:                if (handle.client != this )
0170:                    throw new IOException(
0171:                            "The file handle was created with another SFTPv3FileHandle instance.");
0172:
0173:                if (handle.isClosed == true)
0174:                    throw new IOException("The file handle is closed.");
0175:            }
0176:
0177:            private final void sendMessage(int type, int requestId, byte[] msg,
0178:                    int off, int len) throws IOException {
0179:                int msglen = len + 1;
0180:
0181:                if (type != Packet.SSH_FXP_INIT)
0182:                    msglen += 4;
0183:
0184:                os.write(msglen >> 24);
0185:                os.write(msglen >> 16);
0186:                os.write(msglen >> 8);
0187:                os.write(msglen);
0188:                os.write(type);
0189:
0190:                if (type != Packet.SSH_FXP_INIT) {
0191:                    os.write(requestId >> 24);
0192:                    os.write(requestId >> 16);
0193:                    os.write(requestId >> 8);
0194:                    os.write(requestId);
0195:                }
0196:
0197:                os.write(msg, off, len);
0198:                os.flush();
0199:            }
0200:
0201:            private final void sendMessage(int type, int requestId, byte[] msg)
0202:                    throws IOException {
0203:                sendMessage(type, requestId, msg, 0, msg.length);
0204:            }
0205:
0206:            private final void readBytes(byte[] buff, int pos, int len)
0207:                    throws IOException {
0208:                while (len > 0) {
0209:                    int count = is.read(buff, pos, len);
0210:                    if (count < 0)
0211:                        throw new IOException("Unexpected end of sftp stream.");
0212:                    if ((count == 0) || (count > len))
0213:                        throw new IOException(
0214:                                "Underlying stream implementation is bogus!");
0215:                    len -= count;
0216:                    pos += count;
0217:                }
0218:            }
0219:
0220:            /**
0221:             * Read a message and guarantee that the <b>contents</b> is not larger than
0222:             * <code>maxlen</code> bytes.
0223:             * <p>
0224:             * Note: receiveMessage(34000) actually means that the message may be up to 34004
0225:             * bytes (the length attribute preceeding the contents is 4 bytes).
0226:             * 
0227:             * @param maxlen
0228:             * @return the message contents
0229:             * @throws IOException
0230:             */
0231:            private final byte[] receiveMessage(int maxlen) throws IOException {
0232:                byte[] msglen = new byte[4];
0233:
0234:                readBytes(msglen, 0, 4);
0235:
0236:                int len = (((msglen[0] & 0xff) << 24)
0237:                        | ((msglen[1] & 0xff) << 16)
0238:                        | ((msglen[2] & 0xff) << 8) | (msglen[3] & 0xff));
0239:
0240:                if ((len > maxlen) || (len <= 0))
0241:                    throw new IOException("Illegal sftp packet len: " + len);
0242:
0243:                byte[] msg = new byte[len];
0244:
0245:                readBytes(msg, 0, len);
0246:
0247:                return msg;
0248:            }
0249:
0250:            private final int generateNextRequestID() {
0251:                synchronized (this ) {
0252:                    return next_request_id++;
0253:                }
0254:            }
0255:
0256:            private final void closeHandle(byte[] handle) throws IOException {
0257:                int req_id = generateNextRequestID();
0258:
0259:                TypesWriter tw = new TypesWriter();
0260:                tw.writeString(handle, 0, handle.length);
0261:
0262:                sendMessage(Packet.SSH_FXP_CLOSE, req_id, tw.getBytes());
0263:
0264:                expectStatusOKMessage(req_id);
0265:            }
0266:
0267:            private SFTPv3FileAttributes readAttrs(TypesReader tr)
0268:                    throws IOException {
0269:                /*
0270:                 * uint32   flags
0271:                 * uint64   size           present only if flag SSH_FILEXFER_ATTR_SIZE
0272:                 * uint32   uid            present only if flag SSH_FILEXFER_ATTR_V3_UIDGID
0273:                 * uint32   gid            present only if flag SSH_FILEXFER_ATTR_V3_UIDGID
0274:                 * uint32   permissions    present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
0275:                 * uint32   atime          present only if flag SSH_FILEXFER_ATTR_V3_ACMODTIME
0276:                 * uint32   mtime          present only if flag SSH_FILEXFER_ATTR_V3_ACMODTIME
0277:                 * uint32   extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
0278:                 * string   extended_type
0279:                 * string   extended_data
0280:                 * ...      more extended data (extended_type - extended_data pairs),
0281:                 *          so that number of pairs equals extended_count
0282:                 */
0283:
0284:                SFTPv3FileAttributes fa = new SFTPv3FileAttributes();
0285:
0286:                int flags = tr.readUINT32();
0287:
0288:                if ((flags & AttribFlags.SSH_FILEXFER_ATTR_SIZE) != 0) {
0289:                    if (debug != null)
0290:                        debug.println("SSH_FILEXFER_ATTR_SIZE");
0291:                    fa.size = new Long(tr.readUINT64());
0292:                }
0293:
0294:                if ((flags & AttribFlags.SSH_FILEXFER_ATTR_V3_UIDGID) != 0) {
0295:                    if (debug != null)
0296:                        debug.println("SSH_FILEXFER_ATTR_V3_UIDGID");
0297:                    fa.uid = new Integer(tr.readUINT32());
0298:                    fa.gid = new Integer(tr.readUINT32());
0299:                }
0300:
0301:                if ((flags & AttribFlags.SSH_FILEXFER_ATTR_PERMISSIONS) != 0) {
0302:                    if (debug != null)
0303:                        debug.println("SSH_FILEXFER_ATTR_PERMISSIONS");
0304:                    fa.permissions = new Integer(tr.readUINT32());
0305:                }
0306:
0307:                if ((flags & AttribFlags.SSH_FILEXFER_ATTR_V3_ACMODTIME) != 0) {
0308:                    if (debug != null)
0309:                        debug.println("SSH_FILEXFER_ATTR_V3_ACMODTIME");
0310:                    fa.atime = new Integer(tr.readUINT32());
0311:                    fa.mtime = new Integer(tr.readUINT32());
0312:
0313:                }
0314:
0315:                if ((flags & AttribFlags.SSH_FILEXFER_ATTR_EXTENDED) != 0) {
0316:                    int count = tr.readUINT32();
0317:
0318:                    if (debug != null)
0319:                        debug.println("SSH_FILEXFER_ATTR_EXTENDED (" + count
0320:                                + ")");
0321:
0322:                    /* Read it anyway to detect corrupt packets */
0323:
0324:                    while (count > 0) {
0325:                        tr.readByteString();
0326:                        tr.readByteString();
0327:                        count--;
0328:                    }
0329:                }
0330:
0331:                return fa;
0332:            }
0333:
0334:            /**
0335:             * Retrieve the file attributes of an open file.
0336:             * 
0337:             * @param handle a SFTPv3FileHandle handle.
0338:             * @return a SFTPv3FileAttributes object.
0339:             * @throws IOException
0340:             */
0341:            public SFTPv3FileAttributes fstat(SFTPv3FileHandle handle)
0342:                    throws IOException {
0343:                checkHandleValidAndOpen(handle);
0344:
0345:                int req_id = generateNextRequestID();
0346:
0347:                TypesWriter tw = new TypesWriter();
0348:                tw.writeString(handle.fileHandle, 0, handle.fileHandle.length);
0349:
0350:                if (debug != null) {
0351:                    debug.println("Sending SSH_FXP_FSTAT...");
0352:                    debug.flush();
0353:                }
0354:
0355:                sendMessage(Packet.SSH_FXP_FSTAT, req_id, tw.getBytes());
0356:
0357:                byte[] resp = receiveMessage(34000);
0358:
0359:                if (debug != null) {
0360:                    debug.println("Got REPLY.");
0361:                    debug.flush();
0362:                }
0363:
0364:                TypesReader tr = new TypesReader(resp);
0365:
0366:                int t = tr.readByte();
0367:
0368:                int rep_id = tr.readUINT32();
0369:                if (rep_id != req_id)
0370:                    throw new IOException(
0371:                            "The server sent an invalid id field.");
0372:
0373:                if (t == Packet.SSH_FXP_ATTRS) {
0374:                    return readAttrs(tr);
0375:                }
0376:
0377:                if (t != Packet.SSH_FXP_STATUS)
0378:                    throw new IOException(
0379:                            "The SFTP server sent an unexpected packet type ("
0380:                                    + t + ")");
0381:
0382:                int errorCode = tr.readUINT32();
0383:
0384:                throw new SFTPException(tr.readString(), errorCode);
0385:            }
0386:
0387:            private SFTPv3FileAttributes statBoth(String path, int statMethod)
0388:                    throws IOException {
0389:                int req_id = generateNextRequestID();
0390:
0391:                TypesWriter tw = new TypesWriter();
0392:                tw.writeString(path, charsetName);
0393:
0394:                if (debug != null) {
0395:                    debug.println("Sending SSH_FXP_STAT/SSH_FXP_LSTAT...");
0396:                    debug.flush();
0397:                }
0398:
0399:                sendMessage(statMethod, req_id, tw.getBytes());
0400:
0401:                byte[] resp = receiveMessage(34000);
0402:
0403:                if (debug != null) {
0404:                    debug.println("Got REPLY.");
0405:                    debug.flush();
0406:                }
0407:
0408:                TypesReader tr = new TypesReader(resp);
0409:
0410:                int t = tr.readByte();
0411:
0412:                int rep_id = tr.readUINT32();
0413:                if (rep_id != req_id)
0414:                    throw new IOException(
0415:                            "The server sent an invalid id field.");
0416:
0417:                if (t == Packet.SSH_FXP_ATTRS) {
0418:                    return readAttrs(tr);
0419:                }
0420:
0421:                if (t != Packet.SSH_FXP_STATUS)
0422:                    throw new IOException(
0423:                            "The SFTP server sent an unexpected packet type ("
0424:                                    + t + ")");
0425:
0426:                int errorCode = tr.readUINT32();
0427:
0428:                throw new SFTPException(tr.readString(), errorCode);
0429:            }
0430:
0431:            /**
0432:             * Retrieve the file attributes of a file. This method
0433:             * follows symbolic links on the server.
0434:             * 
0435:             * @see #lstat(String)
0436:             * 
0437:             * @param path See the {@link SFTPv3Client comment} for the class for more details.
0438:             * @return a SFTPv3FileAttributes object.
0439:             * @throws IOException
0440:             */
0441:            public SFTPv3FileAttributes stat(String path) throws IOException {
0442:                return statBoth(path, Packet.SSH_FXP_STAT);
0443:            }
0444:
0445:            /**
0446:             * Retrieve the file attributes of a file. This method
0447:             * does NOT follow symbolic links on the server.
0448:             * 
0449:             * @see #stat(String)
0450:             * 
0451:             * @param path See the {@link SFTPv3Client comment} for the class for more details.
0452:             * @return a SFTPv3FileAttributes object.
0453:             * @throws IOException
0454:             */
0455:            public SFTPv3FileAttributes lstat(String path) throws IOException {
0456:                return statBoth(path, Packet.SSH_FXP_LSTAT);
0457:            }
0458:
0459:            /**
0460:             * Read the target of a symbolic link.
0461:             * 
0462:             * @param path See the {@link SFTPv3Client comment} for the class for more details.
0463:             * @return The target of the link.
0464:             * @throws IOException
0465:             */
0466:            public String readLink(String path) throws IOException {
0467:                int req_id = generateNextRequestID();
0468:
0469:                TypesWriter tw = new TypesWriter();
0470:                tw.writeString(path, charsetName);
0471:
0472:                if (debug != null) {
0473:                    debug.println("Sending SSH_FXP_READLINK...");
0474:                    debug.flush();
0475:                }
0476:
0477:                sendMessage(Packet.SSH_FXP_READLINK, req_id, tw.getBytes());
0478:
0479:                byte[] resp = receiveMessage(34000);
0480:
0481:                if (debug != null) {
0482:                    debug.println("Got REPLY.");
0483:                    debug.flush();
0484:                }
0485:
0486:                TypesReader tr = new TypesReader(resp);
0487:
0488:                int t = tr.readByte();
0489:
0490:                int rep_id = tr.readUINT32();
0491:                if (rep_id != req_id)
0492:                    throw new IOException(
0493:                            "The server sent an invalid id field.");
0494:
0495:                if (t == Packet.SSH_FXP_NAME) {
0496:                    int count = tr.readUINT32();
0497:
0498:                    if (count != 1)
0499:                        throw new IOException(
0500:                                "The server sent an invalid SSH_FXP_NAME packet.");
0501:
0502:                    return tr.readString(charsetName);
0503:                }
0504:
0505:                if (t != Packet.SSH_FXP_STATUS)
0506:                    throw new IOException(
0507:                            "The SFTP server sent an unexpected packet type ("
0508:                                    + t + ")");
0509:
0510:                int errorCode = tr.readUINT32();
0511:
0512:                throw new SFTPException(tr.readString(), errorCode);
0513:            }
0514:
0515:            private void expectStatusOKMessage(int id) throws IOException {
0516:                byte[] resp = receiveMessage(34000);
0517:
0518:                if (debug != null) {
0519:                    debug.println("Got REPLY.");
0520:                    debug.flush();
0521:                }
0522:
0523:                TypesReader tr = new TypesReader(resp);
0524:
0525:                int t = tr.readByte();
0526:
0527:                int rep_id = tr.readUINT32();
0528:                if (rep_id != id)
0529:                    throw new IOException(
0530:                            "The server sent an invalid id field.");
0531:
0532:                if (t != Packet.SSH_FXP_STATUS)
0533:                    throw new IOException(
0534:                            "The SFTP server sent an unexpected packet type ("
0535:                                    + t + ")");
0536:
0537:                int errorCode = tr.readUINT32();
0538:
0539:                if (errorCode == ErrorCodes.SSH_FX_OK)
0540:                    return;
0541:
0542:                throw new SFTPException(tr.readString(), errorCode);
0543:            }
0544:
0545:            /**
0546:             *  Modify the attributes of a file. Used for operations such as changing
0547:             *  the ownership, permissions or access times, as well as for truncating a file.
0548:             * 
0549:             * @param path See the {@link SFTPv3Client comment} for the class for more details.
0550:             * @param attr A SFTPv3FileAttributes object. Specifies the modifications to be
0551:             *             made to the attributes of the file. Empty fields will be ignored.
0552:             * @throws IOException
0553:             */
0554:            public void setstat(String path, SFTPv3FileAttributes attr)
0555:                    throws IOException {
0556:                int req_id = generateNextRequestID();
0557:
0558:                TypesWriter tw = new TypesWriter();
0559:                tw.writeString(path, charsetName);
0560:                tw.writeBytes(createAttrs(attr));
0561:
0562:                if (debug != null) {
0563:                    debug.println("Sending SSH_FXP_SETSTAT...");
0564:                    debug.flush();
0565:                }
0566:
0567:                sendMessage(Packet.SSH_FXP_SETSTAT, req_id, tw.getBytes());
0568:
0569:                expectStatusOKMessage(req_id);
0570:            }
0571:
0572:            /**
0573:             * 	Modify the attributes of a file. Used for operations such as changing
0574:             *  the ownership, permissions or access times, as well as for truncating a file.
0575:             * 
0576:             * @param handle a SFTPv3FileHandle handle
0577:             * @param attr A SFTPv3FileAttributes object. Specifies the modifications to be
0578:             *             made to the attributes of the file. Empty fields will be ignored.
0579:             * @throws IOException
0580:             */
0581:            public void fsetstat(SFTPv3FileHandle handle,
0582:                    SFTPv3FileAttributes attr) throws IOException {
0583:                checkHandleValidAndOpen(handle);
0584:
0585:                int req_id = generateNextRequestID();
0586:
0587:                TypesWriter tw = new TypesWriter();
0588:                tw.writeString(handle.fileHandle, 0, handle.fileHandle.length);
0589:                tw.writeBytes(createAttrs(attr));
0590:
0591:                if (debug != null) {
0592:                    debug.println("Sending SSH_FXP_FSETSTAT...");
0593:                    debug.flush();
0594:                }
0595:
0596:                sendMessage(Packet.SSH_FXP_FSETSTAT, req_id, tw.getBytes());
0597:
0598:                expectStatusOKMessage(req_id);
0599:            }
0600:
0601:            /**
0602:             * Create a symbolic link on the server. Creates a link "src" that points
0603:             * to "target".
0604:             * 
0605:             * @param src See the {@link SFTPv3Client comment} for the class for more details.
0606:             * @param target See the {@link SFTPv3Client comment} for the class for more details.
0607:             * @throws IOException
0608:             */
0609:            public void createSymlink(String src, String target)
0610:                    throws IOException {
0611:                int req_id = generateNextRequestID();
0612:
0613:                /* Either I am too stupid to understand the SFTP draft
0614:                 * or the OpenSSH guys changed the semantics of src and target.
0615:                 */
0616:
0617:                TypesWriter tw = new TypesWriter();
0618:                tw.writeString(target, charsetName);
0619:                tw.writeString(src, charsetName);
0620:
0621:                if (debug != null) {
0622:                    debug.println("Sending SSH_FXP_SYMLINK...");
0623:                    debug.flush();
0624:                }
0625:
0626:                sendMessage(Packet.SSH_FXP_SYMLINK, req_id, tw.getBytes());
0627:
0628:                expectStatusOKMessage(req_id);
0629:            }
0630:
0631:            /**
0632:             * Have the server canonicalize any given path name to an absolute path.
0633:             * This is useful for converting path names containing ".." components or
0634:             * relative pathnames without a leading slash into absolute paths.
0635:             * 
0636:             * @param path See the {@link SFTPv3Client comment} for the class for more details.
0637:             * @return An absolute path.
0638:             * @throws IOException
0639:             */
0640:            public String canonicalPath(String path) throws IOException {
0641:                int req_id = generateNextRequestID();
0642:
0643:                TypesWriter tw = new TypesWriter();
0644:                tw.writeString(path, charsetName);
0645:
0646:                if (debug != null) {
0647:                    debug.println("Sending SSH_FXP_REALPATH...");
0648:                    debug.flush();
0649:                }
0650:
0651:                sendMessage(Packet.SSH_FXP_REALPATH, req_id, tw.getBytes());
0652:
0653:                byte[] resp = receiveMessage(34000);
0654:
0655:                if (debug != null) {
0656:                    debug.println("Got REPLY.");
0657:                    debug.flush();
0658:                }
0659:
0660:                TypesReader tr = new TypesReader(resp);
0661:
0662:                int t = tr.readByte();
0663:
0664:                int rep_id = tr.readUINT32();
0665:                if (rep_id != req_id)
0666:                    throw new IOException(
0667:                            "The server sent an invalid id field.");
0668:
0669:                if (t == Packet.SSH_FXP_NAME) {
0670:                    int count = tr.readUINT32();
0671:
0672:                    if (count != 1)
0673:                        throw new IOException(
0674:                                "The server sent an invalid SSH_FXP_NAME packet.");
0675:
0676:                    return tr.readString(charsetName);
0677:                }
0678:
0679:                if (t != Packet.SSH_FXP_STATUS)
0680:                    throw new IOException(
0681:                            "The SFTP server sent an unexpected packet type ("
0682:                                    + t + ")");
0683:
0684:                int errorCode = tr.readUINT32();
0685:
0686:                throw new SFTPException(tr.readString(), errorCode);
0687:            }
0688:
0689:            private final Vector scanDirectory(byte[] handle)
0690:                    throws IOException {
0691:                Vector files = new Vector();
0692:
0693:                while (true) {
0694:                    int req_id = generateNextRequestID();
0695:
0696:                    TypesWriter tw = new TypesWriter();
0697:                    tw.writeString(handle, 0, handle.length);
0698:
0699:                    if (debug != null) {
0700:                        debug.println("Sending SSH_FXP_READDIR...");
0701:                        debug.flush();
0702:                    }
0703:
0704:                    sendMessage(Packet.SSH_FXP_READDIR, req_id, tw.getBytes());
0705:
0706:                    byte[] resp = receiveMessage(34000);
0707:
0708:                    if (debug != null) {
0709:                        debug.println("Got REPLY.");
0710:                        debug.flush();
0711:                    }
0712:
0713:                    TypesReader tr = new TypesReader(resp);
0714:
0715:                    int t = tr.readByte();
0716:
0717:                    int rep_id = tr.readUINT32();
0718:                    if (rep_id != req_id)
0719:                        throw new IOException(
0720:                                "The server sent an invalid id field.");
0721:
0722:                    if (t == Packet.SSH_FXP_NAME) {
0723:                        int count = tr.readUINT32();
0724:
0725:                        if (debug != null)
0726:                            debug.println("Parsing " + count
0727:                                    + " name entries...");
0728:
0729:                        while (count > 0) {
0730:                            SFTPv3DirectoryEntry dirEnt = new SFTPv3DirectoryEntry();
0731:
0732:                            dirEnt.filename = tr.readString(charsetName);
0733:                            dirEnt.longEntry = tr.readString(charsetName);
0734:
0735:                            dirEnt.attributes = readAttrs(tr);
0736:                            files.addElement(dirEnt);
0737:
0738:                            if (debug != null)
0739:                                debug
0740:                                        .println("File: '" + dirEnt.filename
0741:                                                + "'");
0742:                            count--;
0743:                        }
0744:                        continue;
0745:                    }
0746:
0747:                    if (t != Packet.SSH_FXP_STATUS)
0748:                        throw new IOException(
0749:                                "The SFTP server sent an unexpected packet type ("
0750:                                        + t + ")");
0751:
0752:                    int errorCode = tr.readUINT32();
0753:
0754:                    if (errorCode == ErrorCodes.SSH_FX_EOF)
0755:                        return files;
0756:
0757:                    throw new SFTPException(tr.readString(), errorCode);
0758:                }
0759:            }
0760:
0761:            private final byte[] openDirectory(String path) throws IOException {
0762:                int req_id = generateNextRequestID();
0763:
0764:                TypesWriter tw = new TypesWriter();
0765:                tw.writeString(path, charsetName);
0766:
0767:                if (debug != null) {
0768:                    debug.println("Sending SSH_FXP_OPENDIR...");
0769:                    debug.flush();
0770:                }
0771:
0772:                sendMessage(Packet.SSH_FXP_OPENDIR, req_id, tw.getBytes());
0773:
0774:                byte[] resp = receiveMessage(34000);
0775:
0776:                TypesReader tr = new TypesReader(resp);
0777:
0778:                int t = tr.readByte();
0779:
0780:                int rep_id = tr.readUINT32();
0781:                if (rep_id != req_id)
0782:                    throw new IOException(
0783:                            "The server sent an invalid id field.");
0784:
0785:                if (t == Packet.SSH_FXP_HANDLE) {
0786:                    if (debug != null) {
0787:                        debug.println("Got SSH_FXP_HANDLE.");
0788:                        debug.flush();
0789:                    }
0790:
0791:                    byte[] handle = tr.readByteString();
0792:                    return handle;
0793:                }
0794:
0795:                if (t != Packet.SSH_FXP_STATUS)
0796:                    throw new IOException(
0797:                            "The SFTP server sent an unexpected packet type ("
0798:                                    + t + ")");
0799:
0800:                int errorCode = tr.readUINT32();
0801:                String errorMessage = tr.readString();
0802:
0803:                throw new SFTPException(errorMessage, errorCode);
0804:            }
0805:
0806:            private final String expandString(byte[] b, int off, int len) {
0807:                StringBuffer sb = new StringBuffer();
0808:
0809:                for (int i = 0; i < len; i++) {
0810:                    int c = b[off + i] & 0xff;
0811:
0812:                    if ((c >= 32) && (c <= 126)) {
0813:                        sb.append((char) c);
0814:                    } else {
0815:                        sb.append("{0x" + Integer.toHexString(c) + "}");
0816:                    }
0817:                }
0818:
0819:                return sb.toString();
0820:            }
0821:
0822:            private void init() throws IOException {
0823:                /* Send SSH_FXP_INIT (version 3) */
0824:
0825:                final int client_version = 3;
0826:
0827:                if (debug != null)
0828:                    debug.println("Sending SSH_FXP_INIT (" + client_version
0829:                            + ")...");
0830:
0831:                TypesWriter tw = new TypesWriter();
0832:                tw.writeUINT32(client_version);
0833:                sendMessage(Packet.SSH_FXP_INIT, 0, tw.getBytes());
0834:
0835:                /* Receive SSH_FXP_VERSION */
0836:
0837:                if (debug != null)
0838:                    debug.println("Waiting for SSH_FXP_VERSION...");
0839:
0840:                TypesReader tr = new TypesReader(receiveMessage(34000)); /* Should be enough for any reasonable server */
0841:
0842:                int type = tr.readByte();
0843:
0844:                if (type != Packet.SSH_FXP_VERSION) {
0845:                    throw new IOException(
0846:                            "The server did not send a SSH_FXP_VERSION packet (got "
0847:                                    + type + ")");
0848:                }
0849:
0850:                protocol_version = tr.readUINT32();
0851:
0852:                if (debug != null)
0853:                    debug.println("SSH_FXP_VERSION: protocol_version = "
0854:                            + protocol_version);
0855:
0856:                if (protocol_version != 3)
0857:                    throw new IOException("Server version " + protocol_version
0858:                            + " is currently not supported");
0859:
0860:                /* Read and save extensions (if any) for later use */
0861:
0862:                while (tr.remain() != 0) {
0863:                    String name = tr.readString();
0864:                    byte[] value = tr.readByteString();
0865:                    server_extensions.put(name, value);
0866:
0867:                    if (debug != null)
0868:                        debug.println("SSH_FXP_VERSION: extension: " + name
0869:                                + " = '" + expandString(value, 0, value.length)
0870:                                + "'");
0871:                }
0872:            }
0873:
0874:            /**
0875:             * Returns the negotiated SFTP protocol version between the client and the server.
0876:             * 
0877:             * @return SFTP protocol version, i.e., "3".
0878:             * 
0879:             */
0880:            public int getProtocolVersion() {
0881:                return protocol_version;
0882:            }
0883:
0884:            /**
0885:             * Close this SFTP session. NEVER forget to call this method to free up
0886:             * resources - even if you got an exception from one of the other methods.
0887:             * Sometimes these other methods may throw an exception, saying that the
0888:             * underlying channel is closed (this can happen, e.g., if the other server
0889:             * sent a close message.) However, as long as you have not called the
0890:             * <code>close()</code> method, you are likely wasting resources.
0891:             * 
0892:             */
0893:            public void close() {
0894:                sess.close();
0895:            }
0896:
0897:            /**
0898:             * List the contents of a directory.
0899:             * 
0900:             * @param dirName See the {@link SFTPv3Client comment} for the class for more details.
0901:             * @return A Vector containing {@link SFTPv3DirectoryEntry} objects.
0902:             * @throws IOException
0903:             */
0904:            public Vector ls(String dirName) throws IOException {
0905:                byte[] handle = openDirectory(dirName);
0906:                Vector result = scanDirectory(handle);
0907:                closeHandle(handle);
0908:                return result;
0909:            }
0910:
0911:            /**
0912:             * Create a new directory.
0913:             * 
0914:             * @param dirName See the {@link SFTPv3Client comment} for the class for more details.
0915:             * @param posixPermissions the permissions for this directory, e.g., "0700". The server
0916:             *        will likely apply a umask.
0917:             * @throws IOException
0918:             */
0919:            public void mkdir(String dirName, int posixPermissions)
0920:                    throws IOException {
0921:                int req_id = generateNextRequestID();
0922:
0923:                TypesWriter tw = new TypesWriter();
0924:                tw.writeString(dirName, charsetName);
0925:                tw.writeUINT32(AttribFlags.SSH_FILEXFER_ATTR_PERMISSIONS);
0926:                tw.writeUINT32(posixPermissions);
0927:
0928:                sendMessage(Packet.SSH_FXP_MKDIR, req_id, tw.getBytes());
0929:
0930:                expectStatusOKMessage(req_id);
0931:            }
0932:
0933:            /**
0934:             * Remove a file.
0935:             * 
0936:             * @param fileName See the {@link SFTPv3Client comment} for the class for more details.
0937:             * @throws IOException
0938:             */
0939:            public void rm(String fileName) throws IOException {
0940:                int req_id = generateNextRequestID();
0941:
0942:                TypesWriter tw = new TypesWriter();
0943:                tw.writeString(fileName, charsetName);
0944:
0945:                sendMessage(Packet.SSH_FXP_REMOVE, req_id, tw.getBytes());
0946:
0947:                expectStatusOKMessage(req_id);
0948:            }
0949:
0950:            /**
0951:             * Remove an empty directory. 
0952:             * 
0953:             * @param dirName See the {@link SFTPv3Client comment} for the class for more details.
0954:             * @throws IOException
0955:             */
0956:            public void rmdir(String dirName) throws IOException {
0957:                int req_id = generateNextRequestID();
0958:
0959:                TypesWriter tw = new TypesWriter();
0960:                tw.writeString(dirName, charsetName);
0961:
0962:                sendMessage(Packet.SSH_FXP_RMDIR, req_id, tw.getBytes());
0963:
0964:                expectStatusOKMessage(req_id);
0965:            }
0966:
0967:            /**
0968:             * Move a file or directory.
0969:             * 
0970:             * @param oldPath See the {@link SFTPv3Client comment} for the class for more details.
0971:             * @param newPath See the {@link SFTPv3Client comment} for the class for more details.
0972:             * @throws IOException
0973:             */
0974:            public void mv(String oldPath, String newPath) throws IOException {
0975:                int req_id = generateNextRequestID();
0976:
0977:                TypesWriter tw = new TypesWriter();
0978:                tw.writeString(oldPath, charsetName);
0979:                tw.writeString(newPath, charsetName);
0980:
0981:                sendMessage(Packet.SSH_FXP_RENAME, req_id, tw.getBytes());
0982:
0983:                expectStatusOKMessage(req_id);
0984:            }
0985:
0986:            /**
0987:             * Open a file for reading.
0988:             * 
0989:             * @param fileName See the {@link SFTPv3Client comment} for the class for more details.
0990:             * @return a SFTPv3FileHandle handle
0991:             * @throws IOException
0992:             */
0993:            public SFTPv3FileHandle openFileRO(String fileName)
0994:                    throws IOException {
0995:                return openFile(fileName, 0x00000001, null); // SSH_FXF_READ	
0996:            }
0997:
0998:            /**
0999:             * Open a file for reading and writing.
1000:             * 
1001:             * @param fileName See the {@link SFTPv3Client comment} for the class for more details.
1002:             * @return a SFTPv3FileHandle handle
1003:             * @throws IOException
1004:             */
1005:            public SFTPv3FileHandle openFileRW(String fileName)
1006:                    throws IOException {
1007:                return openFile(fileName, 0x00000003, null); // SSH_FXF_READ | SSH_FXF_WRITE
1008:            }
1009:
1010:            // Append is broken (already in the specification, because there is no way to
1011:            // send a write operation (what offset to use??))
1012:            //	public SFTPv3FileHandle openFileRWAppend(String fileName) throws IOException
1013:            //	{
1014:            //		return openFile(fileName, 0x00000007, null); // SSH_FXF_READ | SSH_FXF_WRITE | SSH_FXF_APPEND
1015:            //	}
1016:
1017:            /**
1018:             * Create a file and open it for reading and writing.
1019:             * Same as {@link #createFile(String, SFTPv3FileAttributes) createFile(fileName, null)}.
1020:             * 
1021:             * @param fileName See the {@link SFTPv3Client comment} for the class for more details.
1022:             * @return a SFTPv3FileHandle handle
1023:             * @throws IOException
1024:             */
1025:            public SFTPv3FileHandle createFile(String fileName)
1026:                    throws IOException {
1027:                return createFile(fileName, null);
1028:            }
1029:
1030:            /**
1031:             * Create a file and open it for reading and writing.
1032:             * You can specify the default attributes of the file (the server may or may
1033:             * not respect your wishes).
1034:             * 
1035:             * @param fileName See the {@link SFTPv3Client comment} for the class for more details.
1036:             * @param attr may be <code>null</code> to use server defaults. Probably only
1037:             *             the <code>uid</code>, <code>gid</code> and <code>permissions</code>
1038:             *             (remember the server may apply a umask) entries of the {@link SFTPv3FileHandle}
1039:             *             structure make sense. You need only to set those fields where you want
1040:             *             to override the server's defaults.
1041:             * @return a SFTPv3FileHandle handle
1042:             * @throws IOException
1043:             */
1044:            public SFTPv3FileHandle createFile(String fileName,
1045:                    SFTPv3FileAttributes attr) throws IOException {
1046:                return openFile(fileName, 0x00000008 | 0x00000003, attr); // SSH_FXF_CREAT | SSH_FXF_READ | SSH_FXF_WRITE
1047:            }
1048:
1049:            /**
1050:             * Create a file (truncate it if it already exists) and open it for reading and writing.
1051:             * Same as {@link #createFileTruncate(String, SFTPv3FileAttributes) createFileTruncate(fileName, null)}.
1052:             * 
1053:             * @param fileName See the {@link SFTPv3Client comment} for the class for more details.
1054:             * @return a SFTPv3FileHandle handle
1055:             * @throws IOException
1056:             */
1057:            public SFTPv3FileHandle createFileTruncate(String fileName)
1058:                    throws IOException {
1059:                return createFileTruncate(fileName, null);
1060:            }
1061:
1062:            /**
1063:             * reate a file (truncate it if it already exists) and open it for reading and writing.
1064:             * You can specify the default attributes of the file (the server may or may
1065:             * not respect your wishes).
1066:             * 
1067:             * @param fileName See the {@link SFTPv3Client comment} for the class for more details.
1068:             * @param attr may be <code>null</code> to use server defaults. Probably only
1069:             *             the <code>uid</code>, <code>gid</code> and <code>permissions</code>
1070:             *             (remember the server may apply a umask) entries of the {@link SFTPv3FileHandle}
1071:             *             structure make sense. You need only to set those fields where you want
1072:             *             to override the server's defaults.
1073:             * @return a SFTPv3FileHandle handle
1074:             * @throws IOException
1075:             */
1076:            public SFTPv3FileHandle createFileTruncate(String fileName,
1077:                    SFTPv3FileAttributes attr) throws IOException {
1078:                return openFile(fileName, 0x00000018 | 0x00000003, attr); // SSH_FXF_CREAT | SSH_FXF_TRUNC | SSH_FXF_READ | SSH_FXF_WRITE
1079:            }
1080:
1081:            private byte[] createAttrs(SFTPv3FileAttributes attr) {
1082:                TypesWriter tw = new TypesWriter();
1083:
1084:                int attrFlags = 0;
1085:
1086:                if (attr == null) {
1087:                    tw.writeUINT32(0);
1088:                } else {
1089:                    if (attr.size != null)
1090:                        attrFlags = attrFlags
1091:                                | AttribFlags.SSH_FILEXFER_ATTR_SIZE;
1092:
1093:                    if ((attr.uid != null) && (attr.gid != null))
1094:                        attrFlags = attrFlags
1095:                                | AttribFlags.SSH_FILEXFER_ATTR_V3_UIDGID;
1096:
1097:                    if (attr.permissions != null)
1098:                        attrFlags = attrFlags
1099:                                | AttribFlags.SSH_FILEXFER_ATTR_PERMISSIONS;
1100:
1101:                    if ((attr.atime != null) && (attr.mtime != null))
1102:                        attrFlags = attrFlags
1103:                                | AttribFlags.SSH_FILEXFER_ATTR_V3_ACMODTIME;
1104:
1105:                    tw.writeUINT32(attrFlags);
1106:
1107:                    if (attr.size != null)
1108:                        tw.writeUINT64(attr.size.longValue());
1109:
1110:                    if ((attr.uid != null) && (attr.gid != null)) {
1111:                        tw.writeUINT32(attr.uid.intValue());
1112:                        tw.writeUINT32(attr.gid.intValue());
1113:                    }
1114:
1115:                    if (attr.permissions != null)
1116:                        tw.writeUINT32(attr.permissions.intValue());
1117:
1118:                    if ((attr.atime != null) && (attr.mtime != null)) {
1119:                        tw.writeUINT32(attr.atime.intValue());
1120:                        tw.writeUINT32(attr.mtime.intValue());
1121:                    }
1122:                }
1123:
1124:                return tw.getBytes();
1125:            }
1126:
1127:            private SFTPv3FileHandle openFile(String fileName, int flags,
1128:                    SFTPv3FileAttributes attr) throws IOException {
1129:                int req_id = generateNextRequestID();
1130:
1131:                TypesWriter tw = new TypesWriter();
1132:                tw.writeString(fileName, charsetName);
1133:                tw.writeUINT32(flags);
1134:                tw.writeBytes(createAttrs(attr));
1135:
1136:                if (debug != null) {
1137:                    debug.println("Sending SSH_FXP_OPEN...");
1138:                    debug.flush();
1139:                }
1140:
1141:                sendMessage(Packet.SSH_FXP_OPEN, req_id, tw.getBytes());
1142:
1143:                byte[] resp = receiveMessage(34000);
1144:
1145:                TypesReader tr = new TypesReader(resp);
1146:
1147:                int t = tr.readByte();
1148:
1149:                int rep_id = tr.readUINT32();
1150:                if (rep_id != req_id)
1151:                    throw new IOException(
1152:                            "The server sent an invalid id field.");
1153:
1154:                if (t == Packet.SSH_FXP_HANDLE) {
1155:                    if (debug != null) {
1156:                        debug.println("Got SSH_FXP_HANDLE.");
1157:                        debug.flush();
1158:                    }
1159:
1160:                    return new SFTPv3FileHandle(this , tr.readByteString());
1161:                }
1162:
1163:                if (t != Packet.SSH_FXP_STATUS)
1164:                    throw new IOException(
1165:                            "The SFTP server sent an unexpected packet type ("
1166:                                    + t + ")");
1167:
1168:                int errorCode = tr.readUINT32();
1169:                String errorMessage = tr.readString();
1170:
1171:                throw new SFTPException(errorMessage, errorCode);
1172:            }
1173:
1174:            /**
1175:             * Read bytes from a file. No more than 32768 bytes may be read at once.
1176:             * Be aware that the semantics of read() are different than for Java streams.
1177:             * <p>
1178:             * <ul>
1179:             * <li>The server will read as many bytes as it can from the file (up to <code>len</code>),
1180:             * and return them.</li>
1181:             * <li>If EOF is encountered before reading any data, <code>-1</code> is returned.
1182:             * <li>If an error occurs, an exception is thrown</li>.
1183:             * <li>For normal disk files, it is guaranteed that the server will return the specified
1184:             * number of bytes, or up to end of file. For, e.g., device files this may return
1185:             * fewer bytes than requested.</li>
1186:             * </ul>
1187:             * 
1188:             * @param handle a SFTPv3FileHandle handle
1189:             * @param fileOffset offset (in bytes) in the file
1190:             * @param dst the destination byte array
1191:             * @param dstoff offset in the destination byte array
1192:             * @param len how many bytes to read, 0 &lt; len &lt;= 32768 bytes
1193:             * @return the number of bytes that could be read, may be less than requested if
1194:             *         the end of the file is reached, -1 is returned in case of <code>EOF</code>
1195:             * @throws IOException
1196:             */
1197:            public int read(SFTPv3FileHandle handle, long fileOffset,
1198:                    byte[] dst, int dstoff, int len) throws IOException {
1199:                checkHandleValidAndOpen(handle);
1200:
1201:                if ((len > 32768) || (len <= 0))
1202:                    throw new IllegalArgumentException("invalid len argument");
1203:
1204:                int req_id = generateNextRequestID();
1205:
1206:                TypesWriter tw = new TypesWriter();
1207:                tw.writeString(handle.fileHandle, 0, handle.fileHandle.length);
1208:                tw.writeUINT64(fileOffset);
1209:                tw.writeUINT32(len);
1210:
1211:                if (debug != null) {
1212:                    debug.println("Sending SSH_FXP_READ...");
1213:                    debug.flush();
1214:                }
1215:
1216:                sendMessage(Packet.SSH_FXP_READ, req_id, tw.getBytes());
1217:
1218:                byte[] resp = receiveMessage(34000);
1219:
1220:                TypesReader tr = new TypesReader(resp);
1221:
1222:                int t = tr.readByte();
1223:
1224:                int rep_id = tr.readUINT32();
1225:                if (rep_id != req_id)
1226:                    throw new IOException(
1227:                            "The server sent an invalid id field.");
1228:
1229:                if (t == Packet.SSH_FXP_DATA) {
1230:                    if (debug != null) {
1231:                        debug.println("Got SSH_FXP_DATA...");
1232:                        debug.flush();
1233:                    }
1234:
1235:                    int readLen = tr.readUINT32();
1236:
1237:                    if ((readLen < 0) || (readLen > len))
1238:                        throw new IOException(
1239:                                "The server sent an invalid length field.");
1240:
1241:                    tr.readBytes(dst, dstoff, readLen);
1242:
1243:                    return readLen;
1244:                }
1245:
1246:                if (t != Packet.SSH_FXP_STATUS)
1247:                    throw new IOException(
1248:                            "The SFTP server sent an unexpected packet type ("
1249:                                    + t + ")");
1250:
1251:                int errorCode = tr.readUINT32();
1252:
1253:                if (errorCode == ErrorCodes.SSH_FX_EOF) {
1254:                    if (debug != null) {
1255:                        debug.println("Got SSH_FX_EOF.");
1256:                        debug.flush();
1257:                    }
1258:
1259:                    return -1;
1260:                }
1261:
1262:                String errorMessage = tr.readString();
1263:
1264:                throw new SFTPException(errorMessage, errorCode);
1265:            }
1266:
1267:            /**
1268:             * Write bytes to a file. If <code>len</code> &gt; 32768, then the write operation will
1269:             * be split into multiple writes.
1270:             * 
1271:             * @param handle a SFTPv3FileHandle handle.
1272:             * @param fileOffset offset (in bytes) in the file.
1273:             * @param src the source byte array.
1274:             * @param srcoff offset in the source byte array.
1275:             * @param len how many bytes to write.
1276:             * @throws IOException
1277:             */
1278:            public void write(SFTPv3FileHandle handle, long fileOffset,
1279:                    byte[] src, int srcoff, int len) throws IOException {
1280:                checkHandleValidAndOpen(handle);
1281:
1282:                if (len < 0)
1283:
1284:                    while (len > 0) {
1285:                        int writeRequestLen = len;
1286:
1287:                        if (writeRequestLen > 32768)
1288:                            writeRequestLen = 32768;
1289:
1290:                        int req_id = generateNextRequestID();
1291:
1292:                        TypesWriter tw = new TypesWriter();
1293:                        tw.writeString(handle.fileHandle, 0,
1294:                                handle.fileHandle.length);
1295:                        tw.writeUINT64(fileOffset);
1296:                        tw.writeString(src, srcoff, writeRequestLen);
1297:
1298:                        if (debug != null) {
1299:                            debug.println("Sending SSH_FXP_WRITE...");
1300:                            debug.flush();
1301:                        }
1302:
1303:                        sendMessage(Packet.SSH_FXP_WRITE, req_id, tw.getBytes());
1304:
1305:                        fileOffset += writeRequestLen;
1306:
1307:                        srcoff += writeRequestLen;
1308:                        len -= writeRequestLen;
1309:
1310:                        byte[] resp = receiveMessage(34000);
1311:
1312:                        TypesReader tr = new TypesReader(resp);
1313:
1314:                        int t = tr.readByte();
1315:
1316:                        int rep_id = tr.readUINT32();
1317:                        if (rep_id != req_id)
1318:                            throw new IOException(
1319:                                    "The server sent an invalid id field.");
1320:
1321:                        if (t != Packet.SSH_FXP_STATUS)
1322:                            throw new IOException(
1323:                                    "The SFTP server sent an unexpected packet type ("
1324:                                            + t + ")");
1325:
1326:                        int errorCode = tr.readUINT32();
1327:
1328:                        if (errorCode == ErrorCodes.SSH_FX_OK)
1329:                            continue;
1330:
1331:                        String errorMessage = tr.readString();
1332:
1333:                        throw new SFTPException(errorMessage, errorCode);
1334:                    }
1335:            }
1336:
1337:            /**
1338:             * Close a file.
1339:             * 
1340:             * @param handle a SFTPv3FileHandle handle
1341:             * @throws IOException
1342:             */
1343:            public void closeFile(SFTPv3FileHandle handle) throws IOException {
1344:                if (handle == null)
1345:                    throw new IllegalArgumentException(
1346:                            "the handle argument may not be null");
1347:
1348:                try {
1349:                    if (handle.isClosed == false) {
1350:                        closeHandle(handle.fileHandle);
1351:                    }
1352:                } finally {
1353:                    handle.isClosed = true;
1354:                }
1355:            }
1356:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.