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/07/22 20:37:03 UTC
[6/9] Provide an SFTP client
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/21c1cee9/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
index ef555a1..39f80f9 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/sftp/SftpSubsystem.java
@@ -83,161 +83,77 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
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_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_SYMLINK = 20;
+ 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_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_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_FILEXFER_ATTR_SIZE = 0x00000001;
+ public static final int SSH_FILEXFER_ATTR_UIDGID = 0x00000002;
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_FILEXFER_ATTR_ACMODTIME = 0x00000008; //v3 naming convention
+ public static final int SSH_FILEXFER_ATTR_EXTENDED = 0x80000000;
+
+ 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 SSH_FXP_REALPATH_NO_CHECK = 0x00000001;
- public static final int SSH_FXP_REALPATH_STAT_IF = 0x00000002;
- public static final int SSH_FXP_REALPATH_STAT_ALWAYS = 0x00000003;
-
- 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;
+ 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 S_IFMT = 0170000; // bitmask for the file type bitfields
+ public static final int S_IFSOCK = 0140000; // socket
+ public static final int S_IFLNK = 0120000; // symbolic link
+ public static final int S_IFREG = 0100000; // regular file
+ public static final int S_IFBLK = 0060000; // block device
+ public static final int S_IFDIR = 0040000; // directory
+ public static final int S_IFCHR = 0020000; // character device
+ public static final int S_IFIFO = 0010000; // fifo
+ public static final int S_ISUID = 0004000; // set UID bit
+ public static final int S_ISGID = 0002000; // set GID bit
+ public static final int S_ISVTX = 0001000; // sticky bit
+ 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;
private ExitCallback callback;
@@ -254,91 +170,6 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
private Map<String, Handle> handles = new HashMap<String, Handle>();
- 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 abstract class Handle {
SshFile file;
@@ -572,103 +403,35 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
}
}
- if (version <= 4) {
- String path = buffer.getString();
- int pflags = buffer.getInt();
- // 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);
+ String path = buffer.getString();
+ int pflags = buffer.getInt();
+ // attrs
+ try {
+ SshFile file = resolveFile(path);
+ if (file.doesExist()) {
+ if (((pflags & SSH_FXF_CREAT) != 0) && ((pflags & SSH_FXF_EXCL) != 0)) {
+ sendStatus(id, SSH_FX_FAILURE, path);
+ return;
+ }
+ } else {
+ if (((pflags & SSH_FXF_CREAT) != 0)) {
+ if (!file.isWritable()) {
+ sendStatus(id, SSH_FX_PERMISSION_DENIED, "Can not create " + 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();
+ file.create();
}
- 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 = buffer.getString();
- int acc = buffer.getInt();
- int flags = buffer.getInt();
- // 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());
+ 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());
}
break;
}
@@ -677,7 +440,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
try {
Handle h = handles.get(handle);
if (h == null) {
- sendStatus(id, SSH_FX_INVALID_HANDLE, handle, "");
+ sendStatus(id, SSH_FX_FAILURE, handle, "");
} else {
handles.remove(handle);
h.close();
@@ -695,7 +458,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
try {
Handle p = handles.get(handle);
if (!(p instanceof FileHandle)) {
- sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
+ sendStatus(id, SSH_FX_FAILURE, handle);
} else {
FileHandle fh = (FileHandle) p;
byte[] b = new byte[Math.min(len, 1024 * 32)];
@@ -705,9 +468,6 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
buf.putByte((byte) SSH_FXP_DATA);
buf.putInt(id);
buf.putBytes(b, 0, len);
- if (version >= 6) {
- buf.putBoolean(len == 0);
- }
send(buf);
} else {
sendStatus(id, SSH_FX_EOF, "");
@@ -725,7 +485,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
try {
Handle p = handles.get(handle);
if (!(p instanceof FileHandle)) {
- sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
+ sendStatus(id, SSH_FX_FAILURE, handle);
} else {
FileHandle fh = (FileHandle) p;
fh.write(data, offset);
@@ -758,7 +518,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
try {
Handle p = handles.get(handle);
if (p == null) {
- sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
+ sendStatus(id, SSH_FX_FAILURE, handle);
} else {
sendAttrs(id, p.getFile());
}
@@ -776,7 +536,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
if (!p.doesExist()) {
sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
} else if (!p.isDirectory()) {
- sendStatus(id, SSH_FX_NOT_A_DIRECTORY, path);
+ sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
} else if (!p.isReadable()) {
sendStatus(id, SSH_FX_PERMISSION_DENIED, path);
} else {
@@ -794,13 +554,13 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
try {
Handle p = handles.get(handle);
if (!(p instanceof DirectoryHandle)) {
- sendStatus(id, SSH_FX_INVALID_HANDLE, handle);
+ sendStatus(id, SSH_FX_FAILURE, 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());
+ sendStatus(id, SSH_FX_NO_SUCH_FILE, p.getFile().getAbsolutePath());
} else if (!p.getFile().isReadable()) {
sendStatus(id, SSH_FX_PERMISSION_DENIED, p.getFile().getAbsolutePath());
} else {
@@ -834,7 +594,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
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());
+ sendStatus(id, SSH_FX_NO_SUCH_FILE, p.getAbsolutePath());
} else if (!p.delete()) {
sendStatus(id, SSH_FX_FAILURE, "Failed to delete file");
} else {
@@ -852,9 +612,9 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
SshFile p = resolveFile(path);
if (p.doesExist()) {
if (p.isDirectory()) {
- sendStatus(id, SSH_FX_FILE_ALREADY_EXISTS, p.getAbsolutePath());
+ sendStatus(id, SSH_FX_FAILURE, p.getAbsolutePath());
} else {
- sendStatus(id, SSH_FX_NOT_A_DIRECTORY, p.getAbsolutePath());
+ sendStatus(id, SSH_FX_NO_SUCH_FILE, p.getAbsolutePath());
}
} else if (!p.isWritable()) {
sendStatus(id, SSH_FX_PERMISSION_DENIED, p.getAbsolutePath());
@@ -882,13 +642,13 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
sendStatus(id, SSH_FX_FAILURE, "Unable to delete directory " + path);
}
} else {
- sendStatus(id, SSH_FX_DIR_NOT_EMPTY, path);
+ sendStatus(id, SSH_FX_FAILURE, path);
}
} else {
- sendStatus(id, SSH_FX_NO_SUCH_PATH, path);
+ sendStatus(id, SSH_FX_NO_SUCH_FILE, path);
}
} else {
- sendStatus(id, SSH_FX_NOT_A_DIRECTORY, p.getAbsolutePath());
+ sendStatus(id, SSH_FX_NO_SUCH_FILE, p.getAbsolutePath());
}
} catch (IOException e) {
sendStatus(id, SSH_FX_FAILURE, e.getMessage());
@@ -900,20 +660,9 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
if (path.trim().length() == 0) {
path = ".";
}
- byte options = SSH_FXP_REALPATH_NO_CHECK;
- List<String> compose = new ArrayList<String>();
- if (version >= 6 && buffer.available() > 0) {
- options = buffer.getByte();
- }
- while (version >= 6 && buffer.available() > 0) {
- compose.add(buffer.getString());
- }
try {
SshFile p = resolveFile(path);
- for (String s : compose) {
- p = this.root.getFile(p, s);
- }
- sendPath(id, p, options);
+ sendPath(id, p);
} catch (FileNotFoundException e) {
e.printStackTrace();
sendStatus(id, SSH_FX_NO_SUCH_FILE, e.getMessage());
@@ -932,7 +681,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
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());
+ sendStatus(id, SSH_FX_FAILURE, n.getAbsolutePath());
} else if (!o.move(n)) {
sendStatus(id, SSH_FX_FAILURE, "Failed to rename file");
} else {
@@ -976,16 +725,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
send(buffer);
}
- protected void sendAttrs(int id, SshFile file, int flags) throws IOException {
- Buffer buffer = new Buffer();
- buffer.putByte((byte) SSH_FXP_ATTRS);
- buffer.putInt(id);
- writeAttrs(buffer, file, flags);
- send(buffer);
- }
-
-
- protected void sendPath(int id, SshFile f, byte options) throws IOException {
+ protected void sendPath(int id, SshFile f) throws IOException {
Buffer buffer = new Buffer();
buffer.putByte((byte) SSH_FXP_NAME);
buffer.putInt(id);
@@ -1000,19 +740,8 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
if (f.getName().length() == 0) {
f = resolveFile(".");
}
- if (options == SSH_FXP_REALPATH_STAT_IF && f.doesExist() || options == SSH_FXP_REALPATH_STAT_ALWAYS) {
- buffer.putString(f.getName()); // Supposed to be UTF-8
- writeAttrs(buffer, f);
- } else {
- if (version <= 3) {
- buffer.putString(getLongName(f)); // Format specified in the specs
- buffer.putInt(0);
- } else if (version >= 4 || options == SSH_FXP_REALPATH_NO_CHECK) {
- buffer.putString(f.getName());
- buffer.putInt(0);
- buffer.putByte((byte) 0);
- }
- }
+ buffer.putString(getLongName(f)); // Format specified in the specs
+ buffer.putInt(0);
send(buffer);
}
@@ -1026,11 +755,7 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
while (files.hasNext() && buffer.wpos() < MAX_PACKET_LENGTH) {
SshFile f = files.next();
buffer.putString(f.getName());
- if (version <= 3) {
- buffer.putString(getLongName(f)); // Format specified in the specs
- } else {
- buffer.putString(f.getName()); // Supposed to be UTF-8
- }
+ buffer.putString(getLongName(f)); // Format specified in the specs
writeAttrs(buffer, f);
nb++;
}
@@ -1041,8 +766,9 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
send(buffer);
}
- private String getLongName(SshFile f) {
- String username = f.getOwner();
+ private String getLongName(SshFile f) throws IOException {
+ Map<SshFile.Attribute, Object> attributes = f.getAttributes();
+ String username = (String) attributes.get(SshFile.Attribute.Owner);
if (username.length() > 8) {
username = username.substring(0, 8);
} else {
@@ -1050,31 +776,43 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
username = username + " ";
}
}
+ String group = (String) attributes.get(SshFile.Attribute.Group);
+ if (group.length() > 8) {
+ group = group.substring(0, 8);
+ } else {
+ for (int i = group.length(); i < 8; i++) {
+ group = group + " ";
+ }
+ }
- long length = f.getSize();
+ long length = (Long) attributes.get(SshFile.Attribute.Size);
String lengthString = String.format("%1$8s", length);
+ boolean isDirectory = (Boolean) attributes.get(SshFile.Attribute.IsDirectory);
+ boolean isLink = (Boolean) attributes.get(SshFile.Attribute.IsSymbolicLink);
+ int perms = (Integer) attributes.get(SshFile.Attribute.Permissions);
+
StringBuilder sb = new StringBuilder();
- sb.append((f.isDirectory() ? "d" : "-"));
- sb.append((f.isReadable() ? "r" : "-"));
- sb.append((f.isWritable() ? "w" : "-"));
- sb.append((f.isExecutable() ? "x" : "-"));
- sb.append((f.isReadable() ? "r" : "-"));
- sb.append((f.isWritable() ? "w" : "-"));
- sb.append((f.isExecutable() ? "x" : "-"));
- sb.append((f.isReadable() ? "r" : "-"));
- sb.append((f.isWritable() ? "w" : "-"));
- sb.append((f.isExecutable() ? "x" : "-"));
+ sb.append(isDirectory ? "d" : isLink ? "l" : "-");
+ sb.append((perms & 0000400) != 0 ? "r" : "-");
+ sb.append((perms & 0000200) != 0 ? "w" : "-");
+ sb.append((perms & 0000100) != 0 ? "x" : "-");
+ sb.append((perms & 0000040) != 0 ? "r" : "-");
+ sb.append((perms & 0000020) != 0 ? "w" : "-");
+ sb.append((perms & 0000010) != 0 ? "x" : "-");
+ sb.append((perms & 0000004) != 0 ? "r" : "-");
+ sb.append((perms & 0000002) != 0 ? "w" : "-");
+ sb.append((perms & 0000001) != 0 ? "x" : "-");
sb.append(" ");
sb.append(" 1");
sb.append(" ");
sb.append(username);
sb.append(" ");
- sb.append(username);
+ sb.append(group);
sb.append(" ");
sb.append(lengthString);
sb.append(" ");
- sb.append(getUnixDate(f.getLastModified()));
+ sb.append(getUnixDate((Long) attributes.get(SshFile.Attribute.LastModifiedTime)));
sb.append(" ");
sb.append(f.getName());
@@ -1082,76 +820,39 @@ public class SftpSubsystem implements Command, Runnable, SessionAware, FileSyste
}
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);
- }
+ Map<SshFile.Attribute, Object> attributes = file.getAttributes();
+ boolean isReg = (Boolean) attributes.get(SshFile.Attribute.IsRegularFile);
+ boolean isDir = (Boolean) attributes.get(SshFile.Attribute.IsDirectory);
+ boolean isLnk = (Boolean) attributes.get(SshFile.Attribute.IsSymbolicLink);
+ int p = (Integer) attributes.get(SshFile.Attribute.Permissions);
+ p |= isReg ? S_IFREG : 0;
+ p |= isDir ? S_IFDIR : 0;
+ p |= isLnk ? S_IFLNK : 0;
+ if (isReg) {
+ buffer.putInt(SSH_FILEXFER_ATTR_SIZE | SSH_FILEXFER_ATTR_UIDGID | SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
+ buffer.putLong((Long) attributes.get(SshFile.Attribute.Size));
+ buffer.putInt((Integer) attributes.get(SshFile.Attribute.Uid));
+ buffer.putInt((Integer) attributes.get(SshFile.Attribute.Gid));
+ buffer.putInt(p);
+ buffer.putInt(((Long) attributes.get(SshFile.Attribute.LastAccessTime)) / 1000);
+ buffer.putInt(((Long) attributes.get(SshFile.Attribute.LastModifiedTime)) / 1000);
+ } else if (isDir || isLnk) {
+ buffer.putInt(SSH_FILEXFER_ATTR_UIDGID | SSH_FILEXFER_ATTR_PERMISSIONS | SSH_FILEXFER_ATTR_ACMODTIME);
+ buffer.putInt((Integer) attributes.get(SshFile.Attribute.Uid));
+ buffer.putInt((Integer) attributes.get(SshFile.Attribute.Gid));
+ buffer.putInt(p);
+ buffer.putInt(((Long) attributes.get(SshFile.Attribute.LastAccessTime)) / 1000);
+ buffer.putInt(((Long) attributes.get(SshFile.Attribute.LastModifiedTime)) / 1000);
} 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);
- }
+ buffer.putInt(0);
}
}
protected void sendStatus(int id, int substatus, String msg) throws IOException {
- sendStatus(id, mapToVersion(substatus), msg, "");
+ sendStatus(id, substatus, msg, "");
}
protected void sendStatus(int id, int substatus, String msg, String lang) throws IOException {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/21c1cee9/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
index 7259b61..94af9a5 100644
--- a/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/SftpTest.java
@@ -25,12 +25,14 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.util.Arrays;
+import java.util.EnumSet;
import java.util.Vector;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Logger;
import com.jcraft.jsch.UserInfo;
+import org.apache.sshd.client.SftpClient;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.command.ScpCommandFactory;
@@ -39,10 +41,13 @@ import org.apache.sshd.util.BogusPasswordAuthenticator;
import org.apache.sshd.util.EchoShellFactory;
import org.apache.sshd.util.Utils;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -120,6 +125,62 @@ public class SftpTest {
}
@Test
+ public void testClient() throws Exception {
+ SshClient client = SshClient.setUpDefaultClient();
+ client.start();
+ ClientSession session = client.connect("localhost", port).await().getSession();
+ session.authPassword("x", "x").await();
+
+ new File("target/scp").mkdirs();
+ new File("target/scp/client/test.txt").delete();
+ new File("target/scp/client").delete();
+
+ SftpClient sftp = session.createSftpClient();
+
+ sftp.mkdir("target/scp/client");
+
+ SftpClient.Handle h = sftp.open("target/scp/client/test.txt", EnumSet.of(SftpClient.OpenMode.Write));
+ byte[] d = "0123456789\n".getBytes();
+ sftp.write(h, 0, d, 0, d.length);
+ sftp.write(h, d.length, d, 0, d.length);
+
+ SftpClient.Attributes attrs = sftp.stat(h);
+ Assert.assertNotNull(attrs);
+
+ sftp.close(h);
+
+ h = sftp.openDir("target/scp/client");
+ SftpClient.DirEntry[] dir = sftp.readDir(h);
+ assertNotNull(dir);
+ assertEquals(1, dir.length);
+ assertNull(sftp.readDir(h));
+ sftp.close(h);
+
+ sftp.remove("target/scp/client/test.txt");
+
+ OutputStream os = sftp.write("target/scp/client/test.txt");
+ os.write(new byte[1024 * 128]);
+ os.close();
+
+ InputStream is = sftp.read("target/scp/client/test.txt");
+ is.read(new byte[1024 * 128]);
+ int i = is.read();
+ is.close();
+
+ int nb = 0;
+ for (SftpClient.DirEntry entry : sftp.readDir("target/scp/client")) {
+ nb++;
+ }
+ assertEquals(1, nb);
+
+ sftp.remove("target/scp/client/test.txt");
+
+ sftp.rmdir("target/scp/client/");
+
+ client.stop();
+ }
+
+ @Test
public void testSftp() throws Exception {
String d = "0123456789\n";
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/21c1cee9/sshd-sftp/src/main/java/org/apache/sshd/sftp/reply/SshFxpStatusReply.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/reply/SshFxpStatusReply.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/reply/SshFxpStatusReply.java
index 8e5cfee..9722480 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/reply/SshFxpStatusReply.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/reply/SshFxpStatusReply.java
@@ -20,9 +20,10 @@ package org.apache.sshd.sftp.reply;
import java.io.IOException;
-import org.apache.sshd.server.sftp.SftpSubsystem;
import org.apache.sshd.sftp.subsystem.SftpConstants;
+import static org.apache.sshd.sftp.subsystem.SftpConstants.*;
+
/**
* Data container for 'SSH_FXP_STATUS' reply.
*
@@ -67,52 +68,52 @@ public class SshFxpStatusReply extends BaseReply {
this.msg = msg;
switch (substatus) {
- case SftpSubsystem.SSH_FX_FILE_ALREADY_EXISTS:
+ case SSH_FX_FILE_ALREADY_EXISTS:
substatusAsSTR = "SSH_FX_FILE_ALREADY_EXISTS";
break;
- case SftpSubsystem.SSH_FX_DIR_NOT_EMPTY:
+ case SSH_FX_DIR_NOT_EMPTY:
substatusAsSTR = "SSH_FX_DIR_NOT_EMPTY";
break;
- case SftpSubsystem.SSH_FX_EOF:
+ case SSH_FX_EOF:
substatusAsSTR = "SSH_FX_EOF";
break;
- case SftpSubsystem.SSH_FX_FILE_IS_A_DIRECTORY:
+ case SSH_FX_FILE_IS_A_DIRECTORY:
substatusAsSTR = "SSH_FX_FILE_IS_A_DIRECTORY";
break;
- case SftpSubsystem.SSH_FX_INVALID_HANDLE:
+ case SSH_FX_INVALID_HANDLE:
substatusAsSTR = "SSH_FX_INVALID_HANDLE";
break;
- case SftpSubsystem.SSH_FX_NO_SUCH_FILE:
+ case SSH_FX_NO_SUCH_FILE:
substatusAsSTR = "SSH_FX_NO_SUCH_FILE";
break;
- case SftpSubsystem.SSH_FX_NO_SUCH_PATH:
+ case SSH_FX_NO_SUCH_PATH:
substatusAsSTR = "SSH_FX_NO_SUCH_PATH";
break;
- case SftpSubsystem.SSH_FX_NOT_A_DIRECTORY:
+ case SSH_FX_NOT_A_DIRECTORY:
substatusAsSTR = "SSH_FX_NOT_A_DIRECTORY";
break;
- case SftpSubsystem.SSH_FX_OK:
+ case SSH_FX_OK:
substatusAsSTR = "SSH_FX_OK";
break;
- case SftpSubsystem.SSH_FX_OP_UNSUPPORTED:
+ case SSH_FX_OP_UNSUPPORTED:
substatusAsSTR = "SSH_FX_OP_UNSUPPORTED";
break;
- case SftpSubsystem.SSH_FX_FAILURE:
+ case SSH_FX_FAILURE:
substatusAsSTR = "SSH_FX_FAILURE";
break;
- case SftpSubsystem.SSH_FX_PERMISSION_DENIED:
+ case SSH_FX_PERMISSION_DENIED:
substatusAsSTR = "SSH_FX_PERMISSION_DENIED";
break;
- case SftpSubsystem.SSH_FXP_MKDIR:
+ case SSH_FXP_MKDIR:
substatusAsSTR = "SSH_FXP_MKDIR";
break;
- case SftpSubsystem.SSH_FXP_REMOVE:
+ case SSH_FXP_REMOVE:
substatusAsSTR = "SSH_FXP_REMOVE";
break;
- case SftpSubsystem.SSH_FXP_RMDIR:
+ case SSH_FXP_RMDIR:
substatusAsSTR = "SSH_FXP_RMDIR";
break;
- case SftpSubsystem.SSH_FX_WRITE_PROTECT:
+ case SSH_FX_WRITE_PROTECT:
substatusAsSTR = "SSH_FX_WRITE_PROTECT";
break;
default:
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/21c1cee9/sshd-sftp/src/test/java/org/apache/sshd/sftp/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/SftpTest.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/SftpTest.java
index 9652c3b..a1df9e8 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/SftpTest.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/SftpTest.java
@@ -24,7 +24,18 @@ import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.GroupPrincipal;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
import java.util.Arrays;
+import java.util.Map;
+import java.util.Set;
import java.util.Vector;
import com.jcraft.jsch.ChannelSftp;