You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2013/01/17 14:09:52 UTC
svn commit: r1434658 [5/6] - in /mina/sshd/trunk: sshd-core/src/docs/
sshd-core/src/main/java/org/apache/sshd/server/filesystem/ sshd-sftp/
sshd-sftp/src/main/java/org/apache/sshd/sftp/
sshd-sftp/src/main/java/org/apache/sshd/sftp/reply/ sshd-sftp/src/...
Modified: mina/sshd/trunk/sshd-sftp/src/main/java/org/apache/sshd/sftp/subsystem/SftpSubsystem.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-sftp/src/main/java/org/apache/sshd/sftp/subsystem/SftpSubsystem.java?rev=1434658&r1=1434657&r2=1434658&view=diff
==============================================================================
--- mina/sshd/trunk/sshd-sftp/src/main/java/org/apache/sshd/sftp/subsystem/SftpSubsystem.java (original)
+++ mina/sshd/trunk/sshd-sftp/src/main/java/org/apache/sshd/sftp/subsystem/SftpSubsystem.java Thu Jan 17 13:09:51 2013
@@ -19,14 +19,14 @@
package org.apache.sshd.sftp.subsystem;
import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.Session;
import org.apache.sshd.common.util.Buffer;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.SelectorUtils;
import org.apache.sshd.server.*;
+import org.apache.sshd.server.channel.ChannelDataReceiver;
+import org.apache.sshd.server.channel.ChannelSession;
import org.apache.sshd.server.session.ServerSession;
-import org.apache.sshd.sftp.DefaultSftpletContainer;
-import org.apache.sshd.sftp.Handle;
-import org.apache.sshd.sftp.Sftplet;
+import org.apache.sshd.sftp.*;
import org.apache.sshd.sftp.reply.*;
import org.apache.sshd.sftp.request.*;
import org.slf4j.Logger;
@@ -35,15 +35,16 @@ import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.*;
+import static org.apache.sshd.sftp.subsystem.SftpConstants.*;
+
/**
* SFTP subsystem
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class SftpSubsystem implements Command, Runnable, SessionAware, FileSystemAware {
- private Sftplet sftpLet = new DefaultSftpletContainer();
+public class SftpSubsystem implements Command, SessionAware, FileSystemAware, SftpSession, ChannelDataReceiver, ChannelSessionAware {
- protected final Logger log = LoggerFactory.getLogger(getClass());
+ protected static final Logger LOG = LoggerFactory.getLogger(SftpSubsystem.class);
public static class Factory implements NamedFactory<Command> {
@@ -59,168 +60,16 @@ public class SftpSubsystem implements Co
}
}
+ public static final int LOWER_SFTP_IMPL = 3; // Working implementation from v3
+ public static final int HIGHER_SFTP_IMPL = 6; // .. up to
+ public static final String ALL_SFTP_IMPL = "3,4,5,6";
+ public static final int MAX_PACKET_LENGTH = 1024 * 16;
+
/**
* Properties key for the maximum of available open handles per session.
*/
public static final String MAX_OPEN_HANDLES_PER_SESSION = "max-open-handles-per-session";
- public static final int LOWER_SFTP_IMPL = 3; // Working implementation from v3
- public static final int HIGHER_SFTP_IMPL = 3; // .. up to
- public static final String ALL_SFTP_IMPL = "3";
- public static final int MAX_PACKET_LENGTH = 1024 * 16;
-
- public static final int SSH_FXP_INIT = 1;
- public static final int SSH_FXP_VERSION = 2;
- public static final int SSH_FXP_OPEN = 3;
- public static final int SSH_FXP_CLOSE = 4;
- public static final int SSH_FXP_READ = 5;
- public static final int SSH_FXP_WRITE = 6;
- public static final int SSH_FXP_LSTAT = 7;
- public static final int SSH_FXP_FSTAT = 8;
- public static final int SSH_FXP_SETSTAT = 9;
- public static final int SSH_FXP_FSETSTAT = 10;
- public static final int SSH_FXP_OPENDIR = 11;
- public static final int SSH_FXP_READDIR = 12;
- public static final int SSH_FXP_REMOVE = 13;
- public static final int SSH_FXP_MKDIR = 14;
- public static final int SSH_FXP_RMDIR = 15;
- public static final int SSH_FXP_REALPATH = 16;
- public static final int SSH_FXP_STAT = 17;
- public static final int SSH_FXP_RENAME = 18;
- public static final int SSH_FXP_READLINK = 19;
- public static final int SSH_FXP_LINK = 21;
- public static final int SSH_FXP_BLOCK = 22;
- public static final int SSH_FXP_UNBLOCK = 23;
-
- public static final int SSH_FXP_STATUS = 101;
- public static final int SSH_FXP_HANDLE = 102;
- public static final int SSH_FXP_DATA = 103;
- public static final int SSH_FXP_NAME = 104;
- public static final int SSH_FXP_ATTRS = 105;
-
- public static final int SSH_FXP_EXTENDED = 200;
- public static final int SSH_FXP_EXTENDED_REPLY = 201;
-
- public static final int SSH_FX_OK = 0;
- public static final int SSH_FX_EOF = 1;
- public static final int SSH_FX_NO_SUCH_FILE = 2;
- public static final int SSH_FX_PERMISSION_DENIED = 3;
- public static final int SSH_FX_FAILURE = 4;
- public static final int SSH_FX_BAD_MESSAGE = 5;
- public static final int SSH_FX_NO_CONNECTION = 6;
- public static final int SSH_FX_CONNECTION_LOST = 7;
- public static final int SSH_FX_OP_UNSUPPORTED = 8;
- public static final int SSH_FX_INVALID_HANDLE = 9;
- public static final int SSH_FX_NO_SUCH_PATH = 10;
- public static final int SSH_FX_FILE_ALREADY_EXISTS = 11;
- public static final int SSH_FX_WRITE_PROTECT = 12;
- public static final int SSH_FX_NO_MEDIA = 13;
- public static final int SSH_FX_NO_SPACE_ON_FILESYSTEM = 14;
- public static final int SSH_FX_QUOTA_EXCEEDED = 15;
- public static final int SSH_FX_UNKNOWN_PRINCIPAL = 16;
- public static final int SSH_FX_LOCK_CONFLICT = 17;
- public static final int SSH_FX_DIR_NOT_EMPTY = 18;
- public static final int SSH_FX_NOT_A_DIRECTORY = 19;
- public static final int SSH_FX_INVALID_FILENAME = 20;
- public static final int SSH_FX_LINK_LOOP = 21;
- public static final int SSH_FX_CANNOT_DELETE = 22;
- public static final int SSH_FX_INVALID_PARAMETER = 23;
- public static final int SSH_FX_FILE_IS_A_DIRECTORY = 24;
- public static final int SSH_FX_BYTE_RANGE_LOCK_CONFLICT = 25;
- public static final int SSH_FX_BYTE_RANGE_LOCK_REFUSED = 26;
- public static final int SSH_FX_DELETE_PENDING = 27;
- public static final int SSH_FX_FILE_CORRUPT = 28;
- public static final int SSH_FX_OWNER_INVALID = 29;
- public static final int SSH_FX_GROUP_INVALID = 30;
- public static final int SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK = 31;
-
- public static final int SSH_FILEXFER_ATTR_SIZE = 0x00000001;
- public static final int SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004;
- public static final int SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008; //v3 naming convention
- public static final int SSH_FILEXFER_ATTR_ACCESSTIME = 0x00000008;
- public static final int SSH_FILEXFER_ATTR_CREATETIME = 0x00000010;
- public static final int SSH_FILEXFER_ATTR_MODIFYTIME = 0x00000020;
- public static final int SSH_FILEXFER_ATTR_ACL = 0x00000040;
- public static final int SSH_FILEXFER_ATTR_OWNERGROUP = 0x00000080;
- public static final int SSH_FILEXFER_ATTR_SUBSECOND_TIMES = 0x00000100;
- public static final int SSH_FILEXFER_ATTR_BITS = 0x00000200;
- public static final int SSH_FILEXFER_ATTR_ALLOCATION_SIZE = 0x00000400;
- public static final int SSH_FILEXFER_ATTR_TEXT_HINT = 0x00000800;
- public static final int SSH_FILEXFER_ATTR_MIME_TYPE = 0x00001000;
- public static final int SSH_FILEXFER_ATTR_LINK_COUNT = 0x00002000;
- public static final int SSH_FILEXFER_ATTR_UNTRANSLATED_NAME = 0x00004000;
- public static final int SSH_FILEXFER_ATTR_CTIME = 0x00008000;
- public static final int SSH_FILEXFER_ATTR_EXTENDED = 0x80000000;
-
- public static final int SSH_FILEXFER_TYPE_REGULAR = 1;
- public static final int SSH_FILEXFER_TYPE_DIRECTORY = 2;
- public static final int SSH_FILEXFER_TYPE_SYMLINK = 3;
- public static final int SSH_FILEXFER_TYPE_SPECIAL = 4;
- public static final int SSH_FILEXFER_TYPE_UNKNOWN = 5;
- public static final int SSH_FILEXFER_TYPE_SOCKET = 6;
- public static final int SSH_FILEXFER_TYPE_CHAR_DEVICE = 7;
- public static final int SSH_FILEXFER_TYPE_BLOCK_DEVICE = 8;
- public static final int SSH_FILEXFER_TYPE_FIFO = 9;
-
-
- public static final int SSH_FXF_ACCESS_DISPOSITION = 0x00000007;
- public static final int SSH_FXF_CREATE_NEW = 0x00000000;
- public static final int SSH_FXF_CREATE_TRUNCATE = 0x00000001;
- public static final int SSH_FXF_OPEN_EXISTING = 0x00000002;
- public static final int SSH_FXF_OPEN_OR_CREATE = 0x00000003;
- public static final int SSH_FXF_TRUNCATE_EXISTING = 0x00000004;
- public static final int SSH_FXF_APPEND_DATA = 0x00000008;
- public static final int SSH_FXF_APPEND_DATA_ATOMIC = 0x00000010;
- public static final int SSH_FXF_TEXT_MODE = 0x00000020;
- public static final int SSH_FXF_BLOCK_READ = 0x00000040;
- public static final int SSH_FXF_BLOCK_WRITE = 0x00000080;
- public static final int SSH_FXF_BLOCK_DELETE = 0x00000100;
- public static final int SSH_FXF_BLOCK_ADVISORY = 0x00000200;
- public static final int SSH_FXF_NOFOLLOW = 0x00000400;
- public static final int SSH_FXF_DELETE_ON_CLOSE = 0x00000800;
- public static final int SSH_FXF_ACCESS_AUDIT_ALARM_INFO = 0x00001000;
- public static final int SSH_FXF_ACCESS_BACKUP = 0x00002000;
- public static final int SSH_FXF_BACKUP_STREAM = 0x00004000;
- public static final int SSH_FXF_OVERRIDE_OWNER = 0x00008000;
-
- public static final int SSH_FXF_READ = 0x00000001;
- public static final int SSH_FXF_WRITE = 0x00000002;
- public static final int SSH_FXF_APPEND = 0x00000004;
- public static final int SSH_FXF_CREAT = 0x00000008;
- public static final int SSH_FXF_TRUNC = 0x00000010;
- public static final int SSH_FXF_EXCL = 0x00000020;
- public static final int SSH_FXF_TEXT = 0x00000040;
-
- public static final int ACE4_READ_DATA = 0x00000001;
- public static final int ACE4_LIST_DIRECTORY = 0x00000001;
- public static final int ACE4_WRITE_DATA = 0x00000002;
- public static final int ACE4_ADD_FILE = 0x00000002;
- public static final int ACE4_APPEND_DATA = 0x00000004;
- public static final int ACE4_ADD_SUBDIRECTORY = 0x00000004;
- public static final int ACE4_READ_NAMED_ATTRS = 0x00000008;
- public static final int ACE4_WRITE_NAMED_ATTRS = 0x00000010;
- public static final int ACE4_EXECUTE = 0x00000020;
- public static final int ACE4_DELETE_CHILD = 0x00000040;
- public static final int ACE4_READ_ATTRIBUTES = 0x00000080;
- public static final int ACE4_WRITE_ATTRIBUTES = 0x00000100;
- public static final int ACE4_DELETE = 0x00010000;
- public static final int ACE4_READ_ACL = 0x00020000;
- public static final int ACE4_WRITE_ACL = 0x00040000;
- public static final int ACE4_WRITE_OWNER = 0x00080000;
-
- public static final int S_IRUSR = 0000400;
- public static final int S_IWUSR = 0000200;
- public static final int S_IXUSR = 0000100;
- public static final int S_IRGRP = 0000040;
- public static final int S_IWGRP = 0000020;
- public static final int S_IXGRP = 0000010;
- public static final int S_IROTH = 0000004;
- public static final int S_IWOTH = 0000002;
- public static final int S_IXOTH = 0000001;
- public static final int S_ISUID = 0004000;
- public static final int S_ISGID = 0002000;
- public static final int S_ISVTX = 0001000;
-
private ExitCallback callback;
private InputStream in;
@@ -228,199 +77,57 @@ public class SftpSubsystem implements Co
private OutputStream err;
private Environment env;
private ServerSession session;
+ private ChannelSession channel;
private boolean closed = false;
private FileSystemView root;
private int version;
private Map<String, Handle> handles = new HashMap<String, Handle>();
- private Request sftpRequest;
-
- protected static int mapV4ToV3(int code) {
- switch (code) {
- case SSH_FX_INVALID_HANDLE:
- return SSH_FX_FAILURE;
- case SSH_FX_NO_SUCH_PATH:
- return SSH_FX_NO_SUCH_FILE;
- case SSH_FX_FILE_ALREADY_EXISTS:
- return SSH_FX_FAILURE;
- case SSH_FX_WRITE_PROTECT:
- return SSH_FX_PERMISSION_DENIED;
- case SSH_FX_NO_MEDIA:
- return SSH_FX_FAILURE;
- default:
- return code;
- }
- }
-
- protected static int mapV5ToV4(int code) {
- switch (code) {
- case SSH_FX_NO_SPACE_ON_FILESYSTEM:
- return SSH_FX_FAILURE;
- case SSH_FX_QUOTA_EXCEEDED:
- return SSH_FX_FAILURE;
- case SSH_FX_UNKNOWN_PRINCIPAL:
- return SSH_FX_FAILURE;
- case SSH_FX_LOCK_CONFLICT:
- return SSH_FX_FAILURE;
- default:
- return code;
- }
- }
-
- protected static int mapV6ToV5(int code) {
- switch (code) {
- case SSH_FX_DIR_NOT_EMPTY:
- return SSH_FX_FAILURE;
- case SSH_FX_NOT_A_DIRECTORY:
- return SSH_FX_NO_SUCH_FILE;
- case SSH_FX_INVALID_FILENAME:
- return SSH_FX_NO_SUCH_FILE;
- case SSH_FX_LINK_LOOP:
- return SSH_FX_FAILURE;
- case SSH_FX_CANNOT_DELETE:
- return SSH_FX_PERMISSION_DENIED;
- case SSH_FX_INVALID_PARAMETER:
- return SSH_FX_FAILURE;
- case SSH_FX_FILE_IS_A_DIRECTORY:
- return SSH_FX_NO_SUCH_FILE;
- case SSH_FX_BYTE_RANGE_LOCK_CONFLICT:
- return SSH_FX_FAILURE;
- case SSH_FX_BYTE_RANGE_LOCK_REFUSED:
- return SSH_FX_FAILURE;
- case SSH_FX_DELETE_PENDING:
- return SSH_FX_FAILURE;
- case SSH_FX_FILE_CORRUPT:
- return SSH_FX_FAILURE;
- case SSH_FX_OWNER_INVALID:
- return SSH_FX_PERMISSION_DENIED;
- case SSH_FX_GROUP_INVALID:
- return SSH_FX_PERMISSION_DENIED;
- case SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK:
- return SSH_FX_FAILURE;
- default:
- return code;
- }
- }
-
- protected static int mapToVersion(int code, int version) {
- int mappedCode = code;
- if (version < 6) {
- mappedCode = mapV6ToV5(mappedCode);
- }
- if (version < 5) {
- mappedCode = mapV5ToV4(mappedCode);
- }
- if (version < 4) {
- mappedCode = mapV4ToV3(mappedCode);
- }
- return mappedCode;
- }
-
- protected int mapToVersion(int code) {
- return mapToVersion(code, version);
- }
-
- protected static class DirectoryHandle extends Handle implements Iterator<SshFile> {
- boolean done;
- // the directory should be read once at "open directory"
- List<SshFile> fileList = null;
- int fileIndex;
-
- public DirectoryHandle(SshFile file) {
- super(file);
- fileList = file.listSshFiles();
- fileIndex = 0;
- }
-
- public boolean isDone() {
- return done;
- }
-
- public void setDone(boolean done) {
- this.done = done;
- }
-
- public boolean hasNext() {
- return fileIndex < fileList.size();
- }
-
- public SshFile next() {
- SshFile f = fileList.get(fileIndex);
- fileIndex++;
- return f;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- public void clearFileList() {
- // allow the garbage collector to do the job
- fileList = null;
- }
- }
-
- public static class FileHandle extends Handle {
- int flags;
- OutputStream output;
- long outputPos;
- InputStream input;
- long inputPos;
-
- public FileHandle(SshFile sshFile, int flags) {
- super(sshFile);
- this.flags = flags;
- }
-
- public int getFlags() {
- return flags;
- }
-
- public int read(byte[] data, long offset) throws IOException {
- if (input != null && offset != inputPos) {
- IoUtils.closeQuietly(input);
- input = null;
- }
- if (input == null) {
- input = file.createInputStream(offset);
- inputPos = offset;
- }
- int read = input.read(data);
- inputPos += read;
- return read;
- }
+ private Sftplet sftpLet = new DefaultSftpletContainer();
+ private Serializer serializer = new Serializer(this);
- public void write(byte[] data, long offset) throws IOException {
- if (output != null && offset != outputPos) {
- IoUtils.closeQuietly(output);
- output = null;
- }
- if (output == null) {
- output = file.createOutputStream(offset);
- }
- output.write(data);
- outputPos += data.length;
- }
+ public SftpSubsystem() {
+ }
- @Override
- public void close() throws IOException {
- IoUtils.closeQuietly(output, input);
- output = null;
- input = null;
- super.close();
- }
+ public void setSftpLet(final Sftplet sftpLet) {
+ this.sftpLet = sftpLet;
}
- public SftpSubsystem() {}
+ public int getVersion() {
+ return version;
+ }
- public void setSftpLet(final Sftplet sftpLet) {
- this.sftpLet = sftpLet;
+ public Session getSession() {
+ return session;
+ }
+
+ public Handle getHandle(String id) {
+ return handles.get(id);
}
-
+
+ public Handle createFileHandle(SshFile file, int flags) {
+ String id = UUID.randomUUID().toString();
+ Handle handle = new FileHandle(id, file, flags);
+ handles.put(id, handle);
+ return handle;
+ }
+
+ public Handle createDirectoryHandle(SshFile file) {
+ String id = UUID.randomUUID().toString();
+ Handle handle = new DirectoryHandle(id, file);
+ handles.put(id, handle);
+ return handle;
+ }
+
+ public void setChannelSession(ChannelSession channel) {
+ this.channel = channel;
+ channel.setDataReceiver(this);
+ }
+
public void setSession(ServerSession session) {
- sftpLet.onConnect(session);
+ sftpLet.onConnect(this);
this.session = session;
}
@@ -446,558 +153,513 @@ public class SftpSubsystem implements Co
public void start(Environment env) throws IOException {
this.env = env;
- new Thread(this).start();
}
- public void run() {
- DataInputStream dis = null;
- try {
- dis = new DataInputStream(in);
- while (true) {
- int length = dis.readInt();
- if (length < 5) {
- throw new IllegalArgumentException();
- }
- Buffer buffer = new Buffer(length + 4);
- buffer.putInt(length);
- int nb = length;
- while (nb > 0) {
- int l = dis.read(buffer.array(), buffer.wpos(), nb);
- if (l < 0) {
- throw new IllegalArgumentException();
- }
- buffer.wpos(buffer.wpos() + l);
- nb -= l;
- }
- process(buffer);
- }
- } catch (Throwable t) {
- if (!closed && !(t instanceof EOFException)) { // Ignore han
- log.error("Exception caught in SFTP subsystem", t);
- }
- } finally {
- if (dis != null) {
+ private Buffer buffer = new Buffer();
+
+ public int data(ChannelSession channel, byte[] buf, int start, int len) throws IOException {
+ Buffer incoming = new Buffer(buf, start, len);
+ // If we already have partial data, we need to append it to the buffer and use it
+ if (buffer.available() > 0) {
+ buffer.putBuffer(incoming);
+ incoming = buffer;
+ }
+ // Process commands
+ int rpos = incoming.rpos();
+ while (receive(incoming));
+ int read = incoming.rpos() - rpos;
+ // Compact and add remaining data
+ buffer.compact();
+ if (buffer != incoming && incoming.available() > 0) {
+ buffer.putBuffer(incoming);
+ }
+ return read;
+ }
+
+ protected boolean receive(Buffer incoming) throws IOException {
+ int rpos = incoming.rpos();
+ int wpos = incoming.wpos();
+ if (wpos - rpos > 4) {
+ int length = incoming.getInt();
+ if (length < 5) {
+ throw new IOException("Illegal sftp packet length: " + length);
+ }
+ if (wpos - rpos >= length + 4) {
+ incoming.rpos(rpos);
+ incoming.wpos(rpos + 4 + length);
+ process(incoming);
+ incoming.rpos(rpos + 4 + length);
+ incoming.wpos(wpos);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void close() throws IOException {
+ if (handles != null) {
+ for (Map.Entry<String, Handle> entry : handles.entrySet()) {
+ Handle handle = entry.getValue();
try {
- dis.close();
+ handle.close();
} catch (IOException ioe) {
- log.error("Could not close DataInputStream", ioe);
+ LOG.error("Could not close open handle: " + entry.getKey(), ioe);
}
}
+ }
+ callback.onExit(0);
+ sftpLet.onDisconnect(this);
+ }
- if (handles != null) {
- for (Map.Entry<String, Handle> entry : handles.entrySet()) {
- Handle handle = entry.getValue();
- try {
- handle.close();
- } catch (IOException ioe) {
- log.error("Could not close open handle: " + entry.getKey(), ioe);
- }
- }
+ public void process(Buffer buffer) throws IOException {
+ Request request = serializer.readRequest(buffer);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Received sftp request: " + request);
+ }
+ Reply reply = sftpLet.beforeCommand(this, request);
+ if (reply == null) {
+ reply = doProcess(request);
+ }
+ reply = sftpLet.afterCommand(this, request, reply);
+ if (reply != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Sending sftp reply: " + reply);
}
- dis = null;
+ buffer = serializer.writeReply(reply);
+ send(buffer);
+ }
+ }
+
+ protected Reply doProcess(Request request) throws IOException {
+ try {
+ if (request instanceof SshFxpInitRequest) {
+ return doProcessInit((SshFxpInitRequest) request);
+ } else if (request instanceof SshFxpOpenRequest) {
+ return doProcessOpen((SshFxpOpenRequest) request);
+ } else if (request instanceof SshFxpCloseRequest) {
+ return doProcessClose((SshFxpCloseRequest) request);
+ } else if (request instanceof SshFxpReadRequest) {
+ return doProcessRead((SshFxpReadRequest) request);
+ } else if (request instanceof SshFxpWriteRequest) {
+ return doProcessWrite((SshFxpWriteRequest) request);
+ } else if ((request instanceof SshFxpLstatRequest)
+ || (request instanceof SshFxpStatRequest)) {
+ return doProcessStat(request);
+ } else if (request instanceof SshFxpFstatRequest) {
+ return doProcessFstat((SshFxpFstatRequest) request);
+ } else if (request instanceof SshFxpOpendirRequest) {
+ return doProcessOpendir((SshFxpOpendirRequest) request);
+ } else if (request instanceof SshFxpReaddirRequest) {
+ return doProcessReaddir((SshFxpReaddirRequest) request);
+ } else if (request instanceof SshFxpRemoveRequest) {
+ return doProcessRemove((SshFxpRemoveRequest) request);
+ } else if (request instanceof SshFxpMkdirRequest) {
+ return doProcessMkdir((SshFxpMkdirRequest) request);
+ } else if (request instanceof SshFxpRmdirRequest) {
+ return doProcessRmdir((SshFxpRmdirRequest) request);
+ } else if (request instanceof SshFxpRealpathRequest) {
+ return doProcessRealpath((SshFxpRealpathRequest) request);
+ } else if (request instanceof SshFxpRenameRequest) {
+ return doProcessRename((SshFxpRenameRequest) request);
+ } else if ((request instanceof SshFxpSetstatRequest)
+ || (request instanceof SshFxpFsetstatRequest)) {
+ return doProcessSetstat(request);
- callback.onExit(0);
- sftpLet.onDisconnect(session);
+ } else {
+ LOG.error("Received: {}", request);
+ int id = request.getId();
+ return new SshFxpStatusReply(id, SSH_FX_OP_UNSUPPORTED, "Command " + request + " is unsupported or not implemented");
+ }
+ } catch (IOException e) {
+ int id = request.getId();
+ return new SshFxpStatusReply(id, SSH_FX_FAILURE, e.getMessage());
}
}
- public void process(Buffer buffer) throws IOException {
- sftpRequest = getSftpRequest(new Buffer(buffer.array()));
- Reply reply = sftpLet.beforeCommand(session, sftpRequest);
- if (reply != null) {
- sendReply(reply);
- return;
- }
- int id = sftpRequest.getId();
- if (sftpRequest instanceof SshFxpInitRequest) {
- version = id;
- if (version >= LOWER_SFTP_IMPL) {
- version = Math.min(version, HIGHER_SFTP_IMPL);
- Buffer sendBuffer = new Buffer();
- sendBuffer.putByte((byte) SSH_FXP_VERSION);
- sendBuffer.putInt(version);
- send(sendBuffer);
- } else {
- // We only support version 3 (Version 1 and 2 are not common)
- sendStatus(id, SSH_FX_OP_UNSUPPORTED, "SFTP server only support versions " + ALL_SFTP_IMPL);
- }
- } else if (sftpRequest instanceof SshFxpOpenRequest) {
- SshFxpOpenRequest sshFxpOpenRequest = (SshFxpOpenRequest) sftpRequest;
- if (session.getFactoryManager().getProperties() != null) {
- String maxHandlesString = session.getFactoryManager().getProperties().get(MAX_OPEN_HANDLES_PER_SESSION);
- if (maxHandlesString != null) {
- int maxHandleCount = Integer.parseInt(maxHandlesString);
- if (handles.size() > maxHandleCount) {
- sendStatus(id, SSH_FX_FAILURE, "Too many open handles");
- return;
- }
- }
- }
+ private Reply doProcessSetstat(Request request) throws IOException {
+ // This is required for WinSCP / Cyberduck to upload properly
+ // Blindly reply "OK"
+ // TODO implement it
+ int id = request.getId();
+ return new SshFxpStatusReply(id, SSH_FX_OK, "");
+ }
+
+ private Reply doProcessRename(SshFxpRenameRequest request) throws IOException {
+ int id = request.getId();
+ String oldPath = request.getOldPath();
+ String newPath = request.getNewPath();
+ SshFile o = resolveFile(oldPath);
+ SshFile n = resolveFile(newPath);
+ if (!o.doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_FILE, o.getAbsolutePath());
+ } else if (n.doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_FILE_ALREADY_EXISTS, n.getAbsolutePath());
+ } else if (!o.move(n)) {
+ return new SshFxpStatusReply(id, SSH_FX_FAILURE, "Failed to rename file");
+ } else {
+ return new SshFxpStatusReply(id, SSH_FX_OK, "");
+ }
+ }
- Integer accValue = sshFxpOpenRequest.getAcc();
- if (accValue == null) {
- String path = sshFxpOpenRequest.getPath();
- int pflags = sshFxpOpenRequest.getFlags();
- // attrs
- try {
- SshFile file = resolveFile(path);
- if (file.doesExist()) {
- if (((pflags & SSH_FXF_CREAT) != 0) && ((pflags & SSH_FXF_EXCL) != 0)) {
- sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, path);
- return;
- }
- } else {
- if (((pflags & SSH_FXF_CREAT) != 0)) {
- if (!file.isWritable()) {
- sendStatus(id, SSH_FX_PERMISSION_DENIED, "Can not create " + path);
- return;
- }
- file.create();
- }
- }
- String acc = ((pflags & (SSH_FXF_READ | SSH_FXF_WRITE)) != 0 ? "r" : "") +
- ((pflags & SSH_FXF_WRITE) != 0 ? "w" : "");
- if ((pflags & SSH_FXF_TRUNC) != 0) {
- file.truncate();
- }
- String handle = UUID.randomUUID().toString();
- handles.put(handle, new FileHandle(file, pflags)); // handle flags conversion
- sendHandle(id, handle);
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage() == null ? "" : e.getMessage());
- }
- } else {
- String path = sshFxpOpenRequest.getPath();
- int acc = accValue;
- int flags = sshFxpOpenRequest.getFlags();
- // attrs
- try {
- SshFile file = resolveFile(path);
- switch (flags & SSH_FXF_ACCESS_DISPOSITION) {
- case SSH_FXF_CREATE_NEW: {
- if (file.doesExist()) {
- sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, path);
- return;
- } else if (!file.isWritable()) {
- sendStatus(id, SSH_FX_PERMISSION_DENIED, "Can not create " + path);
- }
- file.create();
- break;
- }
- case SSH_FXF_CREATE_TRUNCATE: {
- if (file.doesExist()) {
- sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, path);
- return;
- } else if (!file.isWritable()) {
- sendStatus(id, SSH_FX_PERMISSION_DENIED, "Can not create " + path);
- }
- file.truncate();
- break;
- }
- case SSH_FXF_OPEN_EXISTING: {
- if (!file.doesExist()) {
- if (!file.getParentFile().doesExist()) {
- sendStatus(id, SSH_FX_NO_SUCH_PATH, path);
- } else {
- sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
- }
- return;
- }
- break;
- }
- case SSH_FXF_OPEN_OR_CREATE: {
- if (!file.doesExist()) {
- file.create();
- }
- break;
- }
- case SSH_FXF_TRUNCATE_EXISTING: {
- if (!file.doesExist()) {
- if (!file.getParentFile().doesExist()) {
- sendStatus(id, SSH_FX_NO_SUCH_PATH, path);
- } else {
- sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
- }
- return;
- }
- file.truncate();
- break;
- }
- default:
- throw new IllegalArgumentException("Unsupported open mode: " + flags);
- }
- String handle = UUID.randomUUID().toString();
- handles.put(handle, new FileHandle(file, flags));
- sendHandle(id, handle);
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
- }
- }
- } else if (sftpRequest instanceof SshFxpCloseRequest) {
- SshFxpCloseRequest sshFxpCloseRequest = (SshFxpCloseRequest) sftpRequest;
- String handle = sshFxpCloseRequest.getHandleId();
- try {
- Handle h = handles.get(handle);
- if (h == null) {
- sendStatus(id, SSH_FX_INVALID_HANDLE, handle, "");
- } else {
- handles.remove(handle);
- h.close();
- sendStatus(id, SSH_FX_OK, "", "");
- }
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
- }
- } else if (sftpRequest instanceof SshFxpReadRequest) {
- SshFxpReadRequest sshFxpReadRequest = (SshFxpReadRequest) sftpRequest;
- String handle = sshFxpReadRequest.getHandleId();
- long offset = sshFxpReadRequest.getOffset();
- int len = sshFxpReadRequest.getLen();
- try {
- Handle p = handles.get(handle);
- if (!(p instanceof FileHandle)) {
- sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
- } else {
- FileHandle fh = (FileHandle) p;
- byte[] b = new byte[Math.min(len, 1024 * 32)];
- len = fh.read(b, offset);
- if (len >= 0) {
- SshFxpDataReply sftpReply = new SshFxpDataReply(id, b);
- Buffer buf = new Buffer(len + 5);
- buf.putByte((byte) SSH_FXP_DATA);
- buf.putInt(id);
- buf.putBytes(b, 0, len);
- if (version >= 6) {
- boolean lenFlag = len == 0;
- buf.putBoolean(lenFlag);
- sftpReply = new SshFxpDataReply(id, Arrays.copyOf(b, len), lenFlag);
- }
- if (processAfterCommand(session, sftpRequest, sftpReply)) return;
- send(buf);
- } else {
- sendStatus(id, SSH_FX_EOF, "");
- }
- }
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
- }
- } else if (sftpRequest instanceof SshFxpWriteRequest) {
- SshFxpWriteRequest sshFxpWriteRequest = (SshFxpWriteRequest) sftpRequest;
- String handle = sshFxpWriteRequest.getHandleId();
- long offset = sshFxpWriteRequest.getOffset();
- byte[] data = sshFxpWriteRequest.getData();
- try {
- Handle p = handles.get(handle);
- if (!(p instanceof FileHandle)) {
- sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
+ private Reply doProcessRealpath(SshFxpRealpathRequest request) throws IOException {
+ int id = request.getId();
+ String path = request.getPath();
+ if (path.trim().length() == 0) {
+ path = ".";
+ }
+ // TODO: handle optional args
+ SshFile p = resolveFile(path);
+ if (!p.doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_FILE, p.getAbsolutePath());
+ }
+ String normalizedPath = SelectorUtils.normalizePath(p.getAbsolutePath(), "/");
+ if (normalizedPath.length() == 0) {
+ normalizedPath = "/";
+ }
+ p = resolveFile(normalizedPath);
+ if (p.getName().length() == 0) {
+ p = resolveFile(".");
+ }
+ SshFxpNameReply reply = new SshFxpNameReply(id);
+ int flags = SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_SIZE;
+ reply.addFile(p, normalizedPath, getLongName(p), new FileAttributes(p, flags));
+ return reply;
+ }
+
+ private Reply doProcessRmdir(SshFxpRmdirRequest request) throws IOException {
+ int id = request.getId();
+ String path = request.getPath();
+ // attrs
+ SshFile p = resolveFile(path);
+ if (p.isDirectory()) {
+ if (p.doesExist()) {
+ if (p.listSshFiles().size() == 0) {
+ if (p.delete()) {
+ return new SshFxpStatusReply(id, SSH_FX_OK, "");
} else {
- FileHandle fh = (FileHandle) p;
- fh.write(data, offset);
- SshFile sshFile = fh.getFile();
-
- sshFile.setLastModified(new Date().getTime());
-
- sendStatus(id, SSH_FX_OK, "");
+ return new SshFxpStatusReply(id, SSH_FX_FAILURE, "Unable to delete directory " + path);
}
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
- }
- } else if ((sftpRequest instanceof SshFxpLstatRequest)
- || (sftpRequest instanceof SshFxpStatRequest)) {
- String path;
- if (sftpRequest instanceof SshFxpLstatRequest) {
- SshFxpLstatRequest sshFxpLstatRequest = (SshFxpLstatRequest) sftpRequest;
- path = sshFxpLstatRequest.getPath();
- } else {
- SshFxpStatRequest sshFxpStatRequest = (SshFxpStatRequest) sftpRequest;
- path = sshFxpStatRequest.getPath();
- }
- try {
- SshFile p = resolveFile(path);
- sendAttrs(id, p);
- } catch (FileNotFoundException e) {
- sendStatus(id, SSH_FX_NO_SUCH_FILE, e.getMessage());
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
+ } else {
+ return new SshFxpStatusReply(id, SSH_FX_DIR_NOT_EMPTY, path);
}
- } else if (sftpRequest instanceof SshFxpFstatRequest) {
- SshFxpFstatRequest sshFxpFstatRequest = (SshFxpFstatRequest) sftpRequest;
- String handle = sshFxpFstatRequest.getHandleId();
- try {
- Handle p = handles.get(handle);
- if (p == null) {
- sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
- } else {
- sendAttrs(id, p.getFile());
- }
- } catch (FileNotFoundException e) {
- sendStatus(id, SSH_FX_NO_SUCH_FILE, e.getMessage());
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
+ } else {
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_PATH, path);
+ }
+ } else {
+ return new SshFxpStatusReply(id, SSH_FX_NOT_A_DIRECTORY, p.getAbsolutePath());
+ }
+ }
+
+ private Reply doProcessMkdir(SshFxpMkdirRequest request) throws IOException {
+ int id = request.getId();
+ String path = request.getPath();
+ // attrs
+ SshFile p = resolveFile(path);
+ if (p.doesExist()) {
+ if (p.isDirectory()) {
+ return new SshFxpStatusReply(id, SSH_FX_FILE_ALREADY_EXISTS, p.getAbsolutePath());
+ } else {
+ return new SshFxpStatusReply(id, SSH_FX_NOT_A_DIRECTORY, p.getAbsolutePath());
+ }
+ } else if (!p.isWritable()) {
+ return new SshFxpStatusReply(id, SSH_FX_PERMISSION_DENIED, p.getAbsolutePath());
+ } else if (!p.mkdir()) {
+ return new SshFxpStatusReply(id, SSH_FX_FAILURE, "Error creating dir " + path);
+ } else {
+ return new SshFxpStatusReply(id, SSH_FX_OK, "");
+ }
+ }
+
+ private Reply doProcessRemove(SshFxpRemoveRequest request) throws IOException {
+ int id = request.getId();
+ String path = request.getPath();
+ SshFile p = resolveFile(path);
+ if (!p.doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_FILE, p.getAbsolutePath());
+ } else if (p.isDirectory()) {
+ return new SshFxpStatusReply(id, SSH_FX_FILE_IS_A_DIRECTORY, p.getAbsolutePath());
+ } else if (!p.delete()) {
+ return new SshFxpStatusReply(id, SSH_FX_FAILURE, "Failed to delete file");
+ } else {
+ return new SshFxpStatusReply(id, SSH_FX_OK, "");
+ }
+ }
+
+ private Reply doProcessReaddir(SshFxpReaddirRequest request) throws IOException {
+ int id = request.getId();
+ String handle = request.getHandleId();
+ Handle p = getHandle(handle);
+ if (!(p instanceof DirectoryHandle)) {
+ return new SshFxpStatusReply(id, SSH_FX_INVALID_HANDLE, handle);
+ } else if (((DirectoryHandle) p).isDone()) {
+ return new SshFxpStatusReply(id, SSH_FX_EOF, "", "");
+ } else if (!p.getFile().doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_FILE, p.getFile().getAbsolutePath());
+ } else if (!p.getFile().isDirectory()) {
+ return new SshFxpStatusReply(id, SSH_FX_NOT_A_DIRECTORY, p.getFile().getAbsolutePath());
+ } else if (!p.getFile().isReadable()) {
+ return new SshFxpStatusReply(id, SSH_FX_PERMISSION_DENIED, p.getFile().getAbsolutePath());
+ } else {
+ DirectoryHandle dh = (DirectoryHandle) p;
+ if (dh.hasNext()) {
+ // There is at least one file in the directory.
+ // Send only a few files at a time to not create packets of a too
+ // large size or have a timeout to occur.
+ Reply reply = sendName(id, dh);
+ if (!dh.hasNext()) {
+ // if no more files to send
+ dh.setDone(true);
+ dh.clearFileList();
}
- } else if (sftpRequest instanceof SshFxpOpendirRequest) {
- SshFxpOpendirRequest sshFxpOpendirRequest = (SshFxpOpendirRequest) sftpRequest;
- String path = sshFxpOpendirRequest.getPath();
- try {
- SshFile p = resolveFile(path);
- if (!p.doesExist()) {
- sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
- } else if (!p.isDirectory()) {
- sendStatus(id, SSH_FX_NOT_A_DIRECTORY, path);
- } else if (!p.isReadable()) {
- sendStatus(id, SSH_FX_PERMISSION_DENIED, path);
- } else {
- String handle = UUID.randomUUID().toString();
- handles.put(handle, new DirectoryHandle(p));
- sendHandle(id, handle);
- }
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
+ return reply;
+ } else {
+ // empty directory
+ dh.setDone(true);
+ dh.clearFileList();
+ return new SshFxpStatusReply(id, SSH_FX_EOF, "", "");
+ }
+ }
+ }
+
+ private Reply doProcessOpendir(SshFxpOpendirRequest request) throws IOException {
+ int id = request.getId();
+ String path = request.getPath();
+ SshFile p = resolveFile(path);
+ if (!p.doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_FILE, path);
+ } else if (!p.isDirectory()) {
+ return new SshFxpStatusReply(id, SSH_FX_NOT_A_DIRECTORY, path);
+ } else if (!p.isReadable()) {
+ return new SshFxpStatusReply(id, SSH_FX_PERMISSION_DENIED, path);
+ } else {
+ Handle handle = createDirectoryHandle(p);
+ return new SshFxpHandleReply(id, handle);
+ }
+ }
+
+ private Reply doProcessFstat(SshFxpFstatRequest request) throws IOException {
+ int id = request.getId();
+ String handle = request.getHandleId();
+ Handle p = getHandle(handle);
+ if (p == null) {
+ return new SshFxpStatusReply(id, SSH_FX_INVALID_HANDLE, handle);
+ } else {
+ int flags = SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_SIZE;
+ return new SshFxpAttrsReply(id, new FileAttributes(p.getFile(), flags));
+ }
+ }
+
+ private Reply doProcessStat(Request sftpRequest) throws IOException {
+ int id = sftpRequest.getId();
+ String path;
+ if (sftpRequest instanceof SshFxpLstatRequest) {
+ SshFxpLstatRequest sshFxpLstatRequest = (SshFxpLstatRequest) sftpRequest;
+ path = sshFxpLstatRequest.getPath();
+ } else {
+ SshFxpStatRequest sshFxpStatRequest = (SshFxpStatRequest) sftpRequest;
+ path = sshFxpStatRequest.getPath();
+ }
+ SshFile p = resolveFile(path);
+ if (!p.doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_FILE, p.getAbsolutePath());
+ }
+ int flags = SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_SIZE;
+ return new SshFxpAttrsReply(id, new FileAttributes(p, flags));
+ }
+
+ private Reply doProcessWrite(SshFxpWriteRequest request) throws IOException {
+ int id = request.getId();
+ String handle = request.getHandleId();
+ long offset = request.getOffset();
+ byte[] data = request.getData();
+ Handle p = getHandle(handle);
+ if (!(p instanceof FileHandle)) {
+ return new SshFxpStatusReply(id, SSH_FX_INVALID_HANDLE, handle);
+ } else {
+ FileHandle fh = (FileHandle) p;
+ fh.write(data, offset);
+ SshFile sshFile = fh.getFile();
+
+ sshFile.setLastModified(new Date().getTime());
+
+ return new SshFxpStatusReply(id, SSH_FX_OK, "");
+ }
+ }
+
+ private Reply doProcessRead(SshFxpReadRequest request) throws IOException {
+ int id = request.getId();
+ String handle = request.getHandleId();
+ long offset = request.getOffset();
+ int len = request.getLength();
+ Handle p = getHandle(handle);
+ if (!(p instanceof FileHandle)) {
+ return new SshFxpStatusReply(id, SSH_FX_INVALID_HANDLE, handle);
+ } else {
+ FileHandle fh = (FileHandle) p;
+ byte[] b = new byte[Math.min(len, 1024 * 32)];
+ len = fh.read(b, offset);
+ if (len >= 0) {
+ return new SshFxpDataReply(id, b, 0, len, len < b.length);
+ } else {
+ return new SshFxpStatusReply(id, SSH_FX_EOF, "");
+ }
+ }
+ }
+
+ private Reply doProcessClose(SshFxpCloseRequest sftpRequest) throws IOException {
+ int id = sftpRequest.getId();
+ SshFxpCloseRequest sshFxpCloseRequest = (SshFxpCloseRequest) sftpRequest;
+ String handle = sshFxpCloseRequest.getHandleId();
+ Handle h = getHandle(handle);
+ if (h == null) {
+ return new SshFxpStatusReply(id, SSH_FX_INVALID_HANDLE, handle, "");
+ } else {
+ handles.remove(handle);
+ h.close();
+ return new SshFxpStatusReply(id, SSH_FX_OK, "", "");
+ }
+ }
+
+ private Reply doProcessOpen(SshFxpOpenRequest request) throws IOException {
+ int id = request.getId();
+ if (session.getFactoryManager().getProperties() != null) {
+ String maxHandlesString = session.getFactoryManager().getProperties().get(MAX_OPEN_HANDLES_PER_SESSION);
+ if (maxHandlesString != null) {
+ int maxHandleCount = Integer.parseInt(maxHandlesString);
+ if (handles.size() > maxHandleCount) {
+ return new SshFxpStatusReply(id, SSH_FX_FAILURE, "Too many open handles");
}
- } else if (sftpRequest instanceof SshFxpReaddirRequest) {
- SshFxpReaddirRequest sshFxpReaddirRequest = (SshFxpReaddirRequest) sftpRequest;
- String handle = sshFxpReaddirRequest.getHandleId();
- try {
- Handle p = handles.get(handle);
- if (!(p instanceof DirectoryHandle)) {
- sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
- } else if (((DirectoryHandle) p).isDone()) {
- sendStatus(id, SSH_FX_EOF, "", "");
- } else if (!p.getFile().doesExist()) {
- sendStatus(id, SSH_FX_NO_SUCH_FILE, p.getFile().getAbsolutePath());
- } else if (!p.getFile().isDirectory()) {
- sendStatus(id, SSH_FX_NOT_A_DIRECTORY, p.getFile().getAbsolutePath());
- } else if (!p.getFile().isReadable()) {
- sendStatus(id, SSH_FX_PERMISSION_DENIED, p.getFile().getAbsolutePath());
- } else {
- DirectoryHandle dh = (DirectoryHandle) p;
- if (dh.hasNext()) {
- // There is at least one file in the directory.
- // Send only a few files at a time to not create packets of a too
- // large size or have a timeout to occur.
- sendName(id, dh);
- if (!dh.hasNext()) {
- // if no more files to send
- dh.setDone(true);
- dh.clearFileList();
- }
- } else {
- // empty directory
- dh.setDone(true);
- dh.clearFileList();
- sendStatus(id, SSH_FX_EOF, "", "");
- }
- }
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
+ }
+ }
+
+ int accValue = request.getAcc();
+ if (accValue == 0) {
+ String path = request.getPath();
+ int flags = request.getFlags();
+ // attrs
+ SshFile file = resolveFile(path);
+ if (file.doesExist()) {
+ if (((flags & SSH_FXF_CREAT) != 0) && ((flags & SSH_FXF_EXCL) != 0)) {
+ return new SshFxpStatusReply(id, SSH_FX_FILE_ALREADY_EXISTS, path);
}
- } else if (sftpRequest instanceof SshFxpRemoveRequest) {
- SshFxpRemoveRequest sshFxpRemoveRequest = (SshFxpRemoveRequest) sftpRequest;
- String path = sshFxpRemoveRequest.getPath();
- try {
- SshFile p = resolveFile(path);
- if (!p.doesExist()) {
- sendStatus(id, SSH_FX_NO_SUCH_FILE, p.getAbsolutePath());
- } else if (p.isDirectory()) {
- sendStatus(id, SSH_FX_FILE_IS_A_DIRECTORY, p.getAbsolutePath());
- } else if (!p.delete()) {
- sendStatus(id, SSH_FX_FAILURE, "Failed to delete file");
- } else {
- sendStatus(id, SSH_FX_OK, "");
+ } else {
+ if ((flags & SSH_FXF_CREAT) != 0) {
+ if (!file.isWritable()) {
+ return new SshFxpStatusReply(id, SSH_FX_PERMISSION_DENIED, "Can not create " + path);
}
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
+ file.create();
}
- } else if (sftpRequest instanceof SshFxpMkdirRequest) {
- SshFxpMkdirRequest sshFxpMkdirRequest = (SshFxpMkdirRequest) sftpRequest;
- String path = sshFxpMkdirRequest.getPath();
- // attrs
- try {
- SshFile p = resolveFile(path);
- if (p.doesExist()) {
- if (p.isDirectory()) {
- sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, p.getAbsolutePath());
+ }
+ if ((flags & SSH_FXF_TRUNC) != 0) {
+ file.truncate();
+ }
+ return new SshFxpHandleReply(id, createFileHandle(file, flags));
+ } else {
+ String path = request.getPath();
+ int acc = accValue;
+ int flags = request.getFlags();
+ // attrs
+ SshFile file = resolveFile(path);
+ switch (flags & SSH_FXF_ACCESS_DISPOSITION) {
+ case SSH_FXF_CREATE_NEW: {
+ if (file.doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_FILE_ALREADY_EXISTS, path);
+ } else if (!file.isWritable()) {
+ return new SshFxpStatusReply(id, SSH_FX_PERMISSION_DENIED, "Can not create " + path);
+ }
+ file.create();
+ break;
+ }
+ case SSH_FXF_CREATE_TRUNCATE: {
+ if (file.doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_FILE_ALREADY_EXISTS, path);
+ } else if (!file.isWritable()) {
+ return new SshFxpStatusReply(id, SSH_FX_PERMISSION_DENIED, "Can not create " + path);
+ }
+ file.truncate();
+ break;
+ }
+ case SSH_FXF_OPEN_EXISTING: {
+ if (!file.doesExist()) {
+ if (!file.getParentFile().doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_PATH, path);
} else {
- sendStatus(id, SSH_FX_NOT_A_DIRECTORY, p.getAbsolutePath());
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_FILE, path);
}
- } else if (!p.isWritable()) {
- sendStatus(id, SSH_FX_PERMISSION_DENIED, p.getAbsolutePath());
- } else if (!p.mkdir()) {
- throw new IOException("Error creating dir " + path);
- } else {
- sendStatus(id, SSH_FX_OK, "");
}
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
+ break;
}
- } else if (sftpRequest instanceof SshFxpRmdirRequest) {
- SshFxpRmdirRequest sshFxpRmdirRequest = (SshFxpRmdirRequest) sftpRequest;
- String path = sshFxpRmdirRequest.getPath();
- // attrs
- try {
- SshFile p = resolveFile(path);
- if (p.isDirectory()) {
- if (p.doesExist()) {
- if (p.listSshFiles().size() == 0) {
- if (p.delete()) {
- sendStatus(id, SSH_FX_OK, "");
- } else {
- sendStatus(id, SSH_FX_FAILURE, "Unable to delete directory " + path);
- }
- } else {
- sendStatus(id, SSH_FX_DIR_NOT_EMPTY, path);
- }
+ case SSH_FXF_OPEN_OR_CREATE: {
+ if (!file.doesExist()) {
+ file.create();
+ }
+ break;
+ }
+ case SSH_FXF_TRUNCATE_EXISTING: {
+ if (!file.doesExist()) {
+ if (!file.getParentFile().doesExist()) {
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_PATH, path);
} else {
- sendStatus(id, SSH_FX_NO_SUCH_PATH, path);
+ return new SshFxpStatusReply(id, SSH_FX_NO_SUCH_FILE, path);
}
- } else {
- sendStatus(id, SSH_FX_NOT_A_DIRECTORY, p.getAbsolutePath());
}
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
- }
- } else if (sftpRequest instanceof SshFxpRealpathRequest) {
- SshFxpRealpathRequest sshFxpRealpathRequest = (SshFxpRealpathRequest) sftpRequest;
- String path = sshFxpRealpathRequest.getPath();
- if (path.trim().length() == 0) {
- path = ".";
+ file.truncate();
+ break;
}
- // TODO: handle optional args
- try {
- SshFile p = resolveFile(path);
- sendPath(id, p);
- } catch (FileNotFoundException e) {
- log.error("error while resove file, cause: " + e.getMessage());
- sendStatus(id, SSH_FX_NO_SUCH_FILE, e.getMessage());
- } catch (IOException e) {
- log.error("error while resove file, cause: " + e.getMessage());
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
- }
- } else if (sftpRequest instanceof SshFxpRenameRequest) {
- SshFxpRenameRequest sshFxpRenameRequest = (SshFxpRenameRequest) sftpRequest;
- String oldPath = sshFxpRenameRequest.getOldPath();
- String newPath = sshFxpRenameRequest.getNewPath();
- try {
- SshFile o = resolveFile(oldPath);
- SshFile n = resolveFile(newPath);
- if (!o.doesExist()) {
- sendStatus(id, SSH_FX_NO_SUCH_FILE, o.getAbsolutePath());
- } else if (n.doesExist()) {
- sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, n.getAbsolutePath());
- } else if (!o.move(n)) {
- sendStatus(id, SSH_FX_FAILURE, "Failed to rename file");
- } else {
- sendStatus(id, SSH_FX_OK, "");
- }
- } catch (IOException e) {
- sendStatus(id, SSH_FX_FAILURE, e.getMessage());
- }
- } else if ((sftpRequest instanceof SshFxpSetstatRequest)
- || (sftpRequest instanceof SshFxpFsetstatRequest)) {
- // This is required for WinSCP / Cyberduck to upload properly
- // Blindly reply "OK"
- // TODO implement it
- sendStatus(id, SSH_FX_OK, "");
- } else {
- log.error("Received: {}", sftpRequest);
- sendStatus(id, SSH_FX_OP_UNSUPPORTED, "Command " + sftpRequest + " is unsupported or not implemented");
+ default:
+ throw new IllegalArgumentException("Unsupported open mode: " + flags);
+ }
+ return new SshFxpHandleReply(id, createFileHandle(file, flags));
}
}
- protected void sendHandle(int id, String handle) throws IOException {
- if (processAfterCommand(session, sftpRequest, new SshFxpHandleReply(id, handle, handles.get(handle)))) return;
- Buffer buffer = new Buffer();
- buffer.putByte((byte) SSH_FXP_HANDLE);
- buffer.putInt(id);
- buffer.putString(handle);
- send(buffer);
- }
-
- protected void sendAttrs(int id, SshFile file) throws IOException {
- if (processAfterCommand(session, sftpRequest, new SshFxpAttrsReply(id, file))) return;
- Buffer buffer = new Buffer();
- buffer.putByte((byte) SSH_FXP_ATTRS);
- buffer.putInt(id);
- writeAttrs(buffer, file);
- send(buffer);
- }
-
- protected void sendAttrs(int id, SshFile file, int flags) throws IOException {
- if (processAfterCommand(session, sftpRequest, new SshFxpAttrsReply(id, file, flags))) return;
- Buffer buffer = new Buffer();
- buffer.putByte((byte) SSH_FXP_ATTRS);
- buffer.putInt(id);
- writeAttrs(buffer, file, flags);
- send(buffer);
+ private Reply doProcessInit(SshFxpInitRequest request) throws IOException {
+ int id = request.getId();
+ version = id;
+ if (version >= LOWER_SFTP_IMPL) {
+ version = Math.min(version, HIGHER_SFTP_IMPL);
+ return new SshFxpVersionReply(version);
+ } else {
+ // We only support version >= 3 (Version 1 and 2 are not common)
+ return new SshFxpStatusReply(id, SSH_FX_OP_UNSUPPORTED, "SFTP server only support versions " + ALL_SFTP_IMPL);
+ }
}
-
- protected void sendPath(int id, SshFile f) throws IOException {
- int count = 1;
- SshFxpNameReply sshFxpNameReply = new SshFxpNameReply(id, true);
- Buffer buffer = new Buffer();
- buffer.putByte((byte) SSH_FXP_NAME);
- buffer.putInt(id);
- buffer.putInt(count);
- //normalize the given path, use *nix style separator
- String normalizedPath = SelectorUtils.normalizePath(f.getAbsolutePath(), "/");
- if (normalizedPath.length() == 0) {
- normalizedPath = "/";
- }
- buffer.putString(normalizedPath);
- f = resolveFile(normalizedPath);
- if (f.getName().length() == 0) {
- f = resolveFile(".");
- }
- String longName;
- if (version <= 3) {
- longName = getLongName(f);
- buffer.putString(longName); // Format specified in the specs
- buffer.putInt(0);
- sshFxpNameReply.addFile(f, normalizedPath, longName, 0);
- } else {
- longName = f.getName();
- buffer.putString(longName); // Supposed to be UTF-8
- writeAttrs(buffer, f);
- sshFxpNameReply.addFile(f, normalizedPath, longName, null);
- }
-
- if (processAfterCommand(session, sftpRequest, sshFxpNameReply)) return;
- send(buffer);
- }
-
- protected void sendName(int id, Iterator<SshFile> files) throws IOException {
- SshFxpNameReply sshFxpNameReply = new SshFxpNameReply(id, false);
- Buffer buffer = new Buffer();
- buffer.putByte((byte) SSH_FXP_NAME);
- buffer.putInt(id);
- int wpos = buffer.wpos();
- buffer.putInt(0);
+ protected SshFxpNameReply sendName(int id, Iterator<SshFile> files) throws IOException {
+ SshFxpNameReply reply = new SshFxpNameReply(id);
int nb = 0;
- while (files.hasNext() && buffer.wpos() < MAX_PACKET_LENGTH) {
+ while (files.hasNext() && nb < MAX_PACKET_LENGTH / 2) {
SshFile f = files.next();
String filename = f.getName();
- buffer.putString(filename);
- String longname;
if (version <= 3) {
- longname = getLongName(f);
- buffer.putString(longname); // Format specified in the specs
+ nb += 55 + filename.length() * 2;
} else {
- longname = f.getName();
- buffer.putString(longname); // Supposed to be UTF-8
+ nb += filename.length();
}
- sshFxpNameReply.addFile(f, filename, longname, null);
- writeAttrs(buffer, f);
- nb++;
- }
- int oldpos = buffer.wpos();
- buffer.wpos(wpos);
- buffer.putInt(nb);
- buffer.wpos(oldpos);
- if (processAfterCommand(session, sftpRequest, sshFxpNameReply)) return;
- send(buffer);
+ nb += 10; // Attrs size
+ int flags = SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_SIZE;
+ reply.addFile(f, filename, getLongName(f), new FileAttributes(f, flags));
+ }
+ reply.setEol(!files.hasNext());
+ return reply;
+ }
+
+ protected void send(Buffer buffer) throws IOException {
+ DataOutputStream dos = new DataOutputStream(out);
+ dos.writeInt(buffer.available());
+ dos.write(buffer.array(), buffer.rpos(), buffer.available());
+ dos.flush();
+ }
+
+ public void destroy() {
+ closed = true;
+ }
+
+ private SshFile resolveFile(String path) {
+ return this.root.getFile(path);
}
+
private String getLongName(SshFile f) {
String username = f.getOwner();
if (username.length() > 8) {
@@ -1038,111 +700,8 @@ public class SftpSubsystem implements Co
return sb.toString();
}
- protected void writeAttrs(Buffer buffer, SshFile file) throws IOException {
- writeAttrs(buffer, file, 0);
- }
-
-
- protected void writeAttrs(Buffer buffer, SshFile file, int flags) throws IOException {
- if (!file.doesExist()) {
- throw new FileNotFoundException(file.getAbsolutePath());
- }
- if (version >= 4) {
- long size = file.getSize();
- String username = session.getUsername();
- long lastModif = file.getLastModified();
- int p = 0;
- if (file.isReadable()) {
- p |= S_IRUSR;
- }
- if (file.isWritable()) {
- p |= S_IWUSR;
- }
- if (file.isExecutable()) {
- p |= S_IXUSR;
- }
- if (file.isFile()) {
- buffer.putInt(SSH_FILEXFER_ATTR_PERMISSIONS);
- buffer.putByte((byte) SSH_FILEXFER_TYPE_REGULAR);
- buffer.putInt(p);
- } else if (file.isDirectory()) {
- buffer.putInt(SSH_FILEXFER_ATTR_PERMISSIONS);
- buffer.putByte((byte) SSH_FILEXFER_TYPE_DIRECTORY);
- buffer.putInt(p);
- } else {
- buffer.putInt(0);
- buffer.putByte((byte) SSH_FILEXFER_TYPE_UNKNOWN);
- }
- } else {
- int p = 0;
- if (file.isFile()) {
- p |= 0100000;
- }
- if (file.isDirectory()) {
- p |= 0040000;
- }
- if (file.isReadable()) {
- p |= 0000400;
- }
- if (file.isWritable()) {
- p |= 0000200;
- }
- if (file.isExecutable()) {
- p |= 0000100;
- }
- if (file.isFile()) {
- buffer.putInt(SSH_FILEXFER_ATTR_SIZE| SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
- buffer.putLong(file.getSize());
- buffer.putInt(p);
- buffer.putInt(file.getLastModified()/1000);
- buffer.putInt(file.getLastModified()/1000);
- } else if (file.isDirectory()) {
- buffer.putInt(SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
- buffer.putInt(p);
- buffer.putInt(file.getLastModified()/1000);
- buffer.putInt(file.getLastModified()/1000);
- } else {
- buffer.putInt(0);
- }
- }
- }
-
- protected void sendStatus(int id, int substatus, String msg) throws IOException {
- sendStatus(id, substatus, msg, "");
- }
-
- protected void sendStatus(int id, int substatus, String msg, String lang) throws IOException {
- if (processAfterCommand(session, sftpRequest, new SshFxpStatusReply(id, substatus, msg, lang))) return;
- sendStatusStrict(id, substatus, msg, lang);
- }
-
- protected void sendStatusStrict(int id, int substatus, String msg, String lang) throws IOException {
- Buffer buffer = new Buffer();
- buffer.putByte((byte) SSH_FXP_STATUS);
- buffer.putInt(id);
- buffer.putInt(substatus);
- buffer.putString(msg);
- buffer.putString(lang);
- send(buffer);
- }
-
- protected void send(Buffer buffer) throws IOException {
- DataOutputStream dos = new DataOutputStream(out);
- dos.writeInt(buffer.available());
- dos.write(buffer.array(), buffer.rpos(), buffer.available());
- dos.flush();
- }
-
- public void destroy() {
- closed = true;
- }
-
- private SshFile resolveFile(String path) {
- return this.root.getFile(path);
- }
-
- private final static String[] MONTHS = { "Jan", "Feb", "Mar", "Apr", "May",
- "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ private final static String[] MONTHS = {"Jan", "Feb", "Mar", "Apr", "May",
+ "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
/**
* Get unix style date string.
@@ -1196,179 +755,4 @@ public class SftpSubsystem implements Co
return sb.toString();
}
-
- protected Request getSftpRequest(final Buffer buffer) {
- Request sftpRequest;
-
- int length = buffer.getInt();
- int type = buffer.getByte();
- int id = buffer.getInt();
-
- switch (type) {
- case SSH_FXP_INIT:
- if (length != 5) {
- throw new IllegalArgumentException();
- }
- sftpRequest = new SshFxpInitRequest(id);
- break;
- case SSH_FXP_OPEN:
- if (version <= 4) {
- String path = buffer.getString();
- int pflags = buffer.getInt();
- sftpRequest = new SshFxpOpenRequest(id, path, pflags);
- } else {
- String path = buffer.getString();
- int acc = buffer.getInt();
- int flags = buffer.getInt();
- sftpRequest = new SshFxpOpenRequest(id, path, acc, flags);
- }
- break;
- case SSH_FXP_CLOSE: {
- String handleId = buffer.getString();
- Handle handle = handles.get(handleId);
- sftpRequest = new SshFxpCloseRequest(id, handleId, handle);
- } break;
- case SSH_FXP_READ: {
- String handleId = buffer.getString();
- long offset = buffer.getLong();
- int len = buffer.getInt();
- Handle handle = handles.get(handleId);
- sftpRequest = new SshFxpReadRequest(id, handleId, offset, len, handle);
- } break;
- case SSH_FXP_WRITE: {
- String handleId = buffer.getString();
- long offset = buffer.getLong();
- byte[] data = buffer.getBytes();
- Handle handle = handles.get(handleId);
- sftpRequest = new SshFxpWriteRequest(id, handleId, offset, data, handle);
- } break;
- case SSH_FXP_STAT: {
- String path = buffer.getString();
- sftpRequest = new SshFxpStatRequest(id, path);
- } break;
- case SSH_FXP_LSTAT: {
- String path = buffer.getString();
- sftpRequest = new SshFxpLstatRequest(id, path);
- } break;
- case SSH_FXP_FSTAT: {
- String handle = buffer.getString();
- Handle p = handles.get(handle);
- sftpRequest = new SshFxpFstatRequest(id, handle, p);
- } break;
- case SSH_FXP_OPENDIR: {
- String path = buffer.getString();
- sftpRequest = new SshFxpOpendirRequest(id, path);
- } break;
- case SSH_FXP_READDIR:
- String handle = buffer.getString();
- Handle p = handles.get(handle);
- sftpRequest = new SshFxpReaddirRequest(id, handle, p);
- break;
- case SSH_FXP_REMOVE: {
- String path = buffer.getString();
- sftpRequest = new SshFxpRemoveRequest(id, path);
- } break;
- case SSH_FXP_MKDIR: {
- String path = buffer.getString();
- sftpRequest = new SshFxpMkdirRequest(id, path);
- } break;
- case SSH_FXP_RMDIR: {
- String path = buffer.getString();
- sftpRequest = new SshFxpRmdirRequest(id, path);
- } break;
- case SSH_FXP_REALPATH:
- String path = buffer.getString();
- sftpRequest = new SshFxpRealpathRequest(id, path);
- break;
- case SSH_FXP_RENAME:
- final String oldPath = buffer.getString();
- final String newPath = buffer.getString();
- sftpRequest = new SshFxpRenameRequest(id, oldPath, newPath);
- break;
- case SSH_FXP_SETSTAT:
- sftpRequest = new SshFxpSetstatRequest(id);
- break;
- case SSH_FXP_FSETSTAT:
- sftpRequest = new SshFxpFsetstatRequest(id);
- break;
- default:
- sftpRequest = new UnsupportedRequest(id, type);
- }
-
- return sftpRequest;
- }
-
- private boolean processAfterCommand(final ServerSession session2, final Request sftpRequest2, final Reply sftpReply)
- throws IOException {
- Reply reply = sftpLet.afterCommand(session2, sftpRequest2, sftpReply);
-
- if (reply == null) {
- return false;
- } else {
- sendReply(sftpReply);
- return true;
- }
- }
-
- private void sendReply(final Reply sftpReply) throws IOException {
- if (sftpReply instanceof SshFxpAttrsReply) {
- SshFxpAttrsReply sshFxpAttrsReply = (SshFxpAttrsReply) sftpReply;
- int id = sshFxpAttrsReply.getId();
- SshFile file = sshFxpAttrsReply.getFile();
- Integer flags = sshFxpAttrsReply.getFlags();
- if (flags == null) {
- sendAttrs(id, file);
- } else {
- sendAttrs(id, file, flags);
- }
- } else if (sftpReply instanceof SshFxpDataReply) {
- SshFxpDataReply sshFxpDataReply = (SshFxpDataReply) sftpReply;
- long id = sshFxpDataReply.getId();
- byte[] data = sshFxpDataReply.getData();
- Boolean lenflag = sshFxpDataReply.getLenFlag();
-
- int len = data.length;
- Buffer buf = new Buffer(len + 5);
- buf.putByte((byte) SSH_FXP_DATA);
- buf.putInt(id);
- buf.putBytes(data, 0, len);
- if (version >= 6) {
- buf.putBoolean(lenflag);
- }
- send(buf);
- } else if (sftpReply instanceof SshFxpHandleReply) {
- SshFxpHandleReply sshFxpHandleReply = (SshFxpHandleReply) sftpReply;
- int id = sshFxpHandleReply.getId();
- String handle = sshFxpHandleReply.getHandle();
-
- sendHandle(id, handle);
- } else if (sftpReply instanceof SshFxpNameReply) {
- SshFxpNameReply sshFxpNameReply = (SshFxpNameReply) sftpReply;
- int id = sshFxpNameReply.getId();
-
- Iterator<SshFile> files = sshFxpNameReply.getFiles();
-
- if (sshFxpNameReply.isSendPath()) {
- SshFile file = files.next();
- sendPath(id, file);
- } else {
- sendName(id, files);
- }
- } else if (sftpReply instanceof SshFxpStatusReply) {
- SshFxpStatusReply sshFxpStatusReply = (SshFxpStatusReply) sftpReply;
-
- int id = sshFxpStatusReply.getId();
- int substatus = sshFxpStatusReply.getSubstatus();
- String msg = sshFxpStatusReply.getMsg();
- String lang = sshFxpStatusReply.getLang();
- sendStatusStrict(id, substatus, msg, lang);
- } else if (sftpReply instanceof SshFxpVersionReply) {
- SshFxpVersionReply sshFxpVersionReply = (SshFxpVersionReply) sftpReply;
- Buffer buffer = new Buffer();
- buffer.putByte((byte) SftpSubsystem.SSH_FXP_VERSION);
- int version = sshFxpVersionReply.getVersion();
- buffer.putInt(version);
- send(buffer);
- }
- }
}
Added: mina/sshd/trunk/sshd-sftp/src/test/java/org/apache/sshd/sftp/SftpTest.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-sftp/src/test/java/org/apache/sshd/sftp/SftpTest.java?rev=1434658&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-sftp/src/test/java/org/apache/sshd/sftp/SftpTest.java (added)
+++ mina/sshd/trunk/sshd-sftp/src/test/java/org/apache/sshd/sftp/SftpTest.java Thu Jan 17 13:09:51 2013
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.sftp;
+
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.Logger;
+import com.jcraft.jsch.UserInfo;
+import org.apache.sshd.SshServer;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.ScpCommandFactory;
+import org.apache.sshd.sftp.subsystem.SftpSubsystem;
+import org.apache.sshd.sftp.util.BogusPasswordAuthenticator;
+import org.apache.sshd.sftp.util.EchoShellFactory;
+import org.apache.sshd.sftp.util.Utils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.io.*;
+import java.net.ServerSocket;
+import java.util.Arrays;
+import java.util.Vector;
+
+import static org.junit.Assert.*;
+
+public class SftpTest {
+
+ private SshServer sshd;
+ private int port;
+ private com.jcraft.jsch.Session session;
+
+ @Before
+ public void setUp() throws Exception {
+ ServerSocket s = new ServerSocket(0);
+ port = s.getLocalPort();
+ s.close();
+
+ sshd = SshServer.setUpDefaultServer();
+ sshd.setPort(port);
+ sshd.setKeyPairProvider(Utils.createTestHostKeyProvider());
+ sshd.setSubsystemFactories(Arrays.<NamedFactory<Command>>asList(new SftpSubsystem.Factory()));
+ sshd.setCommandFactory(new ScpCommandFactory());
+ sshd.setShellFactory(new EchoShellFactory());
+ sshd.setPasswordAuthenticator(new BogusPasswordAuthenticator());
+ sshd.start();
+
+ JSch sch = new JSch();
+ sch.setLogger(new Logger() {
+ public boolean isEnabled(int i) {
+ return true;
+ }
+
+ public void log(int i, String s) {
+ System.out.println("Log(jsch," + i + "): " + s);
+ }
+ });
+ session = sch.getSession("sshd", "localhost", port);
+ session.setUserInfo(new UserInfo() {
+ public String getPassphrase() {
+ return null;
+ }
+
+ public String getPassword() {
+ return "sshd";
+ }
+
+ public boolean promptPassword(String message) {
+ return true;
+ }
+
+ public boolean promptPassphrase(String message) {
+ return false;
+ }
+
+ public boolean promptYesNo(String message) {
+ return true;
+ }
+
+ public void showMessage(String message) {
+ }
+ });
+ session.connect();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ session.disconnect();
+ sshd.stop();
+ }
+
+ @Test
+ @Ignore
+ public void testExternal() throws Exception {
+ System.out.println("SFTP subsystem available on port " + port);
+ Thread.sleep(5 * 60000);
+ }
+
+ @Test
+ public void testSftp() throws Exception {
+ String d = "0123456789\n";
+
+ File root = new File("target/scp");
+ File target = new File("target/scp/out.txt");
+ root.mkdirs();
+ assertTrue(root.exists());
+
+ for (int j = 10; j <= 10; j++) {
+ String data = "";
+ for (int i = 0; i < j; i++) {
+ data = data + d;
+ }
+
+ target.delete();
+ assertFalse(target.exists());
+ sendFile("target/scp/out.txt", data);
+ assertFileLength(target, data.length(), 5000);
+
+ target.delete();
+ assertFalse(target.exists());
+ }
+ root.delete();
+ }
+
+ @Test
+ public void testReadWriteWithOffset() throws Exception {
+ File root = new File("target/scp");
+ String unixPath = "target/scp/out.txt";
+ File target = new File(unixPath);
+ root.mkdirs();
+ assertTrue(root.exists());
+
+ ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ c.connect();
+ c.put(new ByteArrayInputStream("0123456789".getBytes()), unixPath);
+
+ assertTrue(target.exists());
+ assertEquals("0123456789", readFile(unixPath));
+
+ OutputStream os = c.put(unixPath, null, ChannelSftp.APPEND, -5);
+ os.write("a".getBytes());
+ os.close();
+ c.disconnect();
+
+ assertTrue(target.exists());
+ assertEquals("01234a", readFile(unixPath));
+
+ target.delete();
+ assertFalse(target.exists());
+ root.delete();
+ }
+
+ @Test
+ public void testReadDir() throws Exception {
+ ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ c.connect();
+ Vector res = c.ls("target/classes/org/apache/sshd/");
+ for (Object f : res) {
+ System.out.println(f.toString());
+ }
+ }
+
+ protected void assertFileLength(File file, long length, long timeout) throws Exception {
+ boolean ok = false;
+ while (timeout > 0) {
+ if (file.exists() && file.length() == length) {
+ if (!ok) {
+ ok = true;
+ } else {
+ return;
+ }
+ } else {
+ ok = false;
+ }
+ Thread.sleep(100);
+ timeout -= 100;
+ }
+ assertTrue(file.exists());
+ assertEquals(length, file.length());
+ }
+
+ protected String readFile(String path) throws Exception {
+ ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ c.connect();
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ InputStream is = c.get(path);
+ try {
+ byte[] buffer = new byte[256];
+ int count;
+ while (-1 != (count = is.read(buffer))) {
+ bos.write(buffer, 0, count);
+ }
+ } finally {
+ is.close();
+ }
+
+ c.disconnect();
+ return new String(bos.toByteArray());
+ }
+
+ protected void sendFile(String path, String data) throws Exception {
+ ChannelSftp c = (ChannelSftp) session.openChannel("sftp");
+ c.connect();
+ c.put(new ByteArrayInputStream(data.getBytes()), path);
+ c.disconnect();
+ }
+
+}
Added: mina/sshd/trunk/sshd-sftp/src/test/java/org/apache/sshd/sftp/util/BogusPasswordAuthenticator.java
URL: http://svn.apache.org/viewvc/mina/sshd/trunk/sshd-sftp/src/test/java/org/apache/sshd/sftp/util/BogusPasswordAuthenticator.java?rev=1434658&view=auto
==============================================================================
--- mina/sshd/trunk/sshd-sftp/src/test/java/org/apache/sshd/sftp/util/BogusPasswordAuthenticator.java (added)
+++ mina/sshd/trunk/sshd-sftp/src/test/java/org/apache/sshd/sftp/util/BogusPasswordAuthenticator.java Thu Jan 17 13:09:51 2013
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.sftp.util;
+
+import org.apache.sshd.server.PasswordAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class BogusPasswordAuthenticator implements PasswordAuthenticator {
+
+ public boolean authenticate(String username, String password, ServerSession session) {
+ return username != null && username.equals(password);
+ }
+}